diff --git a/.gitignore b/.gitignore index e0e2e695..e1a96c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,6 @@ tmp/ **/.obsidian/ # 코리도 서버 사전 생성 번들 — `npm run build:corridor` 산출물(2026-09-04). # 소스가 바뀌면 서버가 스스로 다시 만든다(B05_Profile_Corridor_Prebuild.py). -config/corridor_node/ \ No newline at end of file +config/corridor_node/ +# 횡단 서버 재계산 번들 — `npm run build:server-calc` 산출물(2026-09-06). +config/server_calc_node/ diff --git a/A00_Common/b_page_state.ts b/A00_Common/b_page_state.ts new file mode 100644 index 00000000..85b9bb59 --- /dev/null +++ b/A00_Common/b_page_state.ts @@ -0,0 +1,311 @@ +/* ============================================================================= + * A00_Common/b_page_state.ts + * 화면 상태 보관소 **한 곳** — B05·B06 이 한 페이지처럼 움직이기 위한 뼈대 + * (2026-09-06 사용자 지시). + * + * 왜 필요한가 — 세션 접근이 19개 파일 64곳에 흩어져 있었고 키 이름이 네 갈래 + * (`b05:`, `b06:`, `b05-route-`, `aislo:`)로 제각각이었다. 같은 설계값인데 키가 + * 페이지 이름으로 갈려 두 화면이 서로의 값을 못 보는 자리도 있었다. 값마다 **어느 통에 + * 속하는지**를 아래 등록표에 한 줄로 적어 두고, 저장·복원·비우기가 전부 그 표만 보고 + * 움직이게 한다. 나중에 캐시↔즉시를 바꿀 때도 표 한 줄만 고치면 된다. + * + * 통은 넷이다. + * ① pref 화면 취향 — 패널 열림·높이, 보기 토글. **계정**에 붙는다(다른 PC에서도 같은 + * 배치). 세션은 그 값의 사본이라 서버가 없어도 화면은 돈다. + * ② draft 설계 초안 — 사용자가 만진 설계값. [저장]·[확정] 때만 서버로 간다. + * ③ (즉시) 누르는 순간 다시 계산을 부르는 명령. 여기 쌓지 않는다 — 표에도 없다. + * ④ result 계산 결과 — 서버·브라우저가 만들어 낸 값. 저장 대상이 아니고, 입력이 + * 바뀌면 버리고 다시 만든다. 페이지를 오갈 때 다시 부르지 않으려고 둔다. + * + * 키 형식은 `aislo:{통}:{이름}:{프로젝트}[:{노선}]` 하나다. **페이지 이름을 키에 넣지 + * 않는다** — ②·④는 두 화면이 같은 키를 쓴다. + * ========================================================================== */ + +/** 값이 속한 통. `pref`·`draft`·`result` 셋만 저장소를 쓴다(즉시 반영은 표에 없다). */ +export type StateBucket = "pref" | "draft" | "result"; + +/** 값을 가르는 범위 — 키에 무엇을 덧붙일지 정한다. */ +export type StateScope = "global" | "project" | "route"; + +export interface StateEntry { + bucket: StateBucket; + scope: StateScope; + /** 형식이 바뀌면 올린다 — 옛 값을 읽지 않고 기본값으로 시작한다. */ + version?: number; + /** 옛 키(있으면 한 번 읽어 옮기고 지운다). `project`·`route` 범위는 함수로 받는다. */ + legacy?: (projectId?: string, routeId?: number | string) => string; +} + +/** + * 등록표 — **새 값은 여기 줄부터 넣고 코드를 쓴다.** + * + * `scope: "global"` 은 프로젝트를 가리지 않는 화면 취향이다(패널 높이 등). 설계값은 + * 반드시 `project` 또는 `route` 범위를 쓴다 — 프로젝트를 옮겼는데 앞 프로젝트의 조작이 + * 남으면 안 된다. + */ +export const STATE_REGISTRY = { + /* ── ① 화면 취향 ─────────────────────────────────────────────────────── */ + "profile-collapsed": { + bucket: "pref", + scope: "global", + legacy: () => "b05-route-profile-collapsed", + }, + "profile-height": { bucket: "pref", scope: "global", legacy: () => "b05-route-profile-height" }, + "drainage-collapsed": { + bucket: "pref", + scope: "global", + legacy: () => "b05-route-drainage-collapsed", + }, + "drainage-width": { bucket: "pref", scope: "global", legacy: () => "b05-route-drainage-width" }, + "masshaul-open": { + bucket: "pref", + scope: "global", + legacy: () => "b05-route-profile-masshaul-open", + }, + "masshaul-height": { + bucket: "pref", + scope: "global", + legacy: () => "b05-route-profile-masshaul-height", + }, + /** 유토곡선 범례 — B05·B06 이 같은 값을 본다(예전에도 키를 공유했다). */ + "masshaul-visible": { + bucket: "pref", + scope: "global", + version: 5, + legacy: () => "b06:masshaul-visible-v4", + }, + "table-open": { bucket: "pref", scope: "global", legacy: () => "b05:profile:table:open" }, + "table-height": { bucket: "pref", scope: "global", legacy: () => "b05:profile:table:height" }, + "section-panel-collapsed": { + bucket: "pref", + scope: "global", + legacy: () => "b06:profile-panel-collapsed", + }, + "section-panel-height": { + bucket: "pref", + scope: "global", + legacy: () => "b06:profile-panel-height", + }, + + /* ── ② 설계 초안 ─────────────────────────────────────────────────────── */ + /** 아직 정본에 안 넣은 구조물 목록. B05 에서 만들고 B06 [저장]이 내보낸다. */ + structures: { bucket: "draft", scope: "project", legacy: (p) => `b05:structures:${p}` }, + /** 3D 램프로 바꾼 측점 상단측(측구 방향). */ + uphill: { bucket: "draft", scope: "project", legacy: (p) => `b05:uphill:${p}` }, + /* `pipes`(옛 `b05:pipes`)는 2026-09-06 에 뺐다 — 읽는 곳도 쓰는 곳도 없었다. + 관 위치의 정본은 `pipe_points.json` 이고, 화면은 [저장] 때 `savePipes()` 로 바로 + 내보낸다. 초안처럼 보이는 이름만 남아 대응표에서 「저장 자리 없음」으로 잡혔다. */ + /** B05 에서 고른 구조물을 B06 이 이어받는 자리 — 예전 `aislo:structure-pick:*`. */ + "structure-pick": { + bucket: "draft", + scope: "project", + legacy: (p) => `aislo:structure-pick:${p}`, + }, + /** 배수관·암거 조정창에서 예약한 옵션 값. */ + culvertopt: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:culvertopt:${p}:${r}` }, + /** 배수관 이동(측점 옮김) 예약. */ + culvertmove: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:culvertmove:${p}:${r}` }, + /** 암 경계선 오프셋(측점별). */ + rockb: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:rockb:${p}:${r}` }, + /** 규격 횡단 측점별 지정. */ + "std-cross": { bucket: "draft", scope: "project", legacy: (p) => `b06:std-cross:${p}` }, + /** 표시 반폭 — 사용자가 고른 값이라 초안이되, 바꾸면 횡단 재생성(③)을 함께 부른다. */ + "cross-display": { + bucket: "draft", + scope: "route", + legacy: (p, r) => `b06:cross-display:${p}:${r}`, + }, + /* 측점 조정창이 쌓는 4축·단수·연동 값 — 전부 노선 단위 초안이고 [저장]에서 함께 나간다. + 옛 키는 `b06:{이름}:{프로젝트}:{노선}` 한 규칙이었다. */ + crossw: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:crossw:${p}:${r}` }, + revetx: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:revetx:${p}:${r}` }, + revetlink: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:revetlink:${p}:${r}` }, + basinadjust: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:basinadjust:${p}:${r}` }, + inletstruct: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:inletstruct:${p}:${r}` }, + extrawall: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:extrawall:${p}:${r}` }, + fordadjust: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:fordadjust:${p}:${r}` }, + boxadjust: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:boxadjust:${p}:${r}` }, + extraspan: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:extraspan:${p}:${r}` }, + /** 횡단 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈) 선택 — 2026-09-06. + * 예전에는 버튼을 누를 때마다 서버가 계산해 **바로 저장**했다. 조작은 캐시에 쌓고 + * [저장]·[확정]에서만 정본으로 나가야 한다(사용자 확정). */ + crossdesign: { bucket: "draft", scope: "route" }, + + /* ── ④ 계산 결과 ─────────────────────────────────────────────────────── */ + /** 노선·종단 최신 응답. 페이지를 오갈 때 이 값으로 먼저 그린다. */ + latest: { bucket: "result", scope: "project", legacy: (p) => `b05:latest:${p}` }, + /** 종횡단 설정값(config 상수 + 프로젝트 임도 종류 + 노선 id). B05·B06 이 같은 값을 + * 받아 쓰므로 화면을 오갈 때마다 다시 묻지 않는다(2026-09-06 호출 정리). + * 노선이 바뀌면 `latest` 와 함께 버린다. */ + "section-context": { bucket: "result", scope: "project" }, + /** 횡단 상세 응답 — 예전에는 메모리에만 있어 페이지를 떠나면 사라졌다. */ + "section-detail": { bucket: "result", scope: "route" }, + /** 서버가 준 규격 횡단 기본값 — 사용자가 만든 값이 아니라 **기억해 둔 서버 값**이다. */ + "std-cross-default": { + bucket: "result", + scope: "project", + legacy: (p) => `b06:std-cross-default:${p}`, + }, + /** 서버가 준 암 경계선 기본 오프셋 — 위와 같은 성격. */ + "rock-boundary-default": { + bucket: "result", + scope: "project", + legacy: (p) => `b06:rock-boundary-default:${p}`, + }, +} as const satisfies Record; + +export type StateName = keyof typeof STATE_REGISTRY; + +const warnedNames = new Set(); + +/** + * 등록표에서 한 줄을 꺼낸다. 표에 없는 이름이면 **화면을 죽이지 않고** null 을 돌려준다 — + * 그 값만 저장이 안 될 뿐 페이지는 그대로 선다(2026-09-06: `extraspan` 이 빠져 B06 이 + * 통째로 안 뜬 적이 있다). 대신 콘솔에 한 번 알려 표에 줄을 넣게 한다. + */ +function entryOf(name: StateName): StateEntry | null { + const entry = STATE_REGISTRY[name] as StateEntry | undefined; + if (entry) return entry; + if (!warnedNames.has(name)) { + warnedNames.add(name); + console.warn(`[page-state] 등록표에 없는 이름입니다 — 저장하지 않습니다: ${name}`); + } + return null; +} + +/** + * 저장소 키. 범위가 요구하는 값이 없으면 `null` — 부를 쪽은 그때 저장을 건너뛴다 + * (프로젝트를 아직 모를 때 전역 키에 적으면 다음 프로젝트가 그 값을 물려받는다). + */ +export function stateKey( + name: StateName, + projectId?: string | null, + routeId?: number | string | null, +): string | null { + const entry = entryOf(name); + if (!entry) return null; + const suffix = entry.version && entry.version > 1 ? `-v${entry.version}` : ""; + const head = `aislo:${entry.bucket}:${name}${suffix}`; + if (entry.scope === "global") return head; + if (!projectId) return null; + if (entry.scope === "project") return `${head}:${projectId}`; + if (routeId === null || routeId === undefined) return null; + return `${head}:${projectId}:${routeId}`; +} + +/** 세션 접근은 저장소가 막힌 브라우저(사생활 보호)에서 던진다 — 전부 조용히 넘긴다. */ +function readRaw(key: string): string | null { + try { + return window.sessionStorage.getItem(key); + } catch { + return null; + } +} + +function writeRaw(key: string, value: string | null): void { + try { + if (value === null) window.sessionStorage.removeItem(key); + else window.sessionStorage.setItem(key, value); + } catch { + /* 무시 — 값은 화면 메모리에 남는다. */ + } +} + +/** 옛 키에 남은 값을 새 키로 한 번 옮긴다(옮기고 나면 옛 키는 지운다). */ +function migrate( + name: StateName, + key: string, + projectId?: string | null, + routeId?: number | string | null, +): void { + const legacy = entryOf(name)?.legacy?.(projectId ?? undefined, routeId ?? undefined); + if (!legacy || legacy === key) return; + const old = readRaw(legacy); + if (old !== null && readRaw(key) === null) writeRaw(key, old); + if (old !== null) writeRaw(legacy, null); +} + +/** 문자열 그대로 읽는다(숫자·참거짓처럼 JSON 이 아닌 값). */ +export function readStateRaw( + name: StateName, + projectId?: string | null, + routeId?: number | string | null, +): string | null { + const key = stateKey(name, projectId, routeId); + if (!key) return null; + migrate(name, key, projectId, routeId); + return readRaw(key); +} + +export function writeStateRaw( + name: StateName, + value: string | null, + projectId?: string | null, + routeId?: number | string | null, +): void { + const key = stateKey(name, projectId, routeId); + if (key) writeRaw(key, value); +} + +/** JSON 값을 읽는다. 없거나 손상됐으면 `null` — 부를 쪽이 기본값으로 시작한다. */ +export function readState( + name: StateName, + projectId?: string | null, + routeId?: number | string | null, +): T | null { + const raw = readStateRaw(name, projectId, routeId); + if (raw === null) return null; + try { + return JSON.parse(raw) as T; + } catch { + return null; + } +} + +export function writeState( + name: StateName, + value: unknown, + projectId?: string | null, + routeId?: number | string | null, +): void { + writeStateRaw(name, value === null ? null : JSON.stringify(value), projectId, routeId); +} + +export function clearState( + name: StateName, + projectId?: string | null, + routeId?: number | string | null, +): void { + writeStateRaw(name, null, projectId, routeId); +} + +/** 등록표에서 한 통에 속한 이름만 고른다. */ +export function namesInBucket(bucket: StateBucket): StateName[] { + return (Object.keys(STATE_REGISTRY) as StateName[]).filter( + (name) => entryOf(name)?.bucket === bucket, + ); +} + +/** + * 초안을 통째로 비운다 — **[저장]·[확정]·[초기화]·노선 변경 뒤 여기 한 곳**만 부른다 + * (예전에는 파일마다 따로 지웠다). 노선을 모르면 노선 범위 초안은 남는다. + */ +export function clearDrafts(projectId: string | null, routeId?: number | string | null): void { + namesInBucket("draft").forEach((name) => clearState(name, projectId, routeId)); +} + +/** 계산 결과를 통째로 버린다 — 입력(설계값·노선)이 바뀌어 다시 만들어야 할 때. */ +export function clearResults(projectId: string | null, routeId?: number | string | null): void { + namesInBucket("result").forEach((name) => clearState(name, projectId, routeId)); +} + +/** + * 지금 이 브라우저에 쌓인 초안이 있는가 — [저장] 버튼의 미저장 표시에 쓴다. + * 값이 빈 객체(`{}`)면 없는 것으로 본다. + */ +export function hasDrafts(projectId: string | null, routeId?: number | string | null): boolean { + return namesInBucket("draft").some((name) => { + const raw = readStateRaw(name, projectId, routeId); + return raw !== null && raw !== "{}" && raw !== "[]" && raw !== ""; + }); +} diff --git a/A00_Common/b_workflow_nav.ts b/A00_Common/b_workflow_nav.ts index bbd26970..52a2b613 100644 --- a/A00_Common/b_workflow_nav.ts +++ b/A00_Common/b_workflow_nav.ts @@ -30,15 +30,39 @@ export const WORKFLOW_STEP_ROUTES: readonly RoutePath[] = [ ROUTES.B09_ESTIMATION, ]; +/* 워크플로 상태는 한 화면을 여는 동안 준비 화면 가드와 페이지 본체가 각각 부른다 — + 실측 B05 진입에서 두 번 나갔다(2026-09-06). 짧은 시간 동안 한 번만 부르고 나눠 쓴다. + 단계가 바뀌는 자리(`goToWorkflowStage`)에서는 즉시 버린다. */ +const WORKFLOW_CACHE_MS = 5000; +let workflowCache: { at: number; projectId: string; value: Promise } | null = null; + +/** 워크플로 상태 캐시를 버린다 — 단계가 바뀌는 자리에서 부른다. */ +export function clearWorkflowStateCache(): void { + workflowCache = null; +} + export async function fetchWorkflowState(projectId: string): Promise { - const response = await fetch(`${API_BASE_URL}/projects/${projectId}/workflow-state`, { - credentials: "include", - }); - if (!response.ok) { - throw new Error(`Workflow state request failed: ${response.status}`); + const now = Date.now(); + if ( + workflowCache && + workflowCache.projectId === projectId && + now - workflowCache.at < WORKFLOW_CACHE_MS + ) { + return workflowCache.value; } - const data = await response.json(); - return data.workflow_state ?? data; + const value = (async (): Promise => { + const response = await fetch(`${API_BASE_URL}/projects/${projectId}/workflow-state`, { + credentials: "include", + }); + if (!response.ok) { + throw new Error(`Workflow state request failed: ${response.status}`); + } + const data = await response.json(); + return data.workflow_state ?? data; + })(); + workflowCache = { at: now, projectId, value }; + value.catch(() => clearWorkflowStateCache()); + return value; } /** @@ -52,6 +76,8 @@ const PRELOAD_REQUIRED_ROUTES: readonly RoutePath[] = [ROUTES.B04_PREPROCESS, RO export function goToWorkflowStage(projectId: string, route: RoutePath): void { localStorage.setItem(CURRENT_PROJECT_ID_KEY, projectId); + // 단계가 바뀌어 이동하는 자리다 — 캐시를 버려 다음 화면이 새 상태를 본다. + clearWorkflowStateCache(); if (!PRELOAD_REQUIRED_ROUTES.includes(route)) { navigateTo(route); return; diff --git a/A06_Login/A06_Login_Api_Fetch.ts b/A06_Login/A06_Login_Api_Fetch.ts index ac768d3b..c2565d99 100644 --- a/A06_Login/A06_Login_Api_Fetch.ts +++ b/A06_Login/A06_Login_Api_Fetch.ts @@ -32,25 +32,48 @@ export function requestLogin(email: string, password: string): Promise { + clearSessionCache(); return post("/auth/login/verify", { email, otp_code: otpCode }); } +/* 세션 조회는 한 화면을 여는 동안 라우터 가드·상단 바·워크플로 확인이 각각 부른다 — + 실측 B05 진입에서 `GET /auth/session` 이 네 번 나갔다(2026-09-06). 같은 답을 네 번 + 받을 이유가 없으므로 **짧은 시간 동안 한 번만** 부르고 나눠 쓴다. 로그인·로그아웃 + 에서는 즉시 버려 다음 조회가 서버를 다시 본다. */ +const SESSION_CACHE_MS = 5000; +let sessionCache: { at: number; value: Promise } | null = null; + +/** 세션 캐시를 버린다 — 로그인·로그아웃처럼 상태가 바뀌는 자리에서 부른다. */ +export function clearSessionCache(): void { + sessionCache = null; +} + +function sessionOnce(): Promise { + const now = Date.now(); + if (sessionCache && now - sessionCache.at < SESSION_CACHE_MS) return sessionCache.value; + const value = (async (): Promise => { + try { + const response = await fetch(`${API_BASE_URL}/auth/session`, { credentials: "include" }); + if (!response.ok) return null; + const data = (await response.json()) as { status: string; user?: SessionUser }; + return data.user ?? null; + } catch { + return null; + } + })(); + sessionCache = { at: now, value }; + return value; +} + export async function fetchSession(): Promise { - const response = await fetch(`${API_BASE_URL}/auth/session`, { credentials: "include" }); - return response.ok; + return (await sessionOnce()) !== null; } export async function fetchSessionUser(): Promise { - try { - const response = await fetch(`${API_BASE_URL}/auth/session`, { credentials: "include" }); - if (!response.ok) return null; - const data = (await response.json()) as { status: string; user?: SessionUser }; - return data.user ?? null; - } catch { - return null; - } + return sessionOnce(); } export function logout(): Promise { + clearSessionCache(); return post("/auth/logout"); } diff --git a/B03_FileInput/B03_FileInput_Service_Chain.py b/B03_FileInput/B03_FileInput_Service_Chain.py index b826fda4..00e959af 100644 --- a/B03_FileInput/B03_FileInput_Service_Chain.py +++ b/B03_FileInput/B03_FileInput_Service_Chain.py @@ -280,6 +280,17 @@ async def run_auto_design_chain( except Exception: # noqa: BLE001 — 코리도 실패가 체인을 막지는 않는다 logger.exception("코리도 사전 생성 실패: project_id=%s", project_id) + # 구조물 폐회로 면적 + 유토곡선 — 화면이 쓰는 TS 를 서버에서 한 번 돌려 정본에 + # 얹는다(2026-09-06). 이걸 빼면 B06 을 안 연 프로젝트의 수량이 구조물을 모르는 + # 표준값으로 남고 유토곡선은 아예 없다. 초기값 스냅샷 **앞**이라 되돌릴 + # 기준선에도 보정이 담긴다. + try: + from B06_Section.B06_Section_Server_Calc_Prebuild import recompute_server_side + + await recompute_server_side(project_id, route_id) + except Exception: # noqa: BLE001 — 재계산 실패가 체인을 막지는 않는다 + logger.exception("횡단 서버 재계산 실패: project_id=%s", project_id) + # 초기값 스냅샷 — 여기가 [초기화]가 되돌릴 기준선이다(CLAUDE.md 5장). # 체인 규약대로 실패는 비치명적이다: 계산 결과는 그대로 두고 실패 마커만 남겨 # [초기화]가 재계산으로 얼버무리지 않게 한다(2026-09-02 사용자 확정). diff --git a/B05_Profile/B05_Profile_Api_Fetch.ts b/B05_Profile/B05_Profile_Api_Fetch.ts index b137cef6..bf89201a 100644 --- a/B05_Profile/B05_Profile_Api_Fetch.ts +++ b/B05_Profile/B05_Profile_Api_Fetch.ts @@ -11,6 +11,8 @@ * - 오류 응답 형식 {status:"error", message:"..."}을 Error로 변환. * ========================================================================== */ +import { clearState, readState, writeState } from "../A00_Common/b_page_state"; + import { API_ANALYSIS_TIMEOUT_MS, API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend"; /** 경로 제어점 (BP/EP/CP) */ @@ -264,6 +266,19 @@ export async function confirmRoute( }); } +/** 세션에 쌓인 상단측(측구 방향) 변경분을 정본으로 내보낸다 — B06 [저장]·[확정]용. + * 3D 램프 클릭은 B05 화면에서만 생기지만 저장 버튼은 B06 에도 있다(B05·B06 은 한 페이지). + * B06 에서 저장하면 이 값이 세션에만 남아 확정 뒤 옛 측구 방향이 그대로 쓰였다 + * (2026-09-06 대응표 조사). 비어 있으면 요청을 내지 않는다. */ +export async function flushUphillOverrides(projectId: string): Promise { + const stored = readState>("uphill", projectId); + const overrides = Object.entries(stored ?? {}) + .filter(([, side]) => side === "left" || side === "right") + .map(([chainage, side]) => ({ chainage_m: Number(chainage), side })); + if (!overrides.length) return; + await confirmRoute(projectId, { uphill_overrides: overrides }, false); +} + /** [초기화] 응답 — 초기 자동 계산 상태로 재구성된 경로. */ export interface RouteResetResponse { status: string; @@ -292,39 +307,22 @@ export async function fetchLatestRoute(projectId: string): Promise `b05:latest:${projectId}`; +/* 최신 경로 응답은 ④ 계산 결과다 — 키·이관은 등록표(`b_page_state`)가 맡는다. + B04에서 지표면을 다시 확정하면 옛 확정값이 남아 B05가 이전 지형을 그리므로, 확정 + 직후 `clearRouteLatestCache`로 버린다. */ -/** 담아 둔 최신 경로 값을 버린다. B04에서 지표면을 다시 확정하면 옛 확정값이 남아 - * B05가 이전 지형을 그리게 되므로, 확정 직후 이 값을 지운다. */ /** 세션 캐시에서 최신 경로 응답을 읽는다. 없거나 깨졌으면 null(다음 진입은 DB 조회). */ export function readRouteLatestCache(projectId: string): RouteLatestResponse | null { - try { - const raw = window.sessionStorage.getItem(routeLatestCacheKey(projectId)); - return raw ? (JSON.parse(raw) as RouteLatestResponse) : null; - } catch { - return null; - } + return readState("latest", projectId); } -/** 최신 경로 응답을 세션 캐시에 넣는다. 용량 초과 등으로 실패하면 캐시를 비운다. */ +/** 최신 경로 응답을 세션 캐시에 넣는다. 용량 초과 등으로 실패해도 화면은 그대로 돈다. */ export function writeRouteLatestCache(projectId: string, value: RouteLatestResponse): void { - const key = routeLatestCacheKey(projectId); - try { - window.sessionStorage.setItem(key, JSON.stringify(value)); - } catch { - try { - window.sessionStorage.removeItem(key); - } catch { - /* noop */ - } - } + writeState("latest", value, projectId); } export function clearRouteLatestCache(projectId: string): void { - try { - window.sessionStorage.removeItem(routeLatestCacheKey(projectId)); - } catch { - /* 세션 접근 실패 시에는 다음 진입에서 DB를 읽게 되므로 그대로 둔다. */ - } + clearState("latest", projectId); + // 설정값에 노선 id 가 실려 있어 함께 버려야 옛 노선을 가리키지 않는다(2026-09-06). + clearState("section-context", projectId); } diff --git a/B05_Profile/B05_Profile_Api_Structures.ts b/B05_Profile/B05_Profile_Api_Structures.ts index 9c7a48a2..ad1bfb6d 100644 --- a/B05_Profile/B05_Profile_Api_Structures.ts +++ b/B05_Profile/B05_Profile_Api_Structures.ts @@ -11,6 +11,7 @@ * 하려는 것이라, 목록은 반드시 서버에서 받아 온다. * ========================================================================== */ +import { readState, writeState } from "../A00_Common/b_page_state"; import { API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend"; /** 배치형태 — 점형(측점 1개) / 구간형(시~종점) / 부지형(위치+면적). */ @@ -193,26 +194,13 @@ export function defaultOptions(type: StructureType): Record `b05:structures:${projectId}`; - -/** 미저장 조작분. 없으면 null(= 만진 적 없음, 빈 목록과 구분된다). */ +/** 미저장 조작분(② 설계 초안). 없으면 null(= 만진 적 없음, 빈 목록과 구분된다). */ export function readPendingStructures(projectId: string): StructureInstance[] | null { - try { - const raw = window.sessionStorage.getItem(pendingStructuresKey(projectId)); - return raw ? (JSON.parse(raw) as StructureInstance[]) : null; - } catch { - return null; - } + return readState("structures", projectId); } export function writePendingStructures(projectId: string, next: StructureInstance[] | null): void { - try { - const key = pendingStructuresKey(projectId); - if (next) window.sessionStorage.setItem(key, JSON.stringify(next)); - else window.sessionStorage.removeItem(key); - } catch { - /* 세션 저장 실패는 무시 — 값은 화면에 남아 있다. */ - } + writeState("structures", next, projectId); } /** diff --git a/B05_Profile/B05_Profile_Corridor_Prebuild.py b/B05_Profile/B05_Profile_Corridor_Prebuild.py index a69be261..9361fac2 100644 --- a/B05_Profile/B05_Profile_Corridor_Prebuild.py +++ b/B05_Profile/B05_Profile_Corridor_Prebuild.py @@ -16,8 +16,6 @@ from __future__ import annotations import asyncio import json import logging -import os -import subprocess import tempfile from pathlib import Path from typing import Any @@ -25,76 +23,13 @@ from uuid import UUID from B05_Profile.B05_Profile_Repository import get_route_points from B05_Profile.B05_Profile_Router_Corridor import corridor_path +from common_util.common_util_node_bundle import build_bundle, bundle_stale, run_node from config.config_db import get_db_pool logger = logging.getLogger(__name__) ROOT = Path(__file__).resolve().parents[1] BUNDLE = ROOT / "config" / "corridor_node" / "B05_Profile_Corridor_Node.js" -# 번들이 낡았는지 재는 대상 — 빌더 계통이 걸쳐 있는 폴더. -_SOURCE_DIRS = ("B05_Profile", "B06_Section", "common_util") -# 번들 만들기·실행 상한(초). 실측 번들 0.1초, 빌드 65측점 3초 수준이라 넉넉하다. -_BUILD_TIMEOUT_S = 300 -_RUN_TIMEOUT_S = 600 - - -def _node_env() -> dict[str, str]: - """config/node_modules를 쓰는 프론트엔드 프로세스 환경(main.py와 같은 규약).""" - env = os.environ.copy() - node_modules = ROOT / "config" / "node_modules" - env["PATH"] = f"{node_modules / '.bin'}{os.pathsep}{env.get('PATH', '')}" - env["NODE_PATH"] = str(node_modules) - return env - - -def _bundle_stale() -> bool: - """번들이 없거나 TS 원본보다 오래됐으면 참. - - 번들이 낡으면 서버와 화면이 **다른 기하**를 만든다 — 이 판정이 그것을 막는 유일한 - 장치다. 개발 중에는 `npm run build`를 따로 돌리지 않으므로 여기서 스스로 갱신한다. - """ - if not BUNDLE.is_file(): - return True - built_at = BUNDLE.stat().st_mtime - for directory in _SOURCE_DIRS: - for path in (ROOT / directory).rglob("*.ts"): - if path.stat().st_mtime > built_at: - return True - return False - - -def _build_bundle() -> bool: - result = subprocess.run( # noqa: S602 — 고정 명령, 사용자 입력 없음 - "npm run build:corridor", - shell=True, - cwd=str(ROOT), - env=_node_env(), - capture_output=True, - text=True, - encoding="utf-8", - errors="replace", - timeout=_BUILD_TIMEOUT_S, - ) - if result.returncode != 0: - logger.error("코리도 번들 빌드 실패:\n%s", result.stderr) - return False - return True - - -def _run_node(input_path: Path, output_path: Path) -> int: - result = subprocess.run( # noqa: S603 — 고정 실행 파일, 인자는 임시 파일 경로뿐 - ["node", str(BUNDLE), str(input_path), str(output_path)], - cwd=str(ROOT), - env=_node_env(), - capture_output=True, - text=True, - encoding="utf-8", - errors="replace", - timeout=_RUN_TIMEOUT_S, - ) - if result.returncode != 0: - logger.warning("코리도 사전 생성 실패(끝 코드 %s): %s", result.returncode, result.stderr) - return result.returncode async def _section_detail(project_id: UUID | str, route_id: int) -> dict[str, Any] | None: @@ -121,7 +56,7 @@ async def prebuild_corridor(project_id: UUID | str, route_id: int, project_root: logger.info("코리도 사전 생성 건너뜀 — 노선 점이 부족함 (route_id=%s)", route_id) return False - if _bundle_stale() and not await asyncio.to_thread(_build_bundle): + if bundle_stale(BUNDLE) and not await asyncio.to_thread(build_bundle, "build:corridor"): return False target = corridor_path(Path(project_root), route_id) @@ -133,7 +68,7 @@ async def prebuild_corridor(project_id: UUID | str, route_id: int, project_root: json.dumps({"detail": detail, "route_points": points}, default=float), "utf-8", ) - if await asyncio.to_thread(_run_node, source, built) != 0: + if await asyncio.to_thread(run_node, BUNDLE, source, built) != 0: return False await asyncio.to_thread(target.parent.mkdir, parents=True, exist_ok=True) await asyncio.to_thread(_replace, built, target) diff --git a/B05_Profile/B05_Profile_Engine_Grade.py b/B05_Profile/B05_Profile_Engine_Grade.py index c7574a34..e250d8f4 100644 --- a/B05_Profile/B05_Profile_Engine_Grade.py +++ b/B05_Profile/B05_Profile_Engine_Grade.py @@ -139,6 +139,18 @@ def legal_grade_limit_pct( return legal_max +def legal_plan_radius_min_m(design_speed_kph: int, terrain_type: str = "normal") -> float: + """설계속도 × 지형 구분에 따른 법정 **평면** 최소곡선반지름(m, 별표2 Ⅰ.2.다.(1)). + + 경로탐색 제약이 아니라 **위반 표시** 기준이다(2026-09-06 사용자 확정). 설계속도는 + 이미 확정된 값을 받는다(계획선 옵션이 `resolve_design_speed`로 눌러 둔 값). + """ + table = FOREST_ROAD_PROFILE_CRITERIA["min_plan_radius_m"] + terrain = terrain_type if terrain_type in GRADE_TERRAIN_TYPES else "normal" + speeds = table.get(int(design_speed_kph)) or table[20] + return float(speeds[terrain]) + + def _pick(*candidates: Any) -> Any: """요청 → DB 저장값 → config 순으로 처음 나오는 유효값을 고른다.""" for value in candidates: diff --git a/B05_Profile/B05_Profile_Engine_Grade_Alignment.py b/B05_Profile/B05_Profile_Engine_Grade_Alignment.py index 005d5a8a..254b252d 100644 --- a/B05_Profile/B05_Profile_Engine_Grade_Alignment.py +++ b/B05_Profile/B05_Profile_Engine_Grade_Alignment.py @@ -20,7 +20,7 @@ from typing import Any import numpy as np -from config.config_system import FOREST_ROAD_PROFILE_ALIGNMENT +from config.config_system import FOREST_ROAD_PROFILE_ALIGNMENT, FOREST_ROAD_PROFILE_CRITERIA ALIGNMENT_SCHEMA_VERSION = 1 # chainage를 dict 키로 쓸 때의 표기. 프론트엔드(`toFixed(3)`)와 반드시 같아야 한다. @@ -51,6 +51,10 @@ class AlignmentPolicy: max_grade_pct: float curve_skip_delta_pct: float paved: bool + #: 법정 평면 최소곡선반지름(m) — 위반 표시 기준(2026-09-06). 0이면 판정하지 않는다. + min_plan_radius_m: float = 0.0 + #: 배향곡선 하한(m) — 이보다 급하면 경고만 낸다. + hairpin_min_radius_m: float = 0.0 @classmethod def from_config( @@ -60,6 +64,7 @@ class AlignmentPolicy: max_grade_pct: float, curve_skip_delta_pct: float, paved: bool, + min_plan_radius_m: float = 0.0, ) -> "AlignmentPolicy": config = FOREST_ROAD_PROFILE_ALIGNMENT return cls( @@ -76,6 +81,8 @@ class AlignmentPolicy: max_grade_pct=float(max_grade_pct), curve_skip_delta_pct=float(curve_skip_delta_pct), paved=bool(paved), + min_plan_radius_m=float(min_plan_radius_m), + hairpin_min_radius_m=float(FOREST_ROAD_PROFILE_CRITERIA["hairpin_min_radius_m"]), ) @classmethod @@ -140,6 +147,9 @@ class AlignmentPolicy: "max_grade_pct": self.max_grade_pct, "curve_skip_delta_pct": self.curve_skip_delta_pct, "paved": self.paved, + # 평면 곡선 판정값 — 화면 위반 표시가 쓴다(2026-09-06). + "min_plan_radius_m": self.min_plan_radius_m, + "hairpin_min_radius_m": self.hairpin_min_radius_m, } diff --git a/B05_Profile/B05_Profile_Engine_Grade_Profile.py b/B05_Profile/B05_Profile_Engine_Grade_Profile.py index fc7e51db..b5991a44 100644 --- a/B05_Profile/B05_Profile_Engine_Grade_Profile.py +++ b/B05_Profile/B05_Profile_Engine_Grade_Profile.py @@ -30,6 +30,7 @@ from B05_Profile.B05_Profile_Engine_Grade import ( GradeDesignOptions, detect_main_direction, ground_profile, + legal_plan_radius_min_m, ) from B05_Profile.B05_Profile_Engine_Grade_Alignment import ( ALIGNMENT_SCHEMA_VERSION, @@ -179,6 +180,8 @@ def design_ground_following_profile( max_grade_pct=options.max_grade_pct, curve_skip_delta_pct=options.vertical_curve_skip_delta_pct, paved=options.paved, + # 평면 최소곡선반지름은 화면 위반 표시에만 쓴다(2026-09-06) — 탐색 제약과 별개. + min_plan_radius_m=legal_plan_radius_min_m(options.design_speed_kph, options.terrain_type), ) warnings = list(options.warnings) @@ -270,6 +273,8 @@ def design_pipe_anchored_profile( max_grade_pct=options.max_grade_pct, curve_skip_delta_pct=options.vertical_curve_skip_delta_pct, paved=options.paved, + # 평면 최소곡선반지름은 화면 위반 표시에만 쓴다(2026-09-06) — 탐색 제약과 별개. + min_plan_radius_m=legal_plan_radius_min_m(options.design_speed_kph, options.terrain_type), ) warnings = list(options.warnings) @@ -385,6 +390,8 @@ def design_alignment_profile( max_grade_pct=options.max_grade_pct, curve_skip_delta_pct=options.vertical_curve_skip_delta_pct, paved=options.paved, + # 평면 최소곡선반지름은 화면 위반 표시에만 쓴다(2026-09-06) — 탐색 제약과 별개. + min_plan_radius_m=legal_plan_radius_min_m(options.design_speed_kph, options.terrain_type), ) warnings = list(options.warnings) diff --git a/B05_Profile/B05_Profile_Engine_Sections.py b/B05_Profile/B05_Profile_Engine_Sections.py index 33ca8bd3..491a76fc 100644 --- a/B05_Profile/B05_Profile_Engine_Sections.py +++ b/B05_Profile/B05_Profile_Engine_Sections.py @@ -100,6 +100,8 @@ def _cross_summary(cross_section: dict[str, Any]) -> dict[str, Any]: "chainage_m": cross_section.get("chainage_m"), "center_z": cross_section.get("center_z"), "azimuth_deg": cross_section.get("azimuth_deg"), + # 평면 곡선반경 — 곡선부 확폭·최소곡선반지름 판정이 쓴다(2026-09-06). + "plan_radius_m": cross_section.get("plan_radius_m"), "sample_count": len(samples), "min_elevation_m": min(valid_z) if valid_z else None, "max_elevation_m": max(valid_z) if valid_z else None, diff --git a/B05_Profile/B05_Profile_Engine_Sections_Core.py b/B05_Profile/B05_Profile_Engine_Sections_Core.py index 94b4eb5a..9c1274e9 100644 --- a/B05_Profile/B05_Profile_Engine_Sections_Core.py +++ b/B05_Profile/B05_Profile_Engine_Sections_Core.py @@ -11,13 +11,16 @@ from typing import Any import numpy as np +from B05_Profile.B05_Profile_Engine_Geometry import circumradius_2d from common_util.common_util_surface_sampler import SurfaceElevationSampler from config.config_system import ( + CURVE_WIDENING_TAPER_M, SECTION_CROSS_HALF_WIDTH_M, SECTION_CROSS_SAMPLE_INTERVAL_M, SECTION_INCLUDE_ENDPOINT, SECTION_LONG_SAMPLE_INTERVAL_M, SECTION_STATION_INTERVAL_M, + curve_widening_m, ) SECTION_SCHEMA_VERSION = 1 @@ -116,6 +119,100 @@ def _float_or_none(value: float) -> float | None: return round(float(value), 6) if math.isfinite(float(value)) else None +#: 평면 곡선반경을 재는 앞뒤 거리(m). 측점 간격(20m)의 절반이라 한 측점의 곡률을 +#: 이웃 측점에 번지지 않게 재고, 짧은 곡선도 놓치지 않는다. +PLAN_RADIUS_ARM_M = 10.0 +#: 이보다 크면 직선으로 본다(m). 별표2 확폭표가 45m 이상을 "확폭 없음"으로 두므로 +#: 그보다 넉넉한 값이면 판정에 영향이 없다. +PLAN_RADIUS_STRAIGHT_M = 10000.0 + + +def _plan_radii( + points: np.ndarray, + route_chainage: np.ndarray, + station_chainage: np.ndarray, + total: float, +) -> tuple[list[float | None], list[str | None]]: + """측점마다 (평면 곡선반경 m, 곡선 **바깥쪽**). 직선·측정 불가는 (None, None). + + 바깥쪽은 확폭이 붙는 쪽이다(2026-09-06 사용자 확정). 좌회전(반시계)이면 곡선 안쪽이 + 좌측이므로 바깥은 우측이다. offset 부호는 +가 좌측이라는 횡단 규약을 따른다. + """ + arm = min(PLAN_RADIUS_ARM_M, max(total / 2.0, 0.0)) + if arm < 0.5: + return [None] * len(station_chainage), [None] * len(station_chainage) + radii: list[float | None] = [] + outer_sides: list[str | None] = [] + for value in station_chainage: + center = float(value) + back = max(0.0, center - arm) + ahead = min(total, center + arm) + # 시·종점에서는 한쪽 팔이 짧아진다 — 양쪽이 다 확보될 때만 잰다. + if center - back < arm * 0.5 or ahead - center < arm * 0.5: + radii.append(None) + outer_sides.append(None) + continue + trio = _interpolate_xy(points, route_chainage, np.array([back, center, ahead])) + radius = circumradius_2d(trio[0], trio[1], trio[2]) + if not math.isfinite(radius) or radius >= PLAN_RADIUS_STRAIGHT_M: + radii.append(None) + outer_sides.append(None) + continue + radii.append(round(radius, 3)) + # 외적 z 부호로 회전 방향을 본다: 양수 = 좌회전 → 안쪽이 좌측 → 바깥은 우측. + first = trio[1] - trio[0] + second = trio[2] - trio[1] + cross = float(first[0] * second[1] - first[1] * second[0]) + outer_sides.append("right" if cross > 0 else "left" if cross < 0 else None) + return radii, outer_sides + + +def _curve_widenings( + station_chainage: np.ndarray, + radii: list[float | None], + outer_sides: list[str | None], +) -> tuple[list[float], list[str | None]]: + """측점별 확폭량(m)과 그것이 붙는 쪽 — 곡선 앞뒤 테이퍼까지 반영한다. + + 표(별표2 Ⅰ.2.나.(4))는 곡선 안에서의 확폭량만 준다. 곡선 시·종점에서 폭이 뚝 + 끊기면 안 되므로, 앞뒤 `CURVE_WIDENING_TAPER_M` 구간에서 0 → W 로 잇는다 + (2026-09-06 사용자 지시). 측점 간격이 테이퍼보다 넓으면 이 함수가 낼 중간값이 + 없고, 화면·3D 가 측점 사이를 이어 그리는 것으로 대신한다. + """ + base = [curve_widening_m(radius) for radius in radii] + widenings = list(base) + sides: list[str | None] = list(outer_sides) + # 확폭이 붙는 측점의 연속 덩어리(=곡선 구간)를 찾아 그 바깥으로 테이퍼를 편다. + runs: list[tuple[int, int]] = [] + start: int | None = None + for index, value in enumerate(base): + if value > 0.0 and outer_sides[index] in ("left", "right"): + if start is None: + start = index + elif start is not None: + runs.append((start, index - 1)) + start = None + if start is not None: + runs.append((start, len(base) - 1)) + + for first, last in runs: + for edge, step in ((first, -1), (last, 1)): + edge_chainage = float(station_chainage[edge]) + index = edge + step + while 0 <= index < len(base): + distance = abs(float(station_chainage[index]) - edge_chainage) + if distance > CURVE_WIDENING_TAPER_M or base[index] > 0.0: + break + ratio = max(0.0, 1.0 - distance / CURVE_WIDENING_TAPER_M) + tapered = round(base[edge] * ratio, 4) + # 양쪽 곡선 사이에 낀 측점은 넓은 쪽을 따른다. + if tapered > widenings[index]: + widenings[index] = tapered + sides[index] = outer_sides[edge] + index += step + return widenings, sides + + def generate_sections( polyline: np.ndarray | list[list[float]], sampler: SurfaceElevationSampler, @@ -167,6 +264,14 @@ def generate_sections( ] ) left_axes = np.column_stack([-tangents[:, 1], tangents[:, 0]]) + # 측점별 **평면 곡선반경**(m). 곡선부 확폭(별표2 Ⅰ.2.나.(4))과 최소곡선반지름 위반 + # 표시가 이 값을 쓴다(2026-09-06). 노선 폴리라인 위에서 앞뒤로 같은 거리를 떨어진 세 + # 점의 외접원 반경이며, 직선이면 무한대라 None 으로 낸다. + plan_radii, plan_outer_sides = _plan_radii(points, route_chainage, station_chainage, total) + # 확폭량은 여기서 한 번에 낸다 — 테이퍼가 이웃 측점을 봐야 하므로 측점 단위로는 못 낸다. + plan_widenings, plan_outer_sides = _curve_widenings( + station_chainage, plan_radii, plan_outer_sides + ) offsets = np.arange( -options.cross_half_width_m, @@ -240,6 +345,12 @@ def generate_sections( "center_y": round(float(station_xy[index, 1]), 6), "center_z": _float_or_none(center_z), "azimuth_deg": round(azimuth, 6), + "plan_radius_m": plan_radii[index], + # 곡선 바깥쪽 — 곡선부 확폭이 붙는 쪽(2026-09-06 사용자 확정). + "curve_outer_side": plan_outer_sides[index], + # 확폭량(m) — 표값에 곡선 앞뒤 테이퍼를 얹은 값. 설계는 반경이 아니라 + # 이 값을 쓴다(테이퍼 측점은 반경이 없거나 커도 확폭이 남아 있다). + "curve_widening_m": plan_widenings[index], # 횡단 기준 등고가 높은 쪽(측구 설계 기본 방향). 사용자 변경 시 확정에서 덮어쓴다. "uphill_side": uphill_side, "frame": frame, diff --git a/B05_Profile/B05_Profile_Router_Confirm.py b/B05_Profile/B05_Profile_Router_Confirm.py index 14539e1f..8e87d7b6 100644 --- a/B05_Profile/B05_Profile_Router_Confirm.py +++ b/B05_Profile/B05_Profile_Router_Confirm.py @@ -95,6 +95,7 @@ async def sync_uphill_overrides_into_designs( get_cross_section_designs, update_cross_section_design, ) + from B06_Section.B06_Section_Engine_Design import curve_widening_args from B06_Section.B06_Section_Router import _read_cross_design_inputs from B06_Section.B06_Section_Router_Design import ford_drop_at, ford_surface_drops @@ -123,7 +124,7 @@ async def sync_uphill_overrides_into_designs( next_ditch = side if next_mode == mode and design.get("ditch_side") == next_ditch: continue - samples, design_elevation, pavement_suggested = await asyncio.to_thread( + samples, design_elevation, pavement_suggested, cross_record = await asyncio.to_thread( _read_cross_design_inputs, project_root, longitudinal_file_path, float(chainage) ) next_design = compute_cross_design( @@ -139,6 +140,7 @@ async def sync_uphill_overrides_into_designs( two_stage_slope=bool(design.get("two_stage_slope", True)), ditch_enabled=design.get("ditch_enabled"), surface_drop_m=ford_drop_at(float(chainage), ford_drops), + **curve_widening_args(cross_record), ) next_design["status"] = design.get("status", "provisional") next_design["pavement_suggested"] = design.get("pavement_suggested", pavement_suggested) diff --git a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts index 75f865cb..860b4abe 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts @@ -1,4 +1,5 @@ import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; +import { readStateRaw, writeStateRaw } from "../A00_Common/b_page_state"; import { computeDetailBasins, fetchDetailPipePoints, @@ -39,7 +40,6 @@ import { fitViewToRoute, observeViewportSize, bindPipeContextMenu, - COLLAPSED_KEY, MAX_PANEL_WIDTH_RATIO, MIN_PANEL_WIDTH, renderBasinRows, @@ -526,7 +526,7 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra function setCollapsed(collapsed: boolean): void { root.classList.toggle("is-collapsed", collapsed); panelHandle.setOpen(!collapsed); - sessionStorage.setItem(COLLAPSED_KEY, String(collapsed)); + writeStateRaw("drainage-collapsed", String(collapsed)); if (!collapsed) scheduleDraw(); } panelHandle.root.addEventListener("click", () => @@ -534,7 +534,7 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra ); // 상세 배수유역 정보는 페이지에 들어오면 바로 보여야 한다 — 저장값이 없으면 펼침이 기본이다 // (같은 페이지의 하단 종단 패널과 같은 규칙). - setCollapsed(sessionStorage.getItem(COLLAPSED_KEY) === "true"); + setCollapsed(readStateRaw("drainage-collapsed") === "true"); return { root, diff --git a/B05_Profile/B05_Profile_UI_Drainage_Parts.ts b/B05_Profile/B05_Profile_UI_Drainage_Parts.ts index e64ed302..d246c7fd 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Parts.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Parts.ts @@ -6,6 +6,7 @@ * 분리한 것으로, 여기 있는 것들은 패널의 내부 상태를 알지 못한다 — 전부 인자로 받는다. * ========================================================================== */ +import { stateKey } from "../A00_Common/b_page_state"; import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; import { themeColor } from "@ui/ui_template_palette"; import { DRAINAGE_SHEET_LAYERS, fetchCachedSheetLayer } from "../A00_Common/b_asset_cache"; @@ -52,9 +53,10 @@ export const hotspotToggleColor = (): string => themeColor("--map-flow-ramp-4", /** 위성사진은 선이 아니라 배경이라 맞출 선 색이 없다 — 중립 회색을 띠 색으로 쓴다. */ export const satelliteToggleColor = (): string => themeColor("--map-satellite-toggle", "#64748b"); -export const COLLAPSED_KEY = "b05-route-drainage-collapsed"; +/** 접힘·폭은 화면 취향(①) — 키는 등록표(`b_page_state`)가 만든다. */ +export const COLLAPSED_KEY = stateKey("drainage-collapsed") ?? ""; /** 드래그로 조절한 패널 폭(px) 보관 키 — 브라우저 세션 동안만 유지한다. */ -export const WIDTH_KEY = "b05-route-drainage-width"; +export const WIDTH_KEY = stateKey("drainage-width") ?? ""; /** 지도가 담기는 최소 폭(px). CSS의 min-width와 같은 값. */ export const MIN_PANEL_WIDTH = 320; /** 상한은 하단 패널 폭의 70%까지(사용자 지시) — 종단면도가 최소한 30%는 남아야 한다. */ diff --git a/B05_Profile/B05_Profile_UI_Markers.ts b/B05_Profile/B05_Profile_UI_Markers.ts index 7e304fa5..f115c28c 100644 --- a/B05_Profile/B05_Profile_UI_Markers.ts +++ b/B05_Profile/B05_Profile_UI_Markers.ts @@ -95,6 +95,14 @@ export function sceneToModel(point: THREE.Vector3, bounds: ModelBounds) { return { x: point.x + cx, y: -point.z + cy, z: point.y + cz }; } +/** 노선 선을 지형에 붙일 때 정점 사이를 나누는 간격(m) — 2m 면 20m 측점 사이가 10토막이라 + * 능선을 가로질러도 선이 지면 아래로 잠기지 않는다(2026-09-06). */ +const DRAPE_STEP_M = 2; +/** 한 구간을 나누는 최대 토막 수 — 정점이 아주 멀리 떨어진 자료에서 점이 폭주하지 않게 한다. */ +const MAX_DRAPE_STEPS = 64; +/** 노선 선을 지형 위로 띄우는 높이(m) — 지형과 겹쳐 깜빡이지 않을 만큼만. */ +const ROUTE_LINE_LIFT_M = 0.35; + export function createRouteMarkers( scene: THREE.Scene, getBounds: () => ModelBounds | null, @@ -254,17 +262,40 @@ export function createRouteMarkers( disposeGroup(routeGroup); const bounds = getBounds(); if (!bounds || polyline.length < 2) return; + // 정점 사이를 잘게 나눠 **각 점의 지형고를 찍어** 선을 지면에 붙인다(2026-09-06). + // 원래는 정점(간격 중앙값 10m)을 곧바로 이었는데, 볼록한 능선에서는 그 10m 직선이 + // 지면을 뚫고 들어가 선이 땅속에 잠겼다 — 화면에는 폴리라인이 끊긴 것처럼 보였다 + // (실측: 161+0.0~163+0.0 구간이 통째로 사라짐). 원래 정점은 모두 남기므로 평면 + // 형상은 바뀌지 않는다. + const dense: Array<{ x: number; y: number; z?: number }> = []; + /** 원래 정점 i 가 조밀화 뒤 몇 번째인지 — 경고 구간이 인덱스로 자르므로 필요하다. */ + const denseIndex: number[] = []; + polyline.forEach((point, index) => { + if (index > 0) { + const previous = polyline[index - 1]; + const span = Math.hypot(point.x - previous.x, point.y - previous.y); + const steps = Math.min(MAX_DRAPE_STEPS, Math.ceil(span / DRAPE_STEP_M)); + for (let step = 1; step < steps; step += 1) { + const ratio = step / steps; + dense.push({ + x: previous.x + (point.x - previous.x) * ratio, + y: previous.y + (point.y - previous.y) * ratio, + }); + } + } + denseIndex[index] = dense.length; + dense.push(point); + }); // 표고 없는 점을 0으로 삼키면 마커와 같은 함정에 빠진다(지형 한참 아래 평면에 눕는다). - // 지형 표면에서 찾아 채우고, 그래도 모르면 직전 점 높이를 이어 쓴다. 경고 구간이 - // 인덱스로 이 배열을 다시 자르므로 점 개수는 그대로 두어야 한다. + // 지형 표면에서 찾아 채우고, 그래도 모르면 직전 점 높이를 이어 쓴다. 끼워 넣은 점과 + // 원래 정점이 **같은 지형면**에서 높이를 받아야 선이 매끄러우므로 지형고를 먼저 본다. let lastZ: number | null = null; - const linePoints = polyline.map((point) => { - const resolved = Number.isFinite(point.z) - ? (point.z as number) - : (getTerrainZ?.(point.x, point.y) ?? lastZ); + const linePoints = dense.map((point) => { + const sampled = getTerrainZ?.(point.x, point.y) ?? null; + const resolved = sampled ?? (Number.isFinite(point.z) ? (point.z as number) : lastZ); if (resolved !== null) lastZ = resolved; return modelToScene({ x: point.x, y: point.y, z: resolved ?? bounds.z[0] }, bounds).add( - new THREE.Vector3(0, 0.35, 0), + new THREE.Vector3(0, ROUTE_LINE_LIFT_M, 0), ); }); routeGroup.add( @@ -274,10 +305,10 @@ export function createRouteMarkers( ), ); warnings.forEach((warning) => { - const segment = linePoints.slice( - Math.max(0, warning.polyline_start_index), - warning.polyline_end_index + 1, - ); + // 경고 구간의 인덱스는 **원래 정점 기준**이라 조밀화 뒤 자리로 옮겨 자른다. + const from = denseIndex[Math.max(0, warning.polyline_start_index)] ?? 0; + const to = denseIndex[Math.min(warning.polyline_end_index, polyline.length - 1)]; + const segment = linePoints.slice(from, (to ?? linePoints.length - 1) + 1); if (segment.length > 1) { routeGroup.add( new THREE.Line( diff --git a/B05_Profile/B05_Profile_UI_Page.ts b/B05_Profile/B05_Profile_UI_Page.ts index e35323b4..e21df61d 100644 --- a/B05_Profile/B05_Profile_UI_Page.ts +++ b/B05_Profile/B05_Profile_UI_Page.ts @@ -1,3 +1,4 @@ +import { dropStationsNear } from "./B05_Profile_Util_Station"; import { CURRENT_PROJECT_ID_KEY, ROUTES } from "@config/config_frontend"; import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; import { showToast } from "@ui/ui_template_elements"; @@ -12,8 +13,7 @@ import { } from "../A00_Common/b_workflow_nav"; import { fetchConfirmedSurface, - listSurfaceModels, - type SurfaceModelSummary, + type SurfaceConfirmedResponse, } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { fetchLatestRoute, @@ -72,6 +72,9 @@ function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } +/** 구 구조물 측점 이관을 이미 시도한 노선 — 탭 수명 동안 유지한다. */ +const migratedRoutes = new Set(); + export async function renderB05Route(root: HTMLElement): Promise { const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY); if (!projectId) { @@ -168,7 +171,10 @@ export async function renderB05Route(root: HTMLElement): Promise { * 선택은 3D·그래프·사이드바가 서로를 갱신하므로, `selectionSyncing` 가드로 재진입을 막아 * 무한 재귀(스택 오버플로우·프리즈)를 방지한다. */ - let confirmedSurface: SurfaceModelSummary | null = null; + /** 확정 지표면 — 모델 id 와 3D 로딩에 필요한 범위만 들고 있는다(2026-09-06 호출 정리). + * 예전에는 목록(`listSurfaceModels`)으로 id 를 찾고 3D 단계에서 `surface/confirmed` + * 를 또 불러 요청이 두 번 나갔다. 확정 응답 하나에 둘 다 들어 있다. */ + let confirmedSurface: SurfaceConfirmedResponse | null = null; let latest: RouteLatestResponse | null = null; let roadWidths = DEFAULT_ROAD_WIDTHS; let currentSectionDetail: SectionDetailResponse | null = null; @@ -233,6 +239,35 @@ export async function renderB05Route(root: HTMLElement): Promise { return fresh; } + /** 이 응답이 "같은 자료"인지 가리는 서명 — 노선 번호·지표면 모델·지표면 설정. */ + const latestSignature = (value: RouteLatestResponse): string => + [ + value.route?.id ?? "", + value.route?.surface_model_id ?? "", + value.surface_params.source_filter, + value.surface_params.method, + String(value.surface_params.smooth), + ].join("|"); + + /** + * 캐시로 먼저 그린 뒤 **뒤에서** 신선도를 확인한다(2026-09-06 캐시·세션 일원화). + * + * 예전에는 진입 때마다 `loadLatest(true)`로 DB를 다시 읽었다 — 다른 탭의 재업로드로 + * 옛 노선번호가 남을까 봐 넣은 안전장치인데, 그 탓에 B05↔B06을 오갈 때마다 화면이 + * 처음부터 다시 섰다. 이제 서명(노선번호·지표면)이 달라졌을 때만 다시 그린다. + */ + async function verifyLatestFreshness(shown: RouteLatestResponse): Promise { + try { + const fresh = await fetchLatestRoute(activeProjectId); + writeLatestCache(fresh); + if (latestSignature(fresh) === latestSignature(shown)) return; + renderLatest(fresh); + if (fresh.route?.id) await restoreSections(fresh.route.id); + } catch { + /* 확인 실패는 조용히 넘긴다 — 화면은 캐시로 이미 서 있다. */ + } + } + const panel = createRoutePanel({ onSolve: () => void solveRouteAction(actionContext), onTempSave: () => void tempSaveAction(actionContext), @@ -420,7 +455,9 @@ export async function renderB05Route(root: HTMLElement): Promise { return best.elevation_m; }; // 측점 바 양 끝 램프용 상단측: 사용자 변경분 → solve 자동 판정 순으로 적용. - const withUphill = [...regular, ...injected].map((station) => { + // 구조물 측점과 0.1m 안에서 겹치는 규칙 측점은 지운다 — 3D 측점 띠도 종단 그래프와 + // 같은 규칙을 써야 두 화면의 측점이 어긋나지 않는다(2026-09-06). + const withUphill = [...dropStationsNear(regular, injected), ...injected].map((station) => { const design = designAt(station.chainage_m); return { ...station, @@ -504,7 +541,11 @@ export async function renderB05Route(root: HTMLElement): Promise { chainage_m: station.chainage_m, structure: station.structure ?? "", })); - if (legacy.length) { + // 이관은 멱등이지만 **진입할 때마다** POST 가 나갔다(2026-09-06 실측). 탭 수명 동안 + // 노선마다 한 번만 시도한다 — 옮길 것이 남아 있으면 다음 새로고침에 다시 본다. + const migrateKey = `${activeProjectId}:${routeId}`; + if (legacy.length && !migratedRoutes.has(migrateKey)) { + migratedRoutes.add(migrateKey); void migrateLegacyStations(activeProjectId, legacy) .then((result) => { if (result.migrated > 0) { @@ -618,9 +659,11 @@ export async function renderB05Route(root: HTMLElement): Promise { try { // ② 좌측 폼·노선 설정값 — 도착하는 대로 폼과 3D 마커 복원에 쓴다. + // 캐시가 있으면 그것으로 **먼저** 그리고 신선도는 뒤에서 확인한다 — B05↔B06 이동에서 + // 서버를 다시 부르지 않으려는 것이다(2026-09-06). 캐시가 없을 때만 DB를 기다린다. + const cachedLatest = readLatestCache(); const [latestResponse, sectionContext, configuredRoadWidths] = await Promise.all([ - // 다른 탭의 재업로드로 옛 route_id가 남을 수 있어 진입 때는 DB 최신값을 읽는다. - loadLatest(true), + cachedLatest ? Promise.resolve(cachedLatest) : loadLatest(true), fetchSectionContext(activeProjectId), fetchRoadWidths(activeProjectId), ]); @@ -651,9 +694,9 @@ export async function renderB05Route(root: HTMLElement): Promise { latest = latestResponse; advanceLoading("확정 지표면 모델을 확인하는 중…"); - // ③ 확정 지표면 모델 목록. - const models = await listSurfaceModels(activeProjectId); - confirmedSurface = models.models.find((model) => model.status === "CONFIRMED") ?? null; + // ③ 확정 지표면 — 모델 id·범위를 한 번에 받는다. + const confirmed = await fetchConfirmedSurface(activeProjectId); + confirmedSurface = confirmed.model_id === null ? null : confirmed; if (!confirmedSurface) { // 새 자료가 올라와 옛 결과가 지워진 상태 — 여기서 보여 줄 게 없다. leaveForDashboard(); @@ -666,6 +709,9 @@ export async function renderB05Route(root: HTMLElement): Promise { // 구조물 타입 레지스트리·정본 — 노선이 없어도 목록은 보여 준다(추가는 노선 이후). await bridge.load(); advanceLoading(""); + // 캐시로 그렸다면 이제 뒤에서 신선도만 확인한다 — 화면은 이미 서 있으므로 기다리지 + // 않는다. 다른 탭이 자료를 갈아 끼웠을 때만 다시 그린다. + if (cachedLatest) void verifyLatestFreshness(latestResponse); } catch (error) { showToast(error instanceof Error ? error.message : "화면을 불러오지 못했습니다.", "error"); } finally { @@ -679,16 +725,15 @@ export async function renderB05Route(root: HTMLElement): Promise { const [surface, current] = [confirmedSurface, latest]; if (!surface || !current) return; try { - // 가장자리만 받는다 — 포인트클라우드 전체(수십 MB)는 안 받는다. - const confirmed = await fetchConfirmedSurface(activeProjectId); - if (!confirmed.bounds) throw new Error("지표면 범위 정보를 찾을 수 없습니다."); + // 범위는 ③에서 받아 둔 확정 응답에 이미 들어 있다 — 다시 부르지 않는다. + if (!surface.bounds) throw new Error("지표면 범위 정보를 찾을 수 없습니다."); await viewer.loadSurface( activeProjectId, - surface.id, + surface.model_id as number, current.surface_params.method, current.surface_params.smooth, current.surface_params.contour_interval_m, - toBounds(confirmed.bounds), + toBounds(surface.bounds), ); renderLatest(current); // 지형이 올라온 뒤에야 마커·측점선이 지형 위에 놓인다. if (currentSectionDetail) renderStationLines(currentSectionDetail); diff --git a/B05_Profile/B05_Profile_UI_Page_Actions.ts b/B05_Profile/B05_Profile_UI_Page_Actions.ts index 0b4b0424..f5aac8a3 100644 --- a/B05_Profile/B05_Profile_UI_Page_Actions.ts +++ b/B05_Profile/B05_Profile_UI_Page_Actions.ts @@ -16,7 +16,6 @@ import { showToast, } from "@ui/ui_template_elements"; import { navigateTo } from "../A00_Common/router"; -import type { SurfaceModelSummary } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { clearRouteLatestCache, confirmRoute, @@ -29,7 +28,7 @@ import { invalidateSectionDetail, saveCachedCrossPatches, } from "../B06_Section/B06_Section_Section_Store"; -import { clearStandardCrossSession } from "../B06_Section/B06_Section_UI_Standard_Panel"; +import { clearDrafts } from "../A00_Common/b_page_state"; import { saveCorridorIfDirty } from "./B05_Profile_UI_Corridor"; import { circlePoint, routePoint } from "./B05_Profile_UI_Page_Helpers"; import { clearAlignmentDrafts } from "./B05_Profile_UI_Profile_Edit"; @@ -46,7 +45,8 @@ function L(key: keyof typeof ui_locales): string { export interface PageActionContext { projectId: string; latest: () => RouteLatestResponse | null; - confirmedSurface: () => SurfaceModelSummary | null; + /** 확정 지표면 응답 — 모델 id 는 `model_id` 다(2026-09-06 호출 정리). */ + confirmedSurface: () => { model_id: number | null } | null; routeReady: () => boolean; viewer: () => ReturnType; panel: () => ReturnType; @@ -77,7 +77,7 @@ export async function solveRouteAction(ctx: PageActionContext): Promise { filter_key: latest.surface_params.source_filter, method: latest.surface_params.method, smooth: latest.surface_params.smooth, - surface_model_id: confirmedSurface.id, + surface_model_id: confirmedSurface.model_id ?? undefined, algorithm: values.algorithm, bp: routePoint(points.bp), ep: routePoint(points.ep), @@ -149,7 +149,7 @@ export async function tempSaveAction(ctx: PageActionContext): Promise { filter_key: latest?.surface_params.source_filter, method: latest?.surface_params.method, smooth: latest?.surface_params.smooth, - surface_model_id: ctx.confirmedSurface()?.id, + surface_model_id: ctx.confirmedSurface()?.model_id ?? undefined, irregular_stations: ctx .bridge() .irregularStations() @@ -202,11 +202,11 @@ export async function resetDesignAction(ctx: PageActionContext): Promise { // 옛 경로 기준 캐시를 전부 비우고 페이지를 새로 그린다 — 초기 계산본이 정본이 된다. clearRouteLatestCache(ctx.projectId); invalidateSectionDetail(ctx.projectId); - // 프로젝트 단위 세션 값도 함께 버린다 — 키에 route_id가 없어 새 노선에 그대로 - // 되붙는다(2026-08-28). 초기화는 "사용자 편집을 전부 버린다"가 규약이다. + // 사용자 조작(② 초안)은 **등록표 한 곳**에서 통째로 버린다(2026-09-06 일원화). + // 예전에는 파일마다 따로 지워 새 값이 늘 때 빠뜨리기 쉬웠다. 노선 범위 초안은 + // 노선이 바뀌면 키가 달라져 자연히 딸려 오지 않는다. + clearDrafts(ctx.projectId, ctx.latest()?.route?.id ?? null); ctx.uphillOverrides.clear(); - ctx.persistUphillOverrides(); - clearStandardCrossSession(ctx.projectId); // 계획선 편집 초안도 함께 버린다 — 남기면 초기값 위에 옛 편집이 다시 얹혀 계획선이 // 측점에서 원지반선과 만나지 않는다(2026-09-04 실측: 새로고침 후 최대 6.0m 어긋남). clearAlignmentDrafts(); diff --git a/B05_Profile/B05_Profile_UI_Page_Helpers.ts b/B05_Profile/B05_Profile_UI_Page_Helpers.ts index a623b345..b0b158bb 100644 --- a/B05_Profile/B05_Profile_UI_Page_Helpers.ts +++ b/B05_Profile/B05_Profile_UI_Page_Helpers.ts @@ -7,6 +7,7 @@ * 전부 상태를 갖지 않는 변환 함수라 화면 흐름과 독립적이다. * ========================================================================== */ +import { readState, writeState } from "../A00_Common/b_page_state"; import type { RoutePanelValues } from "./B05_Profile_UI_Panel"; import type { ModelBounds, @@ -246,19 +247,15 @@ export const FACILITY_NAMES: Record = { /* ── 측점 상단측(=측구 방향) 사용자 변경분 세션 보관 ───────────────────── * 3D 램프 클릭으로 바꾼 값. 경로 확정 때 uphill_overrides로 백엔드에 병합한다. * 화면 본체가 700줄에 닿아 읽기·쓰기만 여기로 뺐다(2026-09-04, 동작 불변). */ -const uphillSessionKey = (projectId: string): string => `b05:uphill:${projectId}`; - /** 세션에 남은 상단측 변경분을 읽는다. 손상된 값은 무시하고 빈 것으로 시작한다. */ export function loadUphillOverrides(projectId: string): Map { const overrides = new Map(); try { - const raw = window.sessionStorage.getItem(uphillSessionKey(projectId)); - if (!raw) return overrides; - Object.entries(JSON.parse(raw) as Record).forEach( - ([chainage, side]) => { - if (side === "left" || side === "right") overrides.set(chainage, side); - }, - ); + const stored = readState>("uphill", projectId); + if (!stored) return overrides; + Object.entries(stored).forEach(([chainage, side]) => { + if (side === "left" || side === "right") overrides.set(chainage, side); + }); } catch { /* 손상된 세션 값은 무시 — 자동 판정값으로 재시작. */ } @@ -271,10 +268,7 @@ export function saveUphillOverrides( overrides: ReadonlyMap, ): void { try { - window.sessionStorage.setItem( - uphillSessionKey(projectId), - JSON.stringify(Object.fromEntries(overrides)), - ); + writeState("uphill", Object.fromEntries(overrides), projectId); } catch { /* 세션 저장 실패는 무시 — 값은 메모리에 유지된다. */ } diff --git a/B05_Profile/B05_Profile_UI_Page_Structures.ts b/B05_Profile/B05_Profile_UI_Page_Structures.ts index 7402e314..61cde2be 100644 --- a/B05_Profile/B05_Profile_UI_Page_Structures.ts +++ b/B05_Profile/B05_Profile_UI_Page_Structures.ts @@ -119,9 +119,11 @@ export function createStructuresBridge(deps: StructuresBridgeDeps) { } /* ── 구조물 정본(structures.json) ──────────────────────────────────── - * 사이드 목록이 바뀌면 곧바로 서버 정본에 저장한다 — 화면에만 남겨 두면 새로고침에 - * 사라지고, 다른 창과도 어긋난다. 판번호가 밀리면(다른 창이 먼저 저장) 최신본을 - * 받아 화면을 맞추고 사용자에게 알린다. */ + * 목록이 바뀌면 **세션 초안**에 담고(`writePending`), 정본에는 [저장]·[확정]에서만 + * 쓴다(`saveStructuresIfDirty`). 판번호가 밀리면(다른 창이 먼저 저장) 최신본을 + * 받아 화면을 맞추고 사용자에게 알린다. + * (옛 주석은 「곧바로 서버에 저장한다」였다 — 2026-08-29 에 초안 방식으로 바뀌었고 + * 주석만 남아 있었다. 2026-09-06 정정.) */ let structureRevision = 0; let structureSaving: Promise = Promise.resolve(); diff --git a/B05_Profile/B05_Profile_UI_Panel.ts b/B05_Profile/B05_Profile_UI_Panel.ts index 905b0ca2..e9ec05cf 100644 --- a/B05_Profile/B05_Profile_UI_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Panel.ts @@ -387,7 +387,11 @@ export function createRoutePanel(callbacks: PanelCallbacks) { minUphillGrade.wrapper, minDownhillGrade.wrapper, ); + // [최적 경로 계산] 입구는 2026-09-06 사용자 확정으로 화면에서 내렸다 — 평면만 보고 + // 노선을 정하는 방식이라 실제 판단(평면·종단·횡단·유토곡선을 함께 봄)과 맞지 않는다. + // 코드·API 는 그대로 두고 버튼만 뺀다. 노선 변경은 계획노선 편집이 대신한다. const solveButton = button("최적 경로 계산", callbacks.onSolve, "filled"); + solveButton.hidden = true; routeCalc.body.append( algorithmField.root, paved.wrapper, diff --git a/B05_Profile/B05_Profile_UI_Profile_Alignment.ts b/B05_Profile/B05_Profile_UI_Profile_Alignment.ts index 929494dc..1a6c62b1 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Alignment.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Alignment.ts @@ -28,6 +28,10 @@ export interface AlignmentPolicy { max_grade_pct: number; curve_skip_delta_pct: number; paved: boolean; + /** 법정 평면 최소곡선반지름(m) — 위반 표시 기준. 0이면 판정하지 않는다(옛 저장분). */ + min_plan_radius_m?: number; + /** 배향곡선 하한(m) — 이보다 급하면 경고만 낸다(2026-09-06 사용자 확정). */ + hairpin_min_radius_m?: number; } export interface AlignmentNode { diff --git a/B05_Profile/B05_Profile_UI_Profile_Balance.ts b/B05_Profile/B05_Profile_UI_Profile_Balance.ts index 3d5732bf..3c3e262e 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Balance.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Balance.ts @@ -16,6 +16,12 @@ import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment"; import type { MinCoverViolation } from "./B05_Profile_UI_Profile_MinCover"; +import type { MassHaulSummaryValues } from "./B05_Profile_UI_Profile_MassHaul"; + +/** 누가토량 표기 — 천 단위 구분 + 소수점 1자리(유토곡선 요약과 같은 규칙). */ +function volume(value: number): string { + return `${value.toLocaleString("ko-KR", { minimumFractionDigits: 1, maximumFractionDigits: 1 })}㎥`; +} export interface BalanceBarParams { /** 표시줄 컨테이너. 그릴 때마다 통째로 갈아 끼운다. */ @@ -36,6 +42,11 @@ export interface BalanceBarParams { minCoverViolations?: MinCoverViolation[]; /** 요약줄 **오른쪽 끝**에 붙이는 묶음(줌·Y레인지 조작구) — 2026-09-04. */ trailing?: HTMLElement; + /** 유토곡선 총괄값 — 「최대 기울기」 오른쪽에 적는다(2026-09-06 사용자 지시). + * 유토곡선 패널을 접어도 이 값은 남아야 계획선을 만지며 볼 수 있다. */ + massHaul?: MassHaulSummaryValues | null; + /** 법정 평면 최소곡선반지름 위반(2026-09-06) — 자동 보정 없이 **경고만** 낸다. */ + planCurve?: { count: number; worstRadiusM: number; limitM: number; hairpin: number } | null; /** [초기선 복원] — 편집·비정규 측점을 모두 지운다. */ onResetAll: () => void; } @@ -77,6 +88,23 @@ export function renderBalanceBar(params: BalanceBarParams): void { // 절·성토 불균형은 2026-09-03 사용자 지시로 뺐다. 이 값은 **종단 기준**이었다 — // 계획선과 지반선 사이 세로 면적(㎡)의 절·성토 비이지 실제 토량이 아니다. 의미 있는 // 균형은 횡단 단면적을 쌓아 부피로 내는 하단 유토곡선 요약(㎥)이고, 그쪽이 이미 있다. + // 유토곡선 총괄값 — 「최대 기울기」 **바로 오른쪽**(2026-09-06 사용자 지시). 곡선을 접어도 + // 남는다. 세부 내역(절토·성토·잉여/부족)은 이 항목의 툴팁으로 내렸다 — 예전 요약 막대가 + // 세부를 툴팁에 두던 방식 그대로다. + const mass = params.massHaul; + if (mass) { + entries.push(["누가토량", volume(mass.finalM3), mass.finalM3 < 0 ? "over" : undefined]); + } + // 평면 곡선반경 — 법정 하한을 밑도는 측점이 있을 때만 적는다(별표2 Ⅰ.2.다.(1)). + // 프로그램은 값만 드러내고 고치지 않는다: 노선을 바꿀지는 사용자 판단이다. + const plan = params.planCurve; + if (plan && plan.count > 0) { + entries.push([ + "곡선반경 부족", + `${plan.count} 곳 / 최소 ${plan.worstRadiusM.toFixed(1)} m`, + "over", + ]); + } // 필요한 곳이 없으면 적지 않는다 — "0곳"은 화면 폭만 먹는다. if (curvesNeeded) entries.push(["종단곡선 필요", `${curvesNeeded} 곳`, "over"]); // 횡단배수 최소고 표시는 2026-09-02 사용자 지시로 삭제했다. 편집 차단(강제)은 @@ -91,6 +119,22 @@ export function renderBalanceBar(params: BalanceBarParams): void { item.append(caption, document.createTextNode(value)); // 상한 초과 구간의 내역은 별도 경고 칩 대신 이 항목의 툴팁으로 붙인다 — // 같은 사실을 두 번 적지 않는다(2026-08-19 재편). + if (label === "곡선반경 부족" && plan) { + item.title = [ + `법정 하한 ${plan.limitM.toFixed(1)}m 미만인 측점 ${plan.count}곳`, + `가장 급한 곳 R=${plan.worstRadiusM.toFixed(1)}m`, + plan.hairpin > 0 + ? `그중 배향곡선 하한 미만 ${plan.hairpin}곳 — 경고만 낸다(자동 보정 없음)` + : "배향곡선 하한 미만은 없음", + ].join("\n"); + } + if (label === "누가토량" && mass) { + item.title = [ + `절토(자연) ${volume(mass.cutNaturalM3)} · 절토(다짐) ${volume(mass.cutCompactedM3)}`, + `성토(다짐) ${volume(mass.fillCompactedM3)}`, + mass.shortageM3 > 0 ? `부족 ${volume(mass.shortageM3)}` : `잉여 ${volume(mass.surplusM3)}`, + ].join("\n"); + } if (label === "최대 기울기" && violations.length) { item.title = violations .map( diff --git a/B05_Profile/B05_Profile_UI_Profile_Layout.ts b/B05_Profile/B05_Profile_UI_Profile_Layout.ts index 987aa863..cbf42e8a 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Layout.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Layout.ts @@ -17,8 +17,9 @@ import { type IrregularStation, } from "./B05_Profile_UI_IrregularStations"; -/** 테이블 12행. 행 높이와 셀 폭에서 글자 크기를 정하는 데 쓴다. */ -export const TABLE_ROW_COUNT = 12; +/** 테이블 6행(구배 S · 계획고 · 지반고 · 측점 · 곡선 L · 곡선 R). 행 높이와 셀 폭에서 + * 글자 크기를 정하는 데 쓴다. 2026-09-06 사용자 지시로 12행에서 줄였다. */ +export const TABLE_ROW_COUNT = 6; /** 측점 사이 여백 — 이웃 셀끼리 붙어 보이지 않게 띄운다. */ export const CELL_GAP_PX = 2; diff --git a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts index bc6979ad..7280947b 100644 --- a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts +++ b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts @@ -22,6 +22,7 @@ * 스크롤러와 scrollLeft를 양방향 동기화해 측점 세로선이 어긋나지 않게 한다. * ========================================================================== */ +import { readStateRaw, stateKey, writeStateRaw } from "../A00_Common/b_page_state"; import type { EarthworkConversion, HaulEquipmentLimit, @@ -44,7 +45,6 @@ import { resetBalloonOffsets } from "@util/common_util_mass_haul_balance_view"; import { createMassHaulChart, createMassHaulLegend, - createMassHaulSummary, createMassHaulWindowState, MASS_HAUL_MIN_HEIGHT, scheduleMassHaulSettle, @@ -57,14 +57,16 @@ import "./B05_Profile_UI_Style_MassHaul.css"; import { attachWheelHorizontalScroll } from "./B05_Profile_UI_Profile_Wheel"; /** 2차 패널 펼침 여부 — 세션 동안만 유지(패널 높이·접힘과 같은 수명). */ -const OPEN_KEY = "b05-route-profile-masshaul-open"; +/* 펼침 상태·높이·범례는 화면 취향(①) — 키는 등록표(`b_page_state`)가 만든다. */ /** 오버레이 높이(px) 세션 키 — 메인 하단 패널 높이와 같은 수명. */ -const OVERLAY_HEIGHT_KEY = "b05-route-profile-masshaul-height"; +const OVERLAY_HEIGHT_KEY = stateKey("masshaul-height") ?? ""; /** 오버레이 높이 하한/기본값(px). 곡선 + 요약 막대가 읽히는 최소 크기다. */ const OVERLAY_MIN_HEIGHT = 160; /** 유토곡선 오버레이 최소 높이 — 메인 패널 하한 계산(Profile_Panel)이 함께 쓴다. */ export const MASSHAUL_MIN_HEIGHT = OVERLAY_MIN_HEIGHT; const OVERLAY_DEFAULT_HEIGHT = 280; +/** 전체 맞춤(토량 분배) 보기의 우측 여백(px) — 마지막 점의 값 글자가 잘리지 않을 만큼만. */ +const MASS_FIT_PAD_RIGHT = 12; /** 오버레이가 패널 본문을 다 덮지 않게 남기는 상한 비율. */ const OVERLAY_MAX_RATIO = 0.8; /** 리사이저가 높이를 담는 CSS 변수 — CSS 기본값(280px)은 OVERLAY_DEFAULT_HEIGHT와 같아야 한다. */ @@ -74,8 +76,10 @@ const HEIGHT_VAR = "--b05-masshaul-height"; * 표시 상태가 갈리면 "같은 곡선인데 왜 다르게 보이나"가 된다(2026-08-03 사용자 확정). * 정의처는 B06 `_UI_Section_View`와 이 파일 두 곳뿐이며 값이 반드시 같아야 한다. */ -const VISIBLE_KEY = "b06:masshaul-visible-v4"; -const DEFAULT_VISIBLE: string[] = [...MASS_HAUL_DEFAULT_VISIBLE, MASS_HAUL_BALANCE_KEY]; +/** 처음 열 때는 **곡선만** 보인다 — 토량 분배(평형선·운반 블록)는 범례에서 켠다 + * (2026-09-06 사용자 지시). 판을 v4 → v5 로 올려 이미 켜 둔 브라우저도 새 기본값으로 + * 시작하게 한다. */ +const DEFAULT_VISIBLE: string[] = [...MASS_HAUL_DEFAULT_VISIBLE]; /** 유토곡선 계산에 필요한 프로젝트 설정 — B05 Page가 `fetchSectionContext()`에서 받아 넘긴다. */ export interface RouteMassHaulContext { @@ -162,7 +166,7 @@ export interface RouteMassHaulPanel { function readVisible(): Set { try { - const raw = sessionStorage.getItem(VISIBLE_KEY); + const raw = readStateRaw("masshaul-visible"); if (!raw) return new Set(DEFAULT_VISIBLE); const parsed = JSON.parse(raw) as unknown; // 기준 키는 라디오라 항상 하나로 눌러 맞춘다(B06 읽기와 같은 규칙). @@ -177,7 +181,28 @@ function readVisible(): Set { /** * @param onChanged 펼침·범례 토글·높이 조절로 다시 그려야 할 때 호출된다(패널 전체 redraw). */ -export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPanel { +/** + * 종단 상단줄이 **접힌 상태에서도** 보여 주는 유토곡선 총괄값(2026-09-06 사용자 지시). + * 곡선 자체는 접으면 사라져도 이 값은 계획선을 만지며 계속 봐야 한다. + */ +export interface MassHaulSummaryValues { + /** 노선 끝 누가토량(㎥) — 양수 잉여, 음수 부족. */ + finalM3: number; + /** 절토(자연상태) 합계(㎥). */ + cutNaturalM3: number; + /** 절토를 다짐으로 환산한 값(㎥). */ + cutCompactedM3: number; + /** 성토(다짐) 합계(㎥). */ + fillCompactedM3: number; + surplusM3: number; + shortageM3: number; +} + +export function createRouteMassHaulPanel( + onChanged: () => void, + /** 총괄값이 새로 나올 때마다 부른다 — 종단 상단줄이 받아 적는다. */ + onSummary?: (summary: MassHaulSummaryValues | null) => void, +): RouteMassHaulPanel { // 손잡이는 다른 패널과 **같은 양식**의 표준 삼각형 손잡이 하나만 쓴다(2026-08-04 사용자 // 지시 — 예전 풀폭 바 + "유토곡선" 캡션은 다른 패널들과 모양이 달랐다). 무엇의 손잡이인지는 // 툴팁으로 밝힌다. @@ -187,7 +212,8 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa handle.append(handleControl.root); handleControl.root.setAttribute("aria-label", "유토곡선 패널"); - // 오버레이 뼈대 — 위 경계 리사이저 + 요약 막대 + 가로 스크롤러 + 범례. + // 오버레이 뼈대 — 위 경계 리사이저 + 안내 문구 자리 + 가로 스크롤러 + 범례. + // (요약 막대는 2026-09-06 종단 상단줄로 올라갔다.) const overlay = document.createElement("div"); overlay.className = "b05-profile__masshaul-overlay"; const bar = document.createElement("div"); @@ -200,7 +226,7 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa // 높이를 복원하며 생성 중에 onResize → syncHandlePosition을 부르는데, `open`이 그 아래 // 있으면 TDZ ReferenceError로 B05 페이지 전체가 죽는다(2026-08-04 사용자 보고 — // 저장된 높이가 있는 브라우저에서만 재현되는 이유). - let open = sessionStorage.getItem(OPEN_KEY) === "true"; + let open = readStateRaw("masshaul-open") === "true"; let context: RouteMassHaulContext | null = null; // 높이 조절 — 메인 하단 패널과 같은 공용 리사이저(위 경계, 위로 끌면 커짐, 세션 보존). let resizeRedrawPending = false; @@ -253,7 +279,7 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa function applyOpen(next: boolean): void { open = next; - sessionStorage.setItem(OPEN_KEY, String(next)); + writeStateRaw("masshaul-open", String(next)); handleControl.setOpen(next); // 툴팁은 setOpen이 일반 문구로 덮으므로 매번 유토곡선용으로 다시 밝힌다. handleControl.root.title = next ? "유토곡선 접기" : "유토곡선 펼치기"; @@ -271,7 +297,7 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa function toggleSeries(key: string): void { // 곡선 기준(횡단/종단)은 라디오 — 하나를 고르면 그 기준 그래프만 전체 영역에 보인다. const visible = applyLegendToggle(readVisible(), key); - sessionStorage.setItem(VISIBLE_KEY, JSON.stringify([...visible])); + writeStateRaw("masshaul-visible", JSON.stringify([...visible])); onChanged(); } @@ -313,11 +339,39 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa /** 마지막으로 그린 입력 — 이동이 아직 안 끝났으면 다음 프레임에 이걸로 한 번 더 그린다. */ let lastParams: RouteMassHaulDrawParams | null = null; + /** 총괄값만 따로 낸다 — 패널을 접어도 상단줄이 값을 잃지 않게(2026-09-06). */ + function reportSummary(params: RouteMassHaulDrawParams): void { + if (!onSummary) return; + if (!context || params.pendingRecalc) return; + const series = computeMassHaulSeries( + params.longitudinal, + params.crossSections, + context.conversion, + context.naturalSpoilMinSlope, + ); + if (!series.length) return onSummary(null); + const visible = readVisible(); + const picked = series.find((entry) => visible.has(entry.key)) ?? series[0]; + const result = picked.result; + const cut = result.cut_natural_m3; + const points = result.points; + onSummary({ + finalM3: points.length ? points[points.length - 1].cumulative_volume_m3 : 0, + cutNaturalM3: cut.soil + cut.ripping_rock + cut.blasting_rock, + cutCompactedM3: result.cut_compacted_m3, + fillCompactedM3: result.fill_compacted_m3, + surplusM3: result.surplus_m3, + shortageM3: result.shortage_m3, + }); + } + function draw(params: RouteMassHaulDrawParams): void { lastParams = params; clearSelection = params.onClearSelection; overlay.hidden = !open; syncHandlePosition(); + // 곡선을 그리기 전에 총괄값부터 낸다 — 접혀 있어도 상단줄에는 값이 서야 한다. + reportSummary(params); if (!open) return; if (!context) { note("토량환산계수를 불러오지 못해 유토곡선을 계산할 수 없습니다."); @@ -358,8 +412,8 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa banded && visible.has(MASS_HAUL_BALANCE_KEY) ? computeHaulPlan(banded.result, context.haulLimits) : null; - const summarySeries = banded ?? series[0]; - bar.append(createMassHaulSummary(summarySeries, haulPlan)); + // 요약 막대는 2026-09-06 사용자 지시로 뺐다 — 총괄값은 종단 상단줄이 늘 보여 주고, + // 이 자리는 곡선이 넓게 쓴다. `bar` 는 안내 문구 자리로만 남는다. // 곡선 몫 = 스크롤러의 **안쪽 높이**(clientHeight = 가로 스크롤바 제외). 오버레이 전체 // 높이로 잡으면 스크롤바가 곡선 바닥(Y축 -200 라벨)을 덮는다(2026-08-04 사용자 보고). @@ -370,17 +424,35 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa (overlay.clientHeight || OVERLAY_DEFAULT_HEIGHT) - bar.offsetHeight - 12; const chartHeight = Math.max(scrollHeight, MASS_HAUL_MIN_HEIGHT); + // 토량 분배를 켜면 **곡선 전체가 한 화면에** 들어와야 한다(2026-09-06 사용자 지시). + // 평형선·운반 블록은 노선 전체를 놓고 읽는 그림이라, 종단 그래프와의 X 맞춤(가로 + // 스크롤)과 보이는 구간만 보는 Y 창을 둘 다 버리고 스크롤러 안쪽 폭·전 구간 Y로 그린다. + // 종단과 맞물릴 필요가 없으므로 반 칸 들여쓰기(originOffset)도 쓰지 않는다 — 그만큼 + // 좌우가 비어 곡선이 가운데로 쪼그라들었다(2026-09-06 사용자 보고: 「우측 여유 과다」). + const fitAll = haulPlan !== null; + const widthPx = fitAll ? scroll.clientWidth || params.widthPx : params.widthPx; + const chartAxis = fitAll + ? { + ...params.axis, + padLeft: params.axis.axisX ?? params.axis.padLeft, + padRight: MASS_FIT_PAD_RIGHT, + viewRange: undefined, + window: undefined, + hideStations: true, + } + : { ...params.axis, window: windowState }; + let massAxis: { padLeft: number; ticks: Array<{ y: number; label: string }> } | null = null; const chart = createMassHaulChart( series, visible, params.stationSource, - { ...params.axis, window: windowState }, + chartAxis, params.selectedStationId, params.stationInterval, - params.widthPx, + widthPx, chartHeight, - params.widthPx, + widthPx, params.onSelectStation, haulPlan, (axis) => { @@ -390,14 +462,16 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa // 종단 캔버스와 같은 폭의 래퍼 — sticky Y축 앵커의 기준(position: relative)이 된다. const wrap = document.createElement("div"); wrap.className = "b05-profile__chart b05-profile__masshaul-chart"; - wrap.style.width = `${params.widthPx}px`; + wrap.style.width = `${widthPx}px`; wrap.style.height = `${chartHeight}px`; wrap.append(chart); // 앵커는 첫 자식 — SVG 뒤면 흐름 위치가 밀려 스크롤 시 축이 안 보인다(B06과 같은 규칙). if (massAxis) wrap.prepend(buildStickyYAxis(massAxis, chartHeight)); scroll.replaceChildren(wrap); // 종단 스크롤러가 이미 옆으로 가 있으면 새로 그린 곡선도 같은 자리에서 시작한다. - if (syncedMain) scroll.scrollLeft = syncedMain.scrollLeft; + // 전체 맞춤일 때는 스크롤할 것이 없으므로 왼쪽 끝에 둔다. + if (fitAll) scroll.scrollLeft = 0; + else if (syncedMain) scroll.scrollLeft = syncedMain.scrollLeft; legendLayer.append( createMassHaulLegend(series, visible, toggleSeries, () => { @@ -423,7 +497,7 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa commitHeight(px) { const next = Math.round(px); overlay.style.setProperty(HEIGHT_VAR, `${next}px`); - sessionStorage.setItem(OVERLAY_HEIGHT_KEY, String(next)); + writeStateRaw("masshaul-height", String(next)); syncHandlePosition(); }, syncHandle: () => syncHandlePosition(), diff --git a/B05_Profile/B05_Profile_UI_Profile_Panel.ts b/B05_Profile/B05_Profile_UI_Profile_Panel.ts index 3ea62def..2a60f6d8 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Panel.ts @@ -10,6 +10,7 @@ * `saveProfileAlignment()`로 편집 델타만 보낸다. * ========================================================================== */ +import { readStateRaw, stateKey, writeStateRaw } from "../A00_Common/b_page_state"; import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch"; import { createWorkflowPanelHandle } from "@ui/ui_template_overlay"; import { createPanelResizer } from "@ui/ui_template_resizer"; @@ -46,6 +47,7 @@ import { structureGroupMenuItems } from "./B05_Profile_UI_Profile_Structures"; import { configureBalloonOffsets } from "@util/common_util_mass_haul_balance_view"; import { createRouteMassHaulPanel, + type MassHaulSummaryValues, MASSHAUL_MIN_HEIGHT, type RouteMassHaulContext, } from "./B05_Profile_UI_Profile_MassHaul"; @@ -66,9 +68,8 @@ import "../B06_Section/B06_Section_UI_Style.css"; import "../B06_Section/B06_Section_UI_Style_Cross.css"; import "../B06_Section/B06_Section_UI_Style_Cross_Areas.css"; -const COLLAPSED_KEY = "b05-route-profile-collapsed"; -/** 드래그로 조절한 하단 패널 높이(px) 보관 키 — 브라우저 세션 동안만 유지한다. */ -const HEIGHT_KEY = "b05-route-profile-height"; +/** 접힘·높이는 화면 취향(①) — 키는 등록표(`b_page_state`)가 만든다. */ +const HEIGHT_KEY = stateKey("profile-height") ?? ""; /* 테이블 높이는 오버레이 서브패널(--b05-table-height 리사이저)이 관리한다 — 예전 4:6 고정 분할(TABLE_HEIGHT_KEY·CHART_HEIGHT_RATIO)은 폐지(2026-08-05). */ const MIN_CHART_HEIGHT = 100; @@ -144,7 +145,14 @@ export function createRouteProfilePanel( if (subPanelDragging) scheduleLightSync(); else draw(); }; - const massHaul = createRouteMassHaulPanel(subPanelChanged); + /** 유토곡선 총괄값 — 상단줄이 쓴다. 패널을 접어도 값이 남게 여기에 들고 있는다. */ + let massHaulSummary: MassHaulSummaryValues | null = null; + const massHaul = createRouteMassHaulPanel(subPanelChanged, (summary) => { + const before = massHaulSummary; + massHaulSummary = summary; + // 값이 그대로면 상단줄을 다시 그리지 않는다 — 계획고를 연속으로 누를 때 헛일이 된다. + if (before?.finalM3 !== summary?.finalM3) renderBalance(); + }); bodyWrap.append(massHaul.overlay, massHaul.handle); // 오버레이의 가로 스크롤을 종단 스크롤러와 양방향 동기화 — 측점 세로선 정렬 유지. massHaul.attachScrollSync(body); @@ -317,6 +325,34 @@ export function createRouteProfilePanel( return samples[samples.length - 1][field]; } + /** + * 법정 평면 최소곡선반지름을 밑도는 측점을 센다(별표2 Ⅰ.2.다.(1), 2026-09-06). + * 반경은 횡단 측점마다 실려 오고(`plan_radius_m`), 하한은 계획선 정책이 들고 있다. + * **경고만** 낸다 — 노선을 고칠지는 사용자 판단이다. + */ + function planCurveWarning(): { + count: number; + worstRadiusM: number; + limitM: number; + hairpin: number; + } | null { + const limit = alignment?.policy.min_plan_radius_m ?? 0; + const sections = detail?.cross_sections ?? []; + if (!limit || !sections.length) return null; + const hairpinLimit = alignment?.policy.hairpin_min_radius_m ?? 0; + let count = 0; + let hairpin = 0; + let worst = Number.POSITIVE_INFINITY; + sections.forEach((section) => { + const radius = section.plan_radius_m; + if (typeof radius !== "number" || !Number.isFinite(radius) || radius >= limit) return; + count += 1; + worst = Math.min(worst, radius); + if (hairpinLimit > 0 && radius < hairpinLimit) hairpin += 1; + }); + return count ? { count, worstRadiusM: worst, limitM: limit, hairpin } : null; + } + function renderBalance(): void { const minCoverViolations = findMinCoverViolations( minCoverTargets, @@ -324,11 +360,13 @@ export function createRouteProfilePanel( (chainageM) => sampleAt(chainageM, "elevation_m"), ); renderBalanceBar({ + planCurve: planCurveWarning(), minCoverViolations, balanceBar, tools: tools.render(), trailing: profileZoom.bar, alignment, + massHaul: massHaulSummary, legacyAlignment: !!detail && hasLegacyAlignment(detail.longitudinal), edited: store.edited(), hasIrregularStations: irregularStations.length > 0, @@ -590,14 +628,14 @@ export function createRouteProfilePanel( function setCollapsed(collapsed: boolean): void { root.classList.toggle("is-collapsed", collapsed); panelHandle.setOpen(!collapsed); - sessionStorage.setItem(COLLAPSED_KEY, String(collapsed)); + writeStateRaw("profile-collapsed", String(collapsed)); if (!collapsed) requestAnimationFrame(draw); } panelHandle.root.addEventListener("click", () => setCollapsed(!root.classList.contains("is-collapsed")), ); - setCollapsed(sessionStorage.getItem(COLLAPSED_KEY) === "true"); + setCollapsed(readStateRaw("profile-collapsed") === "true"); return { root, diff --git a/B05_Profile/B05_Profile_UI_Profile_Render.ts b/B05_Profile/B05_Profile_UI_Profile_Render.ts index cc84fe5d..062d250e 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Render.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Render.ts @@ -8,6 +8,7 @@ * 거친다. 그래프·테이블·유토곡선이 같은 X 매핑을 쓰는 규칙은 그대로다. * ========================================================================== */ +import { dropStationsNear } from "./B05_Profile_Util_Station"; import { createLongitudinalProfile, longitudinalMinimumWidth, @@ -237,9 +238,13 @@ export function renderProfile(ctx: ProfileRenderContext): void { // 그대로 남는다(2026-08-02 사용자 보고). const regular = graphData.stations.filter((station) => station.kind !== "irregular"); const injected = irregularGraphStations(irregularStations, maxChainageOf(longitudinal)); + // 구조물 측점과 0.1m 안에서 겹치는 규칙 측점은 지운다 — 세로선·라벨이 두 겹으로 + // 겹쳐 읽히지 않는다(2026-09-06). 남는 쪽은 구조물 측점이다. const graphLongitudinal = { ...graphData, - stations: [...regular, ...injected].sort((a, b) => a.chainage_m - b.chainage_m), + stations: [...dropStationsNear(regular, injected), ...injected].sort( + (a, b) => a.chainage_m - b.chainage_m, + ), }; // 세로 자동 맞춤 — 지금 화면에 보이는 누가거리 구간만 보고 Y 창을 잡는다(2026-09-04 // 사용자 확정). 가로 스크롤 위치(`scrollLeft`)와 본문 폭이 곧 보이는 구간이다. @@ -427,9 +432,9 @@ export function renderProfile(ctx: ProfileRenderContext): void { padRight: LONG_PAD.right + originOffset, // 축 선·눈금은 위 종단 그래프의 축과 같은 자리에 — 축이 두 개로 보이지 않게. axisX: LONG_PAD.left, - // 범례·기준 버튼 오버레이(top 34px)가 곡선 위에 떠서 그만큼 상단 여유를 준다 - // (2026-08-05 사용자 보고: 버튼과 커브 겹침). - padTop: 40, + // 범례·기준 버튼 오버레이(top 4px)가 곡선 위에 떠서 그 높이만큼만 여유를 준다 + // (2026-08-05: 버튼과 커브 겹침 / 2026-09-06: 요약 막대가 빠져 상단이 너무 비었음). + padTop: 30, // 유토곡선 Y 도 종단과 같은 창을 본다 — 전 구간 최대 토량으로 고정하면 확대해도 // 곡선이 납작하게 눌린다(2026-09-04 사용자 지시). viewRange: { fromM: viewFromM, toM: viewToM }, diff --git a/B05_Profile/B05_Profile_UI_Profile_Table.ts b/B05_Profile/B05_Profile_UI_Profile_Table.ts index 581345f4..e1cb163f 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Table.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Table.ts @@ -1,10 +1,11 @@ /* ============================================================================= * B05_Profile_UI_Profile_Table.ts - * 종단면도 하단 도면 테이블 (구배 3행 · 측점값 7행 · 곡선 2행 = 12행). + * 종단면도 하단 도면 테이블 (구배 1행 · 측점값 3행 · 곡선 2행 = 6행). * - * 실무 종단면도 좌측 하단 표를 그대로 옮긴 구성이다. 구배와 곡선은 단일값 행이 아니라 - * 도면에서도 여러 줄로 찍히므로 각각 물리적인 행으로 분리했다. - * - 구배: 연장 / 고저차 / 기울기 3행. 블록은 곡선 구간을 뺀 실제 직선부만 덮는다. + * 실무 종단면도 좌측 하단 표를 옮긴 구성이되, **화면에서는 판단에 쓰는 행만** 둔다 + * (2026-09-06 사용자 지시 — 표가 그래프 자리를 너무 먹었다). 뺀 6행은 구배 L·H, + * 절토고, 성토고, 누가거리, 거리이며 **B07 도면 종단도는 12행 그대로**다(별도 코드). + * - 구배: 기울기(S) 1행. 블록은 곡선 구간을 뺀 실제 직선부만 덮는다. * - 곡선: 곡선길이 / 반경 2행. 반경 R만 입력 가능하고 L = R × |대수차| 로 따라온다. * * 값에는 `L=` 같은 접두를 붙이지 않는다 — 행 이름표가 이미 항목과 단위를 말해준다. @@ -173,10 +174,9 @@ function createRow(className: string, label: string, unit: string): HTMLElement return row; } -/** 도면의 구배 블록 3행: 구간 연장(m) / 고저차(m) / 기울기(%). 단위는 행 이름표가 대신한다. */ +/** 화면 구배 블록 1행: 기울기(%). 연장·고저차 두 행은 2026-09-06 사용자 지시로 뺐다 — + * 두 값은 블록 툴팁에 그대로 남아 있어 필요할 때 짚어 볼 수 있다. */ const SEGMENT_ROWS: SegmentRowSpec[] = [ - { label: "구배 L", unit: "m 구간 연장", cell: (segment) => segment.length_m.toFixed(2) }, - { label: "구배 H", unit: "m 구간 고저차", cell: (segment) => segment.height_m.toFixed(2) }, { label: "구배 S", unit: "% 구간 기울기", cell: (segment) => segment.grade_percent.toFixed(2) }, ]; @@ -194,19 +194,9 @@ function buildStationRows( display: { station: number; cumulative: number }, ): StationRowSpec[] { const stations = alignment.stations; + // 절토고·성토고·누가거리·거리 네 행은 2026-09-06 사용자 지시로 뺐다 — 절·성토는 + // 그래프 음영과 유토곡선이, 누가거리는 측점 라벨이 이미 말해 준다. return [ - { - label: "절토고", - unit: "m", - modifier: "cut", - cell: (index) => (stations[index].cut_m > 0.005 ? stations[index].cut_m.toFixed(2) : ""), - }, - { - label: "성토고", - unit: "m", - modifier: "fill", - cell: (index) => (stations[index].fill_m > 0.005 ? stations[index].fill_m.toFixed(2) : ""), - }, { label: "계획고", unit: "m", @@ -214,16 +204,6 @@ function buildStationRows( cell: (index) => stations[index].plan_elevation_m.toFixed(2), }, { label: "지반고", unit: "m", cell: (index) => stations[index].ground_elevation_m.toFixed(2) }, - { - label: "누가거리", - unit: "m", - cell: (index) => (stations[index].chainage_m + display.cumulative).toFixed(2), - }, - { - label: "거리", - unit: "m 전 측점 대비", - cell: (index) => (index ? stations[index].distance_m.toFixed(2) : ""), - }, { label: "측점", unit: "측점번호+잔여거리", @@ -233,7 +213,7 @@ function buildStationRows( } /** - * 구배 3행. 각 블록은 **변화점에서 변화점까지**를 덮는다. + * 구배 행. 각 블록은 **변화점에서 변화점까지**를 덮는다. * * 구분선을 곡선의 접선점(BVC/EVC)에 두면 곡선 길이만큼 블록 사이에 틈이 생기고, * 양옆 블록의 테두리가 그 틈을 감싸 "빈 셀"처럼 보인다. 변화점은 곧 **생성된 R의 @@ -268,7 +248,7 @@ function buildSegmentRows( const span = x(segment.to_m) - left; const text = spec.cell(segment); const node = element("span", "b05-profile-table__segment", ""); - // 구배 3행(L·H·S)은 **늘 보인다** — 구조물로 갈라진 좁은 구간도 값을 적는다 + // 구배 행은 **늘 보인다** — 구조물로 갈라진 좁은 구간도 값을 적는다 // (2026-09-04 사용자 확정: 값 열을 접는 규칙에서 구배 행은 제외). // 옛 규칙(2026-08-03: 구조물 구간은 고를 때만 값 표시)은 여기서 걷어냈고, // 구조물 구간 표시(색·하이라이트)와 툴팁은 그대로 둔다. @@ -499,27 +479,13 @@ function buildSelectedColumn( const curveAt = alignment.curves.find((entry) => Math.abs(entry.chainage_m - chainage) < 0.01); // 값 열 오버레이도 같은 규칙 — 직선화된 자리는 곡선 L·R 을 비운다. const curve = curveAt && !isStraightCurve(curveAt) ? curveAt : undefined; - // 거리: 바로 앞 측점(계획선 측점)까지의 간격. - const previous = alignment.stations - .filter((row) => row.chainage_m < chainage - 1e-6) - .reduce( - (acc, row) => (acc === null ? row.chainage_m : Math.max(acc, row.chainage_m)), - null, - ); - const distance = previous !== null ? chainage - previous : null; - - // 테이블 행 순서(구배 3 · 측점값 7 · 곡선 2)와 정확히 같게 채운다. 없는 값은 공백. - // `plan: true`인 계획고 행만 직접 입력 셀로 만든다(값 열은 오버레이라 실제 12행 격자는 불변). + // 테이블 행 순서(구배 1 · 측점값 3 · 곡선 2)와 정확히 같게 채운다. 없는 값은 공백. + // `plan: true`인 계획고 행만 직접 입력 셀로 만든다(값 열은 오버레이라 실제 6행 격자는 불변). + // 절토·성토고는 행이 빠졌어도 값 자체는 툴팁에 남긴다 — 고른 측점에서 흔히 찾는 값이다. const rows: Array<{ value: CellValue; modifier: string; plan?: boolean }> = [ - { value: gradeCell((segment) => segment.length_m, 2), modifier: "" }, // 구배 L - { value: gradeCell((segment) => segment.height_m, 2), modifier: "" }, // 구배 H { value: gradeCell((segment) => segment.grade_percent, 2), modifier: "grade" }, // 구배 S - { value: { text: cut !== null ? cut.toFixed(2) : "" }, modifier: "cut" }, // 절토고 - { value: { text: fill !== null ? fill.toFixed(2) : "" }, modifier: "fill" }, // 성토고 { value: { text: plan !== null ? plan.toFixed(2) : "" }, modifier: "plan", plan: true }, // 계획고 { value: { text: ground !== null ? ground.toFixed(2) : "" }, modifier: "" }, // 지반고 - { value: { text: (chainage + display.cumulative).toFixed(2) }, modifier: "" }, // 누가거리 - { value: { text: distance !== null ? distance.toFixed(2) : "" }, modifier: "" }, // 거리 { value: { text: displayStationLabel(chainage, interval, display.station) }, modifier: "" }, // 측점 { value: { text: curve ? curve.l_m.toFixed(2) : "" }, modifier: "" }, // 곡선 L { value: { text: curve ? curve.r_m.toFixed(1) : "" }, modifier: "" }, // 곡선 R @@ -560,9 +526,16 @@ function buildSelectedColumn( } column.append(cell); }); - column.title = `${displayStationLabel(chainage, interval, display.station)} · ${( + // 행에서 뺀 값(절토고·성토고·누가거리)은 툴팁에 남긴다 — 고른 측점에서 흔히 찾는 값이다. + const cutFillText = + cut !== null + ? ` · 절토 ${cut.toFixed(2)}m` + : fill !== null + ? ` · 성토 ${fill.toFixed(2)}m` + : ""; + column.title = `${displayStationLabel(chainage, interval, display.station)} · 누가거리 ${( chainage + display.cumulative - ).toFixed(2)}m`; + ).toFixed(2)}m${cutFillText}`; return column; } diff --git a/B05_Profile/B05_Profile_UI_Profile_TableOverlay.ts b/B05_Profile/B05_Profile_UI_Profile_TableOverlay.ts index 2738f154..ea11fbce 100644 --- a/B05_Profile/B05_Profile_UI_Profile_TableOverlay.ts +++ b/B05_Profile/B05_Profile_UI_Profile_TableOverlay.ts @@ -10,18 +10,28 @@ * 가로 오프셋). 테이블 내용물은 Profile_Panel의 draw()가 만들어 setTable로 넣는다. * ========================================================================== */ +import { readStateRaw, stateKey, writeStateRaw } from "../A00_Common/b_page_state"; import { createWorkflowPanelHandle } from "@ui/ui_template_overlay"; import { createPanelResizer } from "@ui/ui_template_resizer"; +import { TABLE_ROW_COUNT } from "./B05_Profile_UI_Profile_Layout"; import { attachWheelHorizontalScroll } from "./B05_Profile_UI_Profile_Wheel"; -const OPEN_KEY = "b05:profile:table:open"; -const HEIGHT_KEY = "b05:profile:table:height"; +/* 펼침·높이는 화면 취향(①) — 키는 등록표(`b_page_state`)가 만든다. */ +const HEIGHT_KEY = stateKey("table-height") ?? ""; const OVERLAY_MIN_HEIGHT = 140; /** 테이블 오버레이 최소 높이 — 메인 패널 하한 계산(Profile_Panel)이 함께 쓴다. */ export const TABLE_OVERLAY_MIN_HEIGHT = OVERLAY_MIN_HEIGHT; const OVERLAY_MAX_RATIO = 0.75; -/** CSS 기본 높이 — `var(--b05-table-height, 300px)`(_Style_MassHaul.css)와 같아야 한다. */ -const OVERLAY_DEFAULT_HEIGHT = 300; +/** 행 하나의 높이 상한(px). 행이 이보다 커지면 글자만 커지고 읽을 내용은 그대로다 — + * 12행에서 6행으로 줄인 뒤 같은 높이를 나눠 가지며 행이 두 배로 부푼 것을 막는다 + * (2026-09-06 사용자 지시: 「최대값 제한, 레이아웃 제어는 현재 유지」). */ +const MAX_ROW_HEIGHT = 30; +/** 오버레이 높이 상한 = 6행 × 행 상한 + 가로 스크롤바·경계 몫. */ +const OVERLAY_MAX_HEIGHT = TABLE_ROW_COUNT * MAX_ROW_HEIGHT + 24; +/** CSS 기본 높이 — `var(--b05-table-height, 204px)`(_Style_MassHaul.css)와 같아야 한다. */ +const OVERLAY_DEFAULT_HEIGHT = OVERLAY_MAX_HEIGHT; +/** 어느 경로로 들어온 높이든 상한을 넘지 않게 한다(리사이저·패널 비례 연동 공용). */ +const clampHeight = (px: number): number => Math.min(px, OVERLAY_MAX_HEIGHT); /** 리사이저가 높이를 담는 CSS 변수. */ const HEIGHT_VAR = "--b05-table-height"; @@ -61,7 +71,7 @@ export function createProfileTableOverlay(onChanged: () => void): RouteProfileTa // 상태 선언은 리사이저 생성보다 먼저 — 세션 높이 복원이 생성 중 onResize를 부른다 // (유토곡선 TDZ 크래시와 같은 함정, 2026-08-04 확인). - let open = sessionStorage.getItem(OPEN_KEY) !== "false"; // 기본 펼침(기존 테이블 상시 표시 유지) + let open = readStateRaw("table-open") !== "false"; // 기본 펼침(기존 테이블 상시 표시 유지) let bottomOffset = 0; let resizeRedrawPending = false; const resizer = createPanelResizer({ @@ -70,7 +80,8 @@ export function createProfileTableOverlay(onChanged: () => void): RouteProfileTa cssVar: HEIGHT_VAR, direction: -1, min: OVERLAY_MIN_HEIGHT, - max: () => (overlay.parentElement?.clientHeight ?? window.innerHeight) * OVERLAY_MAX_RATIO, + max: () => + clampHeight((overlay.parentElement?.clientHeight ?? window.innerHeight) * OVERLAY_MAX_RATIO), storageKey: HEIGHT_KEY, onResize: () => { syncHandlePosition(); @@ -99,7 +110,7 @@ export function createProfileTableOverlay(onChanged: () => void): RouteProfileTa function applyOpen(next: boolean): void { open = next; - sessionStorage.setItem(OPEN_KEY, String(next)); + writeStateRaw("table-open", String(next)); handleControl.setOpen(next); handleControl.root.title = next ? "테이블 접기" : "테이블 펼치기"; handle.classList.toggle("is-open", next); @@ -131,12 +142,12 @@ export function createProfileTableOverlay(onChanged: () => void): RouteProfileTa isOpen: () => open, desiredHeight: () => { const raw = parseFloat(overlay.style.getPropertyValue(HEIGHT_VAR)); - return Number.isFinite(raw) && raw > 0 ? raw : OVERLAY_DEFAULT_HEIGHT; + return clampHeight(Number.isFinite(raw) && raw > 0 ? raw : OVERLAY_DEFAULT_HEIGHT); }, commitHeight: (px) => { - const next = Math.round(px); + const next = Math.round(clampHeight(px)); overlay.style.setProperty(HEIGHT_VAR, `${next}px`); - sessionStorage.setItem(HEIGHT_KEY, String(next)); + writeStateRaw("table-height", String(next)); syncHandlePosition(); }, contentHeight: () => Math.max(0, overlay.offsetHeight - 6), diff --git a/B05_Profile/B05_Profile_UI_Profile_Wheel.ts b/B05_Profile/B05_Profile_UI_Profile_Wheel.ts index 5ee726db..d174fc83 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Wheel.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Wheel.ts @@ -12,6 +12,10 @@ * 거리의 일정 비율씩 좁힌다. 목표가 늘어나도 속도가 이어지므로 굴릴수록 뒤처지지 않는다. * * Shift+휠은 브라우저 기본 가로 스크롤이라 건드리지 않는다. + * + * **끌어서 이동**(2026-09-06 사용자 지시) — 스크롤바를 잡지 않고 그림 위에서 바로 끌어 + * 옮긴다. 좌클릭·휠 버튼 둘 다 되며, 여기 한 곳만 고치면 이것을 쓰는 세 곳(종단 그래프· + * 유토곡선·측점 테이블)이 함께 얻는다. * ========================================================================== */ /** 프레임마다 남은 거리에서 좁히는 비율. 0.35면 60fps에서 약 0.13초에 도착한다 — @@ -19,6 +23,14 @@ const EASE = 0.35; /** 이보다 가까우면 도착으로 보고 딱 맞춘다(px). */ const SNAP_PX = 0.5; +/** 이만큼 넘게 움직여야 "끌기"로 본다(px). 그 아래는 클릭(측점 선택)으로 흘려보낸다. */ +/** 이만큼 움직여야 「끌기」로 본다 — 그 아래는 클릭이다. + * 4px 은 손 떨림에도 넘어가 측점을 고르기 어려웠다(2026-09-06 사용자 지적). */ +const DRAG_THRESHOLD_PX = 6; +/** 끌기를 시작하면 안 되는 조작 부품 — 이 위에서 누른 것은 그 부품의 몫이다. + * 구조물 마크는 자기 `pointerdown`에서 전파를 끊으므로 여기 적지 않아도 된다. */ +const DRAG_BLOCK_SELECTOR = + "button, input, select, textarea, a, .ui-resizer, .b05-profile-edit__btn"; /** EASE의 기준 프레임 간격(ms) — 60Hz 한 칸. */ const BASE_FRAME_MS = 1000 / 60; /** 한 프레임으로 인정하는 최대 간격(ms). 탭이 잠들었다 깨면 간격이 수백 ms라 그대로 @@ -83,4 +95,84 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void { }, { passive: false }, ); + + /* ── 끌어서 이동 ───────────────────────────────────────────────────────── + * 좌클릭(0)·휠 버튼(1)으로 잡아 끈다. 문턱을 넘긴 뒤에야 이동으로 보고, 넘긴 경우에만 + * 뒤따르는 click을 한 번 삼킨다 — 그래야 "그림을 조금 움직였는데 측점 선택이 풀리는" + * 일이 없다. + * + * ⚠ 포인터 잡기(`setPointerCapture`)는 **문턱을 넘긴 뒤에만** 한다(2026-09-06). + * 누르는 즉시 잡으면 뒤따르는 click 의 대상이 측점 `` 가 아니라 스크롤러가 되어, + * 측점 클릭이 배경 클릭으로 처리되고 선택이 그 자리에서 풀렸다 — 「측점을 골라도 + * 하이라이트가 안 된다」는 증상의 원인. 끌기가 실제로 시작된 뒤에는 잡아 두어야 + * 창 밖에서 손을 떼도 이동이 풀리지 않는다. + */ + let dragId: number | null = null; + let dragX = 0; + let dragY = 0; + let dragLeft = 0; + let dragTop = 0; + let dragMoved = false; + + function endDrag(): void { + if (dragId === null) return; + if (scroller.hasPointerCapture(dragId)) scroller.releasePointerCapture(dragId); + dragId = null; + scroller.style.cursor = ""; + scroller.style.userSelect = ""; + // 끈 뒤의 click 한 번만 삼킨다(캡처 단계라 아래 리스너보다 먼저 잡는다). + if (dragMoved) { + const swallow = (event: MouseEvent): void => { + event.stopPropagation(); + event.preventDefault(); + }; + scroller.addEventListener("click", swallow, { capture: true, once: true }); + // 클릭이 안 오는 경우(휠 버튼 등)를 대비해 다음 프레임에 걷어낸다. + requestAnimationFrame(() => + scroller.removeEventListener("click", swallow, { capture: true }), + ); + } + dragMoved = false; + } + + scroller.addEventListener("pointerdown", (event) => { + if (dragId !== null || (event.button !== 0 && event.button !== 1)) return; + if ((event.target as HTMLElement | null)?.closest(DRAG_BLOCK_SELECTOR)) return; + // 끌기가 시작되면 휠 관성 이동은 접는다 — 둘이 같은 scrollLeft를 다투면 튄다. + stop(); + dragId = event.pointerId; + dragX = event.clientX; + dragY = event.clientY; + dragLeft = scroller.scrollLeft; + dragTop = scroller.scrollTop; + dragMoved = false; + // 여기서는 포인터를 잡지 않는다 — 위 주석 참고(클릭이 측점에 닿아야 한다). + // 휠 버튼은 브라우저 자동 스크롤이 뜨므로 막는다. + if (event.button === 1) event.preventDefault(); + }); + + scroller.addEventListener("pointermove", (event) => { + if (dragId !== event.pointerId) return; + const dx = event.clientX - dragX; + const dy = event.clientY - dragY; + if (!dragMoved && Math.abs(dx) < DRAG_THRESHOLD_PX && Math.abs(dy) < DRAG_THRESHOLD_PX) return; + if (!dragMoved) { + dragMoved = true; + scroller.style.cursor = "grabbing"; + // 이제부터 진짜 끌기다 — 창 밖으로 나가도 이어지도록 포인터를 잡는다. + scroller.setPointerCapture(event.pointerId); + // 끄는 동안 글자가 파랗게 잡히지 않게 한다. 포인터 잡기를 미룬 뒤로 브라우저가 + // 기본 글자 선택을 시작했다(2026-09-06 사용자 지적). 이미 잡힌 것도 푼다. + scroller.style.userSelect = "none"; + window.getSelection()?.removeAllRanges(); + } + scroller.scrollLeft = dragLeft - dx; + scroller.scrollTop = dragTop - dy; + event.preventDefault(); + }); + + scroller.addEventListener("pointerup", endDrag); + scroller.addEventListener("pointercancel", endDrag); + // 잡아 둔 포인터를 잃으면(창 전환 등) 끌기도 함께 끝낸다. + scroller.addEventListener("lostpointercapture", endDrag); } diff --git a/B05_Profile/B05_Profile_UI_Structure_Pick_Session.ts b/B05_Profile/B05_Profile_UI_Structure_Pick_Session.ts index 082e66b9..a0214bf3 100644 --- a/B05_Profile/B05_Profile_UI_Structure_Pick_Session.ts +++ b/B05_Profile/B05_Profile_UI_Structure_Pick_Session.ts @@ -9,6 +9,7 @@ * 적혀, 어느 쪽으로 오가든 마지막 선택이 그대로 살아 있다. * ========================================================================== */ +import { readState, writeState } from "../A00_Common/b_page_state"; import type { StructurePick, StructurePickControls } from "./B05_Profile_UI_Viewer_Structure_Pick"; import type { StructuresSection } from "./B05_Profile_UI_Structures_Panel_Types"; import type { StructureInstance } from "./B05_Profile_Api_Structures"; @@ -19,21 +20,15 @@ export interface StructurePickHandoff { key?: string; } -const sessionKey = (projectId: string): string => `aislo:structure-pick:${projectId}`; +/* 넘김값도 ② 설계 초안이다 — 별도 임시 키를 두지 않고 등록표(`b_page_state`)를 쓴다 + (2026-09-06 캐시·세션 일원화). */ /** 세션에 남긴다(선택 해제면 지운다). */ export function rememberStructurePick(projectId: string | null, pick: StructurePick | null): void { if (!projectId) return; - try { - if (!pick) { - window.sessionStorage.removeItem(sessionKey(projectId)); - return; - } - const handoff: StructurePickHandoff = { at: pick.chainageM, key: pick.key }; - window.sessionStorage.setItem(sessionKey(projectId), JSON.stringify(handoff)); - } catch { - /* 세션 저장소가 막힌 환경 — 화면 선택만 살고 넘김은 포기한다. */ - } + if (!pick) return writeState("structure-pick", null, projectId); + const handoff: StructurePickHandoff = { at: pick.chainageM, key: pick.key }; + writeState("structure-pick", handoff, projectId); } /** 화면에서 고른 것을 세션에 적는다 — B06 쪽 창구(측점만 고르면 부재키는 비운다). */ @@ -43,21 +38,20 @@ export function writeStructurePick( key?: string, ): void { if (!projectId) return; - try { - if (at === null) window.sessionStorage.removeItem(sessionKey(projectId)); - else window.sessionStorage.setItem(sessionKey(projectId), JSON.stringify({ at, key })); - } catch { - /* 세션 저장소가 막힌 환경 — 화면 선택만 살고 넘김은 포기한다. */ - } + if (at === null) return writeState("structure-pick", null, projectId); + // 부재키 없이 **측점만** 오는 길(사이드 목록·선택 동기화)이 3D 로 고른 부재키를 지웠다 + // (2026-09-05 진단). 같은 측점이면 이미 적힌 부재키를 지킨다 — 3D 로 고른 직후 선택 + // 동기화가 이 길을 타도 조정창이 그대로 열린다. + const kept = key ?? readStructurePick(projectId)?.key; + writeState("structure-pick", { at, key: kept }, projectId); } /** 세션에 남은 선택을 읽는다(지우지 않는다). 없으면 null. */ export function readStructurePick(projectId: string | null): StructurePickHandoff | null { if (!projectId) return null; try { - const raw = window.sessionStorage.getItem(sessionKey(projectId)); - if (!raw) return null; - const value = JSON.parse(raw) as Partial; + const value = readState>("structure-pick", projectId); + if (!value) return null; if (typeof value.at !== "number" || !Number.isFinite(value.at)) return null; return { at: value.at, key: typeof value.key === "string" ? value.key : undefined }; } catch { diff --git a/B05_Profile/B05_Profile_UI_Style.css b/B05_Profile/B05_Profile_UI_Style.css index a2f2b510..d0b76f53 100644 --- a/B05_Profile/B05_Profile_UI_Style.css +++ b/B05_Profile/B05_Profile_UI_Style.css @@ -509,7 +509,9 @@ flex-wrap: nowrap; gap: var(--spacing-16); align-items: center; - height: 24px; + /* 유토곡선 총괄값이 이 줄로 올라와(2026-09-06) 항목이 늘었다 — 두 픽셀 높여 글자가 + 위아래로 눌리지 않게 한다. */ + height: 28px; padding: 0 var(--spacing-8); overflow-x: auto; overflow-y: hidden; diff --git a/B05_Profile/B05_Profile_UI_Style_MassHaul.css b/B05_Profile/B05_Profile_UI_Style_MassHaul.css index 85c65516..02b120e3 100644 --- a/B05_Profile/B05_Profile_UI_Style_MassHaul.css +++ b/B05_Profile/B05_Profile_UI_Style_MassHaul.css @@ -70,6 +70,12 @@ top: -3px; } +/* 요약 막대는 2026-09-06 종단 상단줄로 올라갔다 — 이 자리는 안내 문구가 있을 때만 쓴다. + 비어 있으면 테두리 한 줄도 남기지 않고 접어 곡선이 그만큼 넓게 쓴다. */ +.b05-profile__masshaul-bar:empty { + display: none; +} + .b05-profile__masshaul-bar { display: flex; flex: none; @@ -95,7 +101,7 @@ 공용 범례(.b06-masshaul__legend)가 이미 absolute + right 배치라 top만 이 래퍼가 정한다. */ .b05-profile__masshaul-legend { position: absolute; - top: 34px; + top: 4px; right: 0; left: 0; z-index: 3; @@ -114,10 +120,10 @@ /* 재계산 대기 표시 — 곡선을 지우지 않고(2026-09-03 깜빡임 제거) 곡선 영역 우측 상단에 **떠 있는** 알림으로 둔다. 요약 막대에 붙이면 막대가 줄바꿈되며 곡선을 밀어냈다 - (2026-09-04 사용자 보고). 범례(top: 34px) 아래 줄에 앉혀 서로 가리지 않는다. */ + (2026-09-04 사용자 보고). 범례(top: 4px) 아래 줄에 앉혀 서로 가리지 않는다. */ .b05-profile__masshaul-pending { position: absolute; - top: 62px; + top: 32px; right: var(--spacing-8); z-index: 4; padding: 2px var(--spacing-8); @@ -167,7 +173,7 @@ z-index: 5; display: flex; flex-direction: column; - height: var(--b05-table-height, 300px); + height: var(--b05-table-height, 204px); border-top: 1px solid var(--color-border); background: var(--color-surface-raised); box-shadow: 0 -4px 12px rgb(0 0 0 / 18%); diff --git a/B05_Profile/B05_Profile_Util_Station.ts b/B05_Profile/B05_Profile_Util_Station.ts index da5ee30a..b6859a0f 100644 --- a/B05_Profile/B05_Profile_Util_Station.ts +++ b/B05_Profile/B05_Profile_Util_Station.ts @@ -52,3 +52,24 @@ export function parseStationText(text: string, intervalM: number): number | null const direct = Number(trimmed); return Number.isFinite(direct) && direct >= 0 ? direct : null; } + +/** 구조물 측점과 겹쳤다고 볼 거리(m) — 이보다 가까우면 규칙 측점을 지운다. */ +export const STATION_MERGE_TOLERANCE_M = 0.1; + +/** + * 구조물 측점과 **겹치는 규칙 측점을 지운다**(2026-09-06). + * + * 구조물은 보조말뚝을 박아 그 자리가 정본 측점이 된다. 규칙 격자(20m)와 0.1m 안에서 + * 만나면 세로선·라벨이 두 겹으로 겹쳐 읽히지 않으므로 구조물 쪽만 남긴다. + */ +export function dropStationsNear( + stations: readonly T[], + anchors: ReadonlyArray<{ chainage_m: number }>, + toleranceM: number = STATION_MERGE_TOLERANCE_M, +): T[] { + if (anchors.length === 0) return [...stations]; + return stations.filter( + (station) => + !anchors.some((anchor) => Math.abs(anchor.chainage_m - station.chainage_m) <= toleranceM), + ); +} diff --git a/B06_Section/B06_Section_Api_Fetch.ts b/B06_Section/B06_Section_Api_Fetch.ts index ab2ff622..59d21970 100644 --- a/B06_Section/B06_Section_Api_Fetch.ts +++ b/B06_Section/B06_Section_Api_Fetch.ts @@ -16,6 +16,7 @@ * 기존 호출 코드가 깨지지 않도록 여기서 그대로 다시 내보낸다. * ========================================================================== */ +import { clearState, readState, writeState } from "../A00_Common/b_page_state"; import { API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend"; import type { CrossDesign, @@ -58,10 +59,21 @@ async function requestJson(path: string, init: RequestInit): Promise { } /** 최신 확정 경로와 B04 확정값, config 기반 생성 기본값을 조회한다. */ +/** 종횡단 설정값 — ④ 계산 결과라 세션에 담아 두고 화면을 오갈 때마다 다시 묻지 않는다 + * (2026-09-06 호출 정리). 노선이 바뀌면 `clearSectionContextCache` 로 버린다. */ export async function fetchSectionContext(projectId: string): Promise { - return requestJson(`/projects/${projectId}/sections/context`, { - method: "GET", - }); + const cached = readState("section-context", projectId); + if (cached) return cached; + const fresh = await requestJson( + `/projects/${projectId}/sections/context`, + { method: "GET" }, + ); + writeState("section-context", fresh, projectId); + return fresh; +} + +export function clearSectionContextCache(projectId: string): void { + clearState("section-context", projectId); } /** 경로의 종단면 요약을 조회한다. */ diff --git a/B06_Section/B06_Section_Api_Types.ts b/B06_Section/B06_Section_Api_Types.ts index e0c0b13c..f0900921 100644 --- a/B06_Section/B06_Section_Api_Types.ts +++ b/B06_Section/B06_Section_Api_Types.ts @@ -116,6 +116,12 @@ export interface SectionStation { structure?: string; center_z: number | null; azimuth_deg: number | null; + /** 평면 곡선반경(m). 직선이거나 잴 수 없으면 null — 곡선부 확폭·법정 최소반경 판정용. */ + plan_radius_m?: number | null; + /** 곡선 바깥쪽 — 확폭이 붙는 쪽(2026-09-06 사용자 확정). 직선이면 null. */ + curve_outer_side?: "left" | "right" | null; + /** 확폭량(m) — 표값에 곡선 앞뒤 테이퍼를 얹은 값. 설계는 이 값을 우선 쓴다. */ + curve_widening_m?: number | null; center_x: number; center_y: number; /** 횡단 기준 등고가 높은 쪽(측구 설계 기본 방향). B05 solve 자동 판정 + 사용자 변경. */ @@ -399,6 +405,11 @@ export interface CrossDesign { fill_slope_ratio: number; roadbed_width_m: number; carriageway_width_m: number; + /** 규격 차도 폭(확폭 전, m) — 확폭 라벨·수량이 둘을 나눠 쓴다(2026-09-06). */ + carriageway_standard_width_m?: number; + /** 곡선부 확폭(m) — 붙은 쪽만 값이 있다. */ + widening_left_m?: number; + widening_right_m?: number; cross_slope_pct: number; ditch: | { type: "standard"; top_width_m: number; bottom_width_m: number; depth_m: number } @@ -495,4 +506,17 @@ export interface CrossSectionPatch { /** 연동 해제(측점별)·종단경사 반영(전체 공통) — 2026-08-24 사용자. */ revet_link_detached?: boolean; revet_follow_grade?: boolean; + /** 카드 버튼 선택(2026-09-06) — 예전에는 버튼을 누를 때 서버가 계산·저장했다. + * 이제 조작은 세션 초안에 쌓이고 [저장]·[확정]에서 이 patch 로만 나간다. */ + ground_type?: string; + section_mode?: string; + ditch_side?: string | null; + ditch_type?: string | null; + paved?: boolean; + two_stage_slope?: boolean; + /** 절·성토 면적(㎡) — 브라우저가 계산해 보낸다(2026-09-06 사용자 확정). */ + cut_area_m2?: number; + fill_area_m2?: number; + cut_soil_area_m2?: number; + cut_rock_area_m2?: number; } diff --git a/B06_Section/B06_Section_Cross_Design_Session.ts b/B06_Section/B06_Section_Cross_Design_Session.ts new file mode 100644 index 00000000..7b6ec3f9 --- /dev/null +++ b/B06_Section/B06_Section_Cross_Design_Session.ts @@ -0,0 +1,67 @@ +/* ============================================================================= + * B06_Section_Cross_Design_Session.ts + * 횡단 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈) 선택의 **세션 보관소**. + * + * 왜 생겼나(2026-09-06 사용자 확정) — 예전에는 버튼을 누를 때마다 + * `POST …/sections/{route}/cross-design` 이 나가 서버가 계산하고 **바로 저장**했다. + * 조작은 캐시에 쌓이고 [저장]·[확정]에서만 정본으로 나가야 한다는 규칙에 어긋난다. + * 계산은 브라우저가 하고(`common_util_cross_design.ts`), 선택값은 여기 담긴다. + * + * 담는 것은 **사용자가 고른 것만**이다 — 계산 결과(면적·설계선)는 담지 않는다. + * ========================================================================== */ + +import { readState, writeState } from "../A00_Common/b_page_state"; + +/** 카드에서 고를 수 있는 값 한 벌 — 서버 `CrossDesignRequest` 와 같은 이름을 쓴다. */ +export interface CrossDesignChoice { + ground_type: string; + section_mode: string; + ditch_side?: string | null; + ditch_type?: string | null; + paved?: boolean; + two_stage_slope?: boolean; +} + +type ChoiceMap = Record; + +/** 측점 키 — 암 경계선 저장소와 같은 규칙(0.01m 단위). */ +const keyOf = (chainageM: number): string => chainageM.toFixed(2); + +function readAll(projectId: string, routeId: number): ChoiceMap { + return readState("crossdesign", projectId, routeId) ?? {}; +} + +/** 이 측점의 선택값(없으면 null). */ +export function readCrossDesignChoice( + projectId: string, + routeId: number, + chainageM: number, +): CrossDesignChoice | null { + return readAll(projectId, routeId)[keyOf(chainageM)] ?? null; +} + +/** 선택값을 세션에 담는다. 같은 측점의 앞선 값은 덮어쓴다. */ +export function writeCrossDesignChoice( + projectId: string, + routeId: number, + chainageM: number, + choice: CrossDesignChoice, +): void { + const all = readAll(projectId, routeId); + all[keyOf(chainageM)] = choice; + writeState("crossdesign", all, projectId, routeId); +} + +/** [저장]·[확정]이 patch 로 실을 목록 — 누가거리(숫자) → 선택값. */ +export function crossDesignChoices( + projectId: string | null, + routeId: number | null, +): Map { + const choices = new Map(); + if (!projectId || routeId === null) return choices; + for (const [key, value] of Object.entries(readAll(projectId, routeId))) { + const chainage = Number(key); + if (Number.isFinite(chainage) && value) choices.set(chainage, value); + } + return choices; +} diff --git a/B06_Section/B06_Section_Cross_Refresh.ts b/B06_Section/B06_Section_Cross_Refresh.ts index 8f91e139..2bf89825 100644 --- a/B06_Section/B06_Section_Cross_Refresh.ts +++ b/B06_Section/B06_Section_Cross_Refresh.ts @@ -29,6 +29,7 @@ import type { StandardCrossSectionSpec } from "@util/common_util_cross_design"; import { previewCrossDesigns } from "./B06_Section_Api_Fetch"; import type { CrossSection, SectionDetailResponse } from "./B06_Section_Api_Fetch"; import { readRockBoundarySession } from "./B06_Section_UI_Page_Persist"; +import { crossDesignChoices } from "./B06_Section_Cross_Design_Session"; import { effectiveStandardCross, readRockBoundaryDefault, @@ -153,6 +154,10 @@ function refreshLocally(input: CrossRefreshInput): number[] | null { const rockOffsets = readRockOffsets(projectId, input.routeId); const rockDefault = readRockBoundaryDefault(projectId); + // 카드 버튼 선택은 세션 초안이 정본보다 새것이다 — 새로고침 뒤에도 고른 값이 남는다 + // (2026-09-06 사용자 확정: 조작은 캐시, 저장은 [저장]·[확정]). + const choices = crossDesignChoices(projectId, input.routeId); + const choiceAt = (chainageM: number) => choices.get(Math.round(chainageM * 100) / 100); const updated: number[] = []; for (const section of detail.cross_sections) { @@ -169,25 +174,42 @@ function refreshLocally(input: CrossRefreshInput): number[] | null { : typeof storedOffset === "number" ? storedOffset : rockDefault; + const choice = choiceAt(section.chainage_m); let next; try { next = computeCrossDesign( section.samples ?? [], planElevationAt(alignment, section.chainage_m), { - groundType: typeof design.ground_type === "string" ? design.ground_type : "ripping_rock", - sectionMode: typeof design.section_mode === "string" ? design.section_mode : "left_cut", - ditchSide: typeof design.ditch_side === "string" ? design.ditch_side : null, + groundType: + choice?.ground_type ?? + (typeof design.ground_type === "string" ? design.ground_type : "ripping_rock"), + sectionMode: + choice?.section_mode ?? + (typeof design.section_mode === "string" ? design.section_mode : "left_cut"), + ditchSide: + choice?.ditch_side ?? + (typeof design.ditch_side === "string" ? design.ditch_side : null), // 저장분은 측구가 없으면 `ditch_type: null` 이다 — 서버와 같이 기본형으로 되돌린다. - ditchType: typeof design.ditch_type === "string" ? design.ditch_type : "standard", - paved: Boolean(design.paved), + ditchType: + choice?.ditch_type ?? + (typeof design.ditch_type === "string" ? design.ditch_type : "standard"), + paved: choice?.paved ?? Boolean(design.paved), standard, rockBoundaryOffsetM, twoStageSlope: - design.two_stage_slope === undefined ? true : Boolean(design.two_stage_slope), + choice?.two_stage_slope ?? + (design.two_stage_slope === undefined ? true : Boolean(design.two_stage_slope)), ditchEnabled: typeof design.ditch_enabled === "boolean" ? design.ditch_enabled : null, // 세월교 월류 하강은 계획선 편집으로 바뀌지 않는다 — 저장분 값을 그대로 잇는다. surfaceDropM: typeof design.surface_drop_m === "number" ? design.surface_drop_m : 0, + // 곡선부 확폭 입력 — 측점 기록에 실려 온다(서버 엔진과 같은 값, 2026-09-06). + planRadiusM: section.plan_radius_m ?? null, + curveOuterSide: + section.curve_outer_side === "left" || section.curve_outer_side === "right" + ? section.curve_outer_side + : null, + curveWideningM: section.curve_widening_m ?? null, }, ); } catch { diff --git a/B06_Section/B06_Section_Engine_Culvert.py b/B06_Section/B06_Section_Engine_Culvert.py index 43c39bca..b513afd5 100644 --- a/B06_Section/B06_Section_Engine_Culvert.py +++ b/B06_Section/B06_Section_Engine_Culvert.py @@ -4,6 +4,10 @@ B05 배수유역도가 찍은 관 지점(`pipe_points.json` = 배관 정본)을 횡단면에 그림을 그릴 수 있을 만큼의 제원을 `culvert` 키로 얹는다. 값을 새로 만들지 않고 **정본 + 레지스트리 기본값**만 조합한다 — 상수 사본을 두면 B05 폼과 갈라진다. +⚠ TS 짝: `common_util/common_util_culvert_sets.ts` (2026-09-06). 한쪽만 고치면 화면과 +저장본이 갈린다 — 거울 테스트 `tmp/tests/test_b06_culvert_sets_mirror.py` 로 지킨다. +매 상세 조회마다 도는 자리라 Node 왕복 대신 짝을 골랐다(CLAUDE.md 5장 「계산 자리」 ①). + 근거(지식DB): · 관은 **지반선상 매설** — 뜨게 매설은 부적합 (교본 8장, 그림 8-3·8-9) · 관 지름 1,000㎜ 이상(현지여건 800㎜ 이상) — 별표2 Ⅰ.2.사.(2) diff --git a/B06_Section/B06_Section_Engine_Design.py b/B06_Section/B06_Section_Engine_Design.py index a9fa8a11..6dfc383a 100644 --- a/B06_Section/B06_Section_Engine_Design.py +++ b/B06_Section/B06_Section_Engine_Design.py @@ -35,13 +35,16 @@ from B06_Section.B06_Section_Engine_Areas import ( _trapezoid_areas, ) from config.config_system import ( + CURVE_WIDENING_MAX_WIDTH_M, SECTION_DITCH_SIDES, SECTION_DITCH_TYPES, SECTION_GROUND_TYPE_PRESET, SECTION_MODES, STANDARD_CROSS_SECTION, ) - +from config.config_system import ( + curve_widening_m as _curve_widening_m, +) # 사면이 원지반과 만났다고 볼 높이차(m). 이보다 크면 샘플 끝에서 잘린 것으로 본다. _SLOPE_CLOSE_TOLERANCE_M = 0.01 @@ -159,11 +162,17 @@ class _SectionGeometry: rock_boundary_offset_m: float | None = None, two_stage_slope: bool = False, ditch_enabled: bool | None = None, + widening_left_m: float = 0.0, + widening_right_m: float = 0.0, ) -> None: half_road = group["road_width_m"] / 2.0 - self.half_road = half_road # 차도 반폭(노견 제외) — 포장 범위 기준 - self.left_extent = half_road + group["shoulder_left_m"] # 좌(+) 노면 끝 - self.right_extent = half_road + group["shoulder_right_m"] # 우(-) 노면 끝 + # 곡선부 확폭은 **한쪽으로만** 붙는다(2026-09-06 사용자 확정: 곡선 바깥쪽). + # 그래서 반폭을 좌·우로 나눠 든다 — 확폭이 0이면 예전과 똑같은 대칭 단면이다. + self.half_road_left = half_road + max(widening_left_m, 0.0) + self.half_road_right = half_road + max(widening_right_m, 0.0) + self.half_road = half_road # 규격 차도 반폭(확폭 전) — 수량·표기 기준 + self.left_extent = self.half_road_left + group["shoulder_left_m"] # 좌(+) 노면 끝 + self.right_extent = self.half_road_right + group["shoulder_right_m"] # 우(-) 노면 끝 self.z_center = design_elevation_m self.cut_ratio = max(group["cut_slope_ratio"], 1e-6) # 암 구간(하단) 절토 경사 self.fill_ratio = max(group["fill_slope_ratio"], 1e-6) @@ -448,6 +457,22 @@ class _SectionGeometry: return points +def curve_widening_args(section: dict[str, Any] | None) -> dict[str, Any]: + """측점 기록에서 곡선부 확폭 입력을 뽑는다 — `compute_cross_design(**...)` 로 넘긴다. + + 측점마다 실려 오는 값이라 호출자마다 따로 꺼내 쓰면 빠뜨리기 쉽다(2026-09-06). + 옛 저장분에는 두 값이 없어 확폭 없이 예전과 같은 단면이 나온다. + """ + if not isinstance(section, dict): + return {"plan_radius_m": None, "curve_outer_side": None, "curve_widening_m": None} + return { + "plan_radius_m": section.get("plan_radius_m"), + "curve_outer_side": section.get("curve_outer_side"), + # 곡선 앞뒤 테이퍼가 얹힌 값 — 있으면 반경 표값 대신 이걸 쓴다(2026-09-06). + "curve_widening_m": section.get("curve_widening_m"), + } + + def compute_cross_design( samples: list[dict[str, Any]], design_elevation_m: float | None, @@ -462,6 +487,9 @@ def compute_cross_design( two_stage_slope: bool = True, ditch_enabled: bool | None = None, surface_drop_m: float = 0.0, + plan_radius_m: float | None = None, + curve_outer_side: str | None = None, + curve_widening_m: float | None = None, ) -> dict[str, Any]: """측점 하나의 표준횡단 설계선과 절·성토 단면적을 계산한다. @@ -472,6 +500,10 @@ def compute_cross_design( standard: B06 설정 패널 편집값(STANDARD_CROSS_SECTION 형태). 요청값 → config 순. rock_boundary_offset_m: 암반 경계선 오프셋(지반선 기준, 음수=하향). 암 지반 2단계 절토용. two_stage_slope: 암 지반에서 암반 경계 기준 2단계 경사 적용 여부(기본 True, 토글로 해제). + plan_radius_m: 이 측점의 평면 곡선반경(m). 곡선부 확폭(별표2 Ⅰ.2.나.(4))을 정하는 + 입력이며, None·45m 이상이면 확폭이 없다. + curve_outer_side: 곡선 **바깥쪽**("left"/"right"). 확폭은 그쪽으로만 붙는다 + (2026-09-06 사용자 확정). 값이 없으면 확폭을 넣지 않는다. surface_drop_m: 노면을 통째로 내리는 양(m) — 세월교 월류 높이. 구체 위 노면은 월류 높이만큼 낮게 앉으므로 계획고를 그만큼 내려 잡는다. 단면 전체가 평행 이동하므로 횡단경사·측구·사면 규칙은 그대로고 절·성토 면적만 따라 바뀐다(2026-08-30 사용자). @@ -515,6 +547,22 @@ def compute_cross_design( preset_key == "rock" and two_stage_slope and rock_boundary_offset_m is not None ) soil_cut_ratio = _resolve_group("soil", standard)["cut_slope_ratio"] + # 곡선부 확폭 — 표는 하한이고, 확폭을 더한 유효너비가 법정 상한(5m)을 넘지 않게 자른다. + # 저장된 확폭량(테이퍼 포함)이 있으면 그것을 쓰고, 없으면 반경 표값으로 되돌아간다. + if curve_outer_side in ("left", "right"): + widening = ( + float(curve_widening_m) + if isinstance(curve_widening_m, (int, float)) + else _curve_widening_m(plan_radius_m) + ) + else: + widening = 0.0 + if widening > 0.0: + room = max(CURVE_WIDENING_MAX_WIDTH_M - group["road_width_m"], 0.0) + widening = min(widening, room) + widening_left = widening if curve_outer_side == "left" else 0.0 + widening_right = widening if curve_outer_side == "right" else 0.0 + geometry = _SectionGeometry( design_elevation_m=design_elevation_m, group=group, @@ -527,6 +575,8 @@ def compute_cross_design( rock_boundary_offset_m=rock_boundary_offset_m, two_stage_slope=enable_two_stage, ditch_enabled=ditch_enabled, + widening_left_m=widening_left, + widening_right_m=widening_right, ) # 적분 오프셋 = 지반 샘플 ∪ 설계 꼭짓점(샘플 범위 안쪽만). 꼭짓점을 넣어야 @@ -617,7 +667,11 @@ def compute_cross_design( "two_stage_slope": bool(geometry.two_stage), "fill_slope_ratio": round(geometry.fill_ratio, 4), "roadbed_width_m": round(geometry.left_extent + geometry.right_extent, 4), - "carriageway_width_m": round(group["road_width_m"], 4), + "carriageway_width_m": round(geometry.half_road_left + geometry.half_road_right, 4), + # 규격 폭과 확폭을 따로 남긴다 — 횡단도 라벨·수량 산출이 둘을 나눠 쓴다. + "carriageway_standard_width_m": round(group["road_width_m"], 4), + "widening_left_m": round(geometry.half_road_left - geometry.half_road, 4), + "widening_right_m": round(geometry.half_road_right - geometry.half_road, 4), "cross_slope_pct": round(cross_slope_pct, 4), "ditch": ditch_spec, "ditch_enabled": bool(geometry.has_ditch), @@ -636,12 +690,12 @@ def compute_cross_design( # 차도(노견 제외) 양 끝점 — 포장 범위 기준(D-5). "carriageway_edges": { "left": { - "offset_m": round(geometry.half_road, 4), - "elevation_m": round(geometry.road_z(geometry.half_road), 4), + "offset_m": round(geometry.half_road_left, 4), + "elevation_m": round(geometry.road_z(geometry.half_road_left), 4), }, "right": { - "offset_m": round(-geometry.half_road, 4), - "elevation_m": round(geometry.road_z(-geometry.half_road), 4), + "offset_m": round(-geometry.half_road_right, 4), + "elevation_m": round(geometry.road_z(-geometry.half_road_right), 4), }, }, "design_elevation_m": round(float(design_elevation_m), 4), diff --git a/B06_Section/B06_Section_Router.py b/B06_Section/B06_Section_Router.py index 9c7a7a16..81bcf2cc 100644 --- a/B06_Section/B06_Section_Router.py +++ b/B06_Section/B06_Section_Router.py @@ -21,7 +21,7 @@ from B05_Profile.B05_Profile_Engine_Sections import ( ) from B05_Profile.B05_Profile_Engine_Sections_Core import SectionGenerationOptions from B06_Section.B06_Section_Engine_Culvert import attach_culvert_sets -from B06_Section.B06_Section_Engine_Design import compute_cross_design +from B06_Section.B06_Section_Engine_Design import compute_cross_design, curve_widening_args from B06_Section.B06_Section_Repository import ( count_cross_sections, create_longitudinal_section, @@ -42,8 +42,6 @@ from B06_Section.B06_Section_Router_Design import ( from B06_Section.B06_Section_Router_Design import ( attach_default_designs as _attach_default_designs, compute_default_designs as _compute_default_designs, - enforce_pavement_ranges as _enforce_pavement_ranges, - enforce_ford_surface_drops as _enforce_ford_surface_drops, stored_standard_cross_section as _stored_standard_cross_section, pavement_ranges as _pavement_ranges, paved_at as _paved_at, @@ -313,27 +311,14 @@ async def get_section_detail( if abs(float(section.get("chainage_m", 0.0)) - record["chainage_m"]) < 0.01: section["design"] = record["design"] break - # 포장 구간·물넘이 범위는 저장분이 비포장이어도 포장으로 맞춘다(2026-08-28). - # 표준횡단면은 확정 때 저장해 둔 사용자 값을 쓴다 — 없으면 config 기본값. + # 포장 구간·세월교 노면 하강 보정은 **저장 때**로 옮겼다(2026-09-06 사용자 확정: + # 「읽을 때는 영구저장소에서 가져오기만」). 조회는 저장분을 그대로 싣는다 — + # 보정은 `B06_Section_Server_Calc_Prebuild.recompute_server_side` 가 [저장]·[확정]과 + # 자동설계 체인에서 돌려 정본에 남긴다. standard = _stored_standard_cross_section(longitudinal) - await asyncio.to_thread( - _enforce_pavement_ranges, - detail["longitudinal"], - detail["cross_sections"], - project_root, - standard, - ) - # 세월교 측점은 구체 위 노면이 월류 높이만큼 낮게 앉는다 — 저장분이 옛 계획고면 - # 여기서 다시 계산한다(2026-08-30 사용자 확정). - await asyncio.to_thread( - _enforce_ford_surface_drops, - detail["longitudinal"], - detail["cross_sections"], - project_root, - standard, - ) # 지정값이 없는 측점은 기본값(토사/좌절토)으로 즉석 계산해 프리뷰로 채운다. - # (미저장 프리뷰: 실제 저장은 사용자가 카드를 조작하거나 확정할 때 이뤄진다.) + # 저장분이 있으면 **아무것도 하지 않는다**(측점마다 design 유무만 본다) — 아직 + # 저장된 적 없는 비정규 측점만 이 폴백을 탄다. await asyncio.to_thread( _attach_default_designs, detail["longitudinal"], @@ -607,7 +592,7 @@ async def compute_cross_section_design( ) stored_path = await get_project_storage_relative_path(connection, project_id) project_root = Path(resolve_stored_project_path(stored_path)) - samples, design_elevation, pavement_suggested = await asyncio.to_thread( + samples, design_elevation, pavement_suggested, cross_record = await asyncio.to_thread( _read_cross_design_inputs, project_root, str(longitudinal["longitudinal_file_path"]), @@ -626,6 +611,7 @@ async def compute_cross_section_design( two_stage_slope=request.two_stage_slope, ditch_enabled=request.ditch_enabled, surface_drop_m=ford_drop_at(request.chainage_m, ford_surface_drops(project_root)), + **curve_widening_args(cross_record), ) # B06 지정 시점은 잠정치. B07 도면 확정 시 동일 엔진으로 재계산해 confirmed로 승격한다. design["status"] = "provisional" diff --git a/B06_Section/B06_Section_Router_Confirm.py b/B06_Section/B06_Section_Router_Confirm.py index 418f1039..ea915f03 100644 --- a/B06_Section/B06_Section_Router_Confirm.py +++ b/B06_Section/B06_Section_Router_Confirm.py @@ -140,12 +140,47 @@ async def _apply_section_edits( patch["revet_link_detached"] = patch_item.revet_link_detached if patch_item.revet_follow_grade is not None: patch["revet_follow_grade"] = patch_item.revet_follow_grade + # 카드 버튼 선택 — 브라우저가 고른 값을 그대로 정본에 얹는다(2026-09-06). + for choice_key in ( + "ground_type", + "section_mode", + "ditch_side", + "ditch_type", + "paved", + "two_stage_slope", + ): + choice = getattr(patch_item, choice_key) + if choice is not None: + patch[choice_key] = choice + # 구조물 폐회로 면적 — 브라우저가 계산해 보낸 값을 그대로 정본에 얹는다. + for area_key in ("cut_area_m2", "fill_area_m2", "cut_soil_area_m2", "cut_rock_area_m2"): + value = getattr(patch_item, area_key) + if value is not None: + patch[area_key] = value if patch: await merge_cross_section_design_patch( connection, route_id=route_id, chainage_m=patch_item.chainage_m, patch=patch ) +async def _enforce_stored_designs(project_id: UUID, route_id: int) -> None: + """저장분의 포장 구간·세월교 노면 하강을 바로잡는다 — 편집분을 얹기 **전에** 돈다. + + 구조물 면적·유토곡선은 브라우저가 만들어 보낸다(2026-09-06 사용자 확정). 여기서는 + 카드를 한 번도 안 그린 측점의 보정만 서버가 챙긴다. 실패는 비치명적이다. + """ + try: + from B06_Section.B06_Section_Server_Calc_Prebuild import enforce_stored_designs + + await enforce_stored_designs(project_id, route_id) + except Exception: + logger.exception( + "저장분 설계 보정 실패 (저장은 유지): project_id=%s route_id=%s", + project_id, + route_id, + ) + + @router.post("/{project_id}/sections/{route_id}/save", response_model=SectionConfirmResponse) async def save_sections( project_id: UUID, @@ -190,6 +225,7 @@ async def save_sections( request.standard_cross_section if request else None, ) + await _enforce_stored_designs(project_id, route_id) async with pool.acquire() as connection: await connection.begin() try: @@ -263,6 +299,7 @@ async def confirm_sections( request.standard_cross_section if request else None, ) + await _enforce_stored_designs(project_id, route_id) async with pool.acquire() as connection: await connection.begin() try: diff --git a/B06_Section/B06_Section_Router_Design.py b/B06_Section/B06_Section_Router_Design.py index 9b67101e..af631349 100644 --- a/B06_Section/B06_Section_Router_Design.py +++ b/B06_Section/B06_Section_Router_Design.py @@ -9,7 +9,7 @@ from B05_Profile.B05_Profile_Engine_Sections import cross_filename from B05_Profile.B05_Profile_Structures_Repository import load_structures from B05_Profile.B05_Profile_Structures_Schema import structure_type_map from B06_Section.B06_Section_Engine_Culvert import load_culvert_sets -from B06_Section.B06_Section_Engine_Design import compute_cross_design +from B06_Section.B06_Section_Engine_Design import compute_cross_design, curve_widening_args from common_util.common_util_route_profile import design_elevation_from_longitudinal from config.config_system import STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M @@ -178,6 +178,7 @@ def enforce_pavement_ranges( two_stage_slope=bool(design.get("two_stage_slope", True)), ditch_enabled=design.get("ditch_enabled"), surface_drop_m=ford_drop_at(chainage, ford_drops), + **curve_widening_args(section), ) except (ValueError, KeyError): continue @@ -228,6 +229,7 @@ def enforce_ford_surface_drops( two_stage_slope=bool(design.get("two_stage_slope", True)), ditch_enabled=design.get("ditch_enabled"), surface_drop_m=wanted, + **curve_widening_args(section), ) except (ValueError, KeyError): continue @@ -251,7 +253,8 @@ def default_section_modes(longitudinal: dict[str, Any]) -> dict[float, str]: def read_cross_design_inputs( project_root: Path, longitudinal_file_path: str, chainage_m: float -) -> tuple[list[dict], float | None, bool]: +) -> tuple[list[dict], float | None, bool, dict[str, Any]]: + """(지반 샘플, 계획고, 포장 제안, 측점 기록) — 측점 기록은 곡선부 확폭 입력을 담고 있다.""" root = project_root.resolve() longitudinal_path = (root / longitudinal_file_path).resolve() if root not in longitudinal_path.parents: @@ -269,7 +272,7 @@ def read_cross_design_inputs( samples = cross.get("samples") if isinstance(cross, dict) else None if not isinstance(samples, list): raise ValueError("횡단 상세 파일 형식이 올바르지 않습니다.") - return samples, design_elevation, suggested + return samples, design_elevation, suggested, cross def attach_default_designs( @@ -298,6 +301,7 @@ def attach_default_designs( standard=standard, rock_boundary_offset_m=STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M, surface_drop_m=ford_drop_at(chainage, ford_drops), + **curve_widening_args(section), ) design.update(status="provisional", pavement_suggested=suggested) section["design"] = design @@ -349,6 +353,7 @@ def recompute_designs_for_alignment( two_stage_slope=bool(stored.get("two_stage_slope", True)), ditch_enabled=stored.get("ditch_enabled"), surface_drop_m=ford_drop_at(chainage, ford_drops), + **curve_widening_args(section), ) except (ValueError, KeyError): continue @@ -408,6 +413,7 @@ def compute_default_designs( standard=standard, rock_boundary_offset_m=STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M, surface_drop_m=ford_drop_at(chainage_m, ford_drops), + **curve_widening_args(cross), ) design["status"] = "provisional" design["pavement_suggested"] = suggested diff --git a/B06_Section/B06_Section_Schema.py b/B06_Section/B06_Section_Schema.py index f4d80979..9a24481b 100644 --- a/B06_Section/B06_Section_Schema.py +++ b/B06_Section/B06_Section_Schema.py @@ -153,6 +153,21 @@ class CrossSectionPatch(BaseModel): # 기슭막이 한 벌 전체 공통이라 소유 측점에만 실린다. revet_link_detached: bool | None = None revet_follow_grade: bool | None = None + # 카드 버튼 선택(2026-09-06) — 예전에는 버튼을 누를 때 서버가 계산·저장했다. + # 이제 조작은 세션 초안에 쌓이고 [저장]·[확정]에서 이 patch 로만 나간다. + ground_type: str | None = None + section_mode: str | None = None + ditch_side: str | None = None + ditch_type: str | None = None + paved: bool | None = None + two_stage_slope: bool | None = None + # 구조물이 선 측점의 폐회로 절·성토 면적(㎡) — 브라우저가 계산해 보낸다 + # (2026-09-06 사용자 확정: 「일단은 브라우저 계산으로」). 서버는 초기값을 만들 때만 + # 같은 코드를 Node 로 돌린다(`B06_Section_Server_Calc_Node.ts`). + cut_area_m2: float | None = Field(default=None, ge=0) + fill_area_m2: float | None = Field(default=None, ge=0) + cut_soil_area_m2: float | None = Field(default=None, ge=0) + cut_rock_area_m2: float | None = Field(default=None, ge=0) class SectionConfirmRequest(BaseModel): diff --git a/B06_Section/B06_Section_Section_Store.ts b/B06_Section/B06_Section_Section_Store.ts index 6464073f..f23fc504 100644 --- a/B06_Section/B06_Section_Section_Store.ts +++ b/B06_Section/B06_Section_Section_Store.ts @@ -10,11 +10,14 @@ * 다음 그리기에서 그대로 본다 — 별도 동기화 코드가 필요 없다. * * ── 수명 규칙 ───────────────────────────────────────────────────── - * 키는 `projectId:routeId`. SPA 모듈 싱글턴이라 페이지를 오가도 살아 있고, 새로고침이면 - * 사라져 영구저장소에서 다시 받는다(영구저장소가 항상 정본). 서버가 파일을 통째로 다시 + * 키는 `projectId:routeId`. SPA 모듈 싱글턴이라 페이지를 오가도 살아 있다. 새로고침이면 + * 메모리가 비므로 **세션에도 한 벌 얹어 둔다**(④ 계산 결과, 2026-09-06 캐시·세션 일원화) + * — 새로고침 뒤 첫 화면이 서버를 기다리지 않는다. 세션 용량을 넘으면 조용히 건너뛰고 + * 예전처럼 영구저장소에서 다시 받는다(영구저장소가 항상 정본). 서버가 파일을 통째로 다시 * 쓰는 조작(재생성·계획선 편집 저장·확정)은 그 응답/재조회로 `replace`·`invalidate`한다. * ========================================================================== */ +import { clearState, readState, writeState } from "../A00_Common/b_page_state"; import type { CrossSectionPatch, SectionDetailResponse } from "./B06_Section_Api_Fetch"; import { fetchSectionDetail, saveSections } from "./B06_Section_Api_Fetch"; @@ -40,10 +43,17 @@ export async function loadSectionDetail( if (cached) return cached; const inFlight = pending.get(key); if (inFlight) return inFlight; + // 새로고침으로 메모리가 빈 경우 — 세션에 얹어 둔 한 벌로 바로 선다. + const stored = readState("section-detail", projectId, routeId); + if (stored) { + cache.set(key, stored); + return stored; + } } const request = fetchSectionDetail(projectId, routeId) .then((detail) => { cache.set(key, detail); + writeState("section-detail", detail, projectId, routeId); return detail; }) .finally(() => { @@ -60,6 +70,7 @@ export function replaceSectionDetail( detail: SectionDetailResponse, ): void { cache.set(keyOf(projectId, routeId), detail); + writeState("section-detail", detail, projectId, routeId); } /** @@ -69,11 +80,14 @@ export function replaceSectionDetail( export function invalidateSectionDetail(projectId: string, routeId?: number): void { if (routeId !== undefined) { cache.delete(keyOf(projectId, routeId)); + clearState("section-detail", projectId, routeId); return; } const prefix = `${projectId}:`; for (const key of [...cache.keys()]) { - if (key.startsWith(prefix)) cache.delete(key); + if (!key.startsWith(prefix)) continue; + cache.delete(key); + clearState("section-detail", projectId, Number(key.slice(prefix.length))); } } diff --git a/B06_Section/B06_Section_Server_Calc_Node.ts b/B06_Section/B06_Section_Server_Calc_Node.ts new file mode 100644 index 00000000..177c053e --- /dev/null +++ b/B06_Section/B06_Section_Server_Calc_Node.ts @@ -0,0 +1,63 @@ +/* ============================================================================= + * B06_Section_Server_Calc_Node.ts + * 브라우저에서만 돌던 횡단 계산을 **서버가 한 번 돌리는** 진입점 — 구조물 폐회로 + * 절·성토 면적 + 그것을 쌓아 만든 유토곡선. + * + * 왜 있나(2026-09-06, CLAUDE.md 5장 「계산 자리」) — 이 두 값은 지금까지 브라우저에서만 + * 나왔다. 사용자가 B06 을 한 번도 안 열면 값이 없고, 저장·확정 뒤 서버가 다시 계산하면 + * 구조물을 모르는 표준값으로 되돌아갔다. 코리도(`B05_Profile_Corridor_Node.ts`)와 같은 + * 방식으로 **브라우저가 쓰는 코드를 서버가 그대로 실행**한다 — 계산을 두 벌로 짜지 않는다. + * + * 순서가 중요하다: 면적 보정을 **먼저** 얹고 그 위에서 유토곡선을 쌓는다. 화면도 같은 + * 순서다(카드를 그리며 면적을 고친 뒤 유토곡선을 낸다). + * + * 실행: node <번들> <입력.json> <출력.json> + * 입력 { detail: 종횡단 상세(API와 같은 꼴), context: { earthwork_conversion, + * natural_spoil_min_ground_slope, haul_equipment_limits } } + * 출력 { areas: [{ chainage_m, cut_area_m2, … }], mass_haul: {…} | null } + * — areas 는 **구조물 트림이 있는 측점만**. 나머지는 표준 계산값이 이미 맞다. + * 끝 코드: 0 성공 / 2 인자 오류 + * ========================================================================== */ + +import { readFileSync, writeFileSync } from "node:fs"; +import { computeMassHaul, massHaulPayload } from "@util/common_util_mass_haul"; +import { computeHaulPlan } from "@util/common_util_mass_haul_balance"; +import type { CrossSection, SectionDetailResponse } from "./B06_Section_Api_Fetch"; +import { applyStructureAreaRows, structureAreaRows } from "./B06_Section_Structure_Layouts"; + +interface ServerCalcInput { + detail: SectionDetailResponse; + context?: { + earthwork_conversion?: Parameters[1]; + natural_spoil_min_ground_slope?: number | null; + haul_equipment_limits?: Parameters[1]; + }; +} + +const [inputPath, outputPath] = process.argv.slice(2); +if (!inputPath || !outputPath) { + console.error("사용법: node <번들> <입력.json> <출력.json>"); + process.exit(2); +} + +const input = JSON.parse(readFileSync(inputPath, "utf8")) as ServerCalcInput; +const sections: CrossSection[] = input.detail?.cross_sections ?? []; + +const areas = structureAreaRows(sections); +// 보정값을 **자리에서** 얹는다 — 유토곡선이 고쳐진 면적 위에서 쌓이게 한다. +applyStructureAreaRows(sections, areas); + +// 유토곡선 — balloon 위치는 사용자 화면값이라 서버가 만들지 않는다(파이썬이 보존). +const conversion = input.context?.earthwork_conversion; +const result = conversion + ? computeMassHaul( + sections, + conversion, + input.context?.natural_spoil_min_ground_slope ?? undefined, + ) + : null; +const massHaul = result + ? massHaulPayload(result, computeHaulPlan(result, input.context?.haul_equipment_limits)) + : null; + +writeFileSync(outputPath, JSON.stringify({ areas, mass_haul: massHaul })); diff --git a/B06_Section/B06_Section_Server_Calc_Prebuild.py b/B06_Section/B06_Section_Server_Calc_Prebuild.py new file mode 100644 index 00000000..98af86fd --- /dev/null +++ b/B06_Section/B06_Section_Server_Calc_Prebuild.py @@ -0,0 +1,199 @@ +"""브라우저에서만 돌던 횡단 계산을 **서버가** 돌려 정본에 남긴다(2026-09-06). + +대상 둘 — + ① 구조물이 선 측점의 절·성토 면적: 기슭막이·세월교·BOX암거가 서면 성토 사면이 벽에서 + 끊겨 지반선과 설계선이 이루는 폐회로가 달라진다. + ② 그 면적을 쌓아 만드는 유토곡선. + +왜 — 사용자가 B06 을 한 번도 안 열어도 **초기값**에는 이 값이 있어야 한다. +여기(Node 실행)는 **초기값 산출 전용**이다 — 사용자가 화면을 만지는 동안과 [저장]·[확정] +때의 계산은 브라우저 몫이다(2026-09-06 사용자 확정: 「일단은 브라우저 계산으로」). + +**계산을 다시 짜지 않는다.** 화면이 쓰는 TS 를 Node 진입점(`B06_Section_Server_Calc_Node.ts`) +으로 감싸 그대로 돌린다. 파이썬으로 포팅하면 같은 기하가 두 벌이 되어 「그림은 이런데 +수량은 저렇다」가 생긴다. + +실패는 비치명적이다 — 보정 전(표준) 값이 그대로 남고 화면은 예전처럼 스스로 고친다. +""" + +from __future__ import annotations + +import asyncio +import json +import logging +from pathlib import Path +from typing import Any +from uuid import UUID + +from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path +from B06_Section.B06_Section_Repository import ( + get_longitudinal_section, + merge_cross_section_design_patch, + merge_longitudinal_section_data, + update_cross_section_design, +) +from common_util.common_util_node_bundle import run_bundle_json +from common_util.common_util_storage import resolve_stored_project_path +from config.config_db import get_db_pool +from config.config_system import ( + EARTHWORK_CONVERSION_FACTORS, + EARTHWORK_HAUL_EQUIPMENT_LIMITS_M, + NATURAL_SPOIL_MIN_GROUND_SLOPE, +) + +logger = logging.getLogger(__name__) + +ROOT = Path(__file__).resolve().parents[1] +BUNDLE = ROOT / "config" / "server_calc_node" / "B06_Section_Server_Calc_Node.js" +_NPM_SCRIPT = "build:server-calc" +# 정본에 얹는 값만 받는다 — Node 가 다른 키를 내도 설계 데이터에 흘리지 않는다. +_AREA_KEYS = ("cut_area_m2", "fill_area_m2", "cut_soil_area_m2", "cut_rock_area_m2") + + +def _mass_haul_context() -> dict[str, Any]: + """유토곡선 계산에 필요한 값 — 화면이 `sections/context`로 받는 것과 같은 상수다.""" + return { + "earthwork_conversion": EARTHWORK_CONVERSION_FACTORS, + "natural_spoil_min_ground_slope": NATURAL_SPOIL_MIN_GROUND_SLOPE, + "haul_equipment_limits": [ + {"key": key, "max_distance_m": limit} + for key, limit in EARTHWORK_HAUL_EQUIPMENT_LIMITS_M + ], + } + + +def _enforce_stored_designs( + longitudinal: dict[str, Any], + sections: list[dict[str, Any]], + project_root: Path, + standard: dict[str, Any] | None, +) -> None: + """저장분 설계를 **쓰는 시점에** 바로잡는다 — 포장 구간·세월교 노면 하강. + + 예전에는 상세를 **읽을 때마다** 돌려 화면이 볼 때만 맞았다(저장분은 낡은 채로). + 2026-09-06 사용자 확정대로 「읽기는 영구저장소에서 가져오기만」이므로 이쪽으로 옮겼다. + """ + from B06_Section.B06_Section_Router_Design import ( + enforce_ford_surface_drops, + enforce_pavement_ranges, + ) + + enforce_pavement_ranges(longitudinal, sections, project_root, standard) + enforce_ford_surface_drops(longitudinal, sections, project_root, standard) + + +async def enforce_stored_designs(project_id: UUID | str, route_id: int) -> int: + """저장분 설계의 포장 구간·세월교 노면 하강만 바로잡는다(Node 실행 없음). + + [저장]·[확정]이 부른다. 구조물 면적·유토곡선은 브라우저가 만들어 보내므로 여기서 + 다시 만들지 않는다(2026-09-06 사용자 확정). 카드를 한 번도 안 그린 측점의 포장· + 세월교 보정만 서버가 챙긴다. + """ + return await _recompute(project_id, route_id, run_node=False) + + +async def recompute_server_side(project_id: UUID | str, route_id: int) -> int: + """초기값 산출 — 위 보정에 더해 구조물 면적·유토곡선까지 Node 로 만들어 저장한다.""" + return await _recompute(project_id, route_id, run_node=True) + + +async def _recompute(project_id: UUID | str, route_id: int, *, run_node: bool) -> int: + from B06_Section.B06_Section_Router import get_section_detail + + project_uuid = UUID(str(project_id)) + response = await get_section_detail(project_uuid, route_id) + payload = getattr(response, "model_dump", None) + if payload is None: # JSONResponse = 실패 + logger.warning("서버 재계산: 종횡단 상세를 못 받음 (route_id=%s)", route_id) + return 0 + detail = payload(mode="json") + sections = detail.get("cross_sections") or [] + + pool = get_db_pool() + async with pool.acquire() as connection: + stored_path = await get_project_storage_relative_path(connection, project_uuid) + longitudinal_row = await get_longitudinal_section(connection, project_uuid, route_id) + project_root = Path(resolve_stored_project_path(stored_path)) + from B06_Section.B06_Section_Router_Design import stored_standard_cross_section + + standard = stored_standard_cross_section(longitudinal_row) + # 포장 구간·세월교 보정 — 고쳐진 설계 위에서 면적·유토곡선이 나와야 한다. + before = [json.dumps(item.get("design"), sort_keys=True, default=str) for item in sections] + await asyncio.to_thread( + _enforce_stored_designs, detail.get("longitudinal") or {}, sections, project_root, standard + ) + fixed = [ + item + for index, item in enumerate(sections) + if json.dumps(item.get("design"), sort_keys=True, default=str) != before[index] + ] + + output = ( + await asyncio.to_thread( + run_bundle_json, + BUNDLE, + _NPM_SCRIPT, + {"detail": detail, "context": _mass_haul_context()}, + ) + if run_node + else {} + ) + if not isinstance(output, dict): + output = {} + rows = output.get("areas") + mass_haul = output.get("mass_haul") + if not fixed and not rows and not mass_haul: + return 0 + + updated = 0 + async with pool.acquire() as connection: + # balloon 위치는 **사용자가 끌어 옮긴 화면값**이다 — 서버가 만들지 않으므로 + # 저장분에서 떼어 새 유토곡선에 도로 붙인다(2026-09-06). + if isinstance(mass_haul, dict): + existing = await get_longitudinal_section(connection, project_uuid, route_id) + stored = (existing or {}).get("data") or {} + offsets = (stored.get("mass_haul") or {}).get("balloon_offsets") + if offsets is not None: + mass_haul["balloon_offsets"] = offsets + + await connection.begin() + try: + for item in fixed: + await update_cross_section_design( + connection, + route_id=route_id, + chainage_m=float(item.get("chainage_m") or 0.0), + design=item["design"], + project_id=project_uuid, + ) + for row in rows if isinstance(rows, list) else []: + patch: dict[str, Any] = { + key: float(row[key]) + for key in _AREA_KEYS + if isinstance(row.get(key), (int, float)) + } + if not patch: + continue + if await merge_cross_section_design_patch( + connection, + route_id=route_id, + chainage_m=float(row["chainage_m"]), + patch=patch, + ): + updated += 1 + if isinstance(mass_haul, dict): + await merge_longitudinal_section_data( + connection, route_id=route_id, data_patch={"mass_haul": mass_haul} + ) + await connection.commit() + except Exception: + await connection.rollback() + raise + logger.info( + "서버 재계산: route_id=%s 설계 보정 %s곳, 구조물 면적 %s곳, 유토곡선 %s", + route_id, + len(fixed), + updated, + "갱신" if isinstance(mass_haul, dict) else "없음", + ) + return updated diff --git a/B06_Section/B06_Section_Structure_Layouts.ts b/B06_Section/B06_Section_Structure_Layouts.ts new file mode 100644 index 00000000..ec4b2613 --- /dev/null +++ b/B06_Section/B06_Section_Structure_Layouts.ts @@ -0,0 +1,180 @@ +/* ============================================================================= + * B06_Section_Structure_Layouts.ts + * 정본(`section.design`)만 읽어 **구조물 기하 한 벌**을 내는 자리 — 화면·조작 없이 돈다. + * + * 왜 있나(2026-09-06, CLAUDE.md 5장 「계산 자리」) — 같은 기하를 세 곳이 쓴다: + * ① B06 횡단 카드(사용자 조작 중) ② B07 도면 작도 ③ 서버 초기 계산(Node 진입점). + * ①은 조작 제어기를 물고 돌아야 하고, ②·③은 저장된 값만 보면 된다. ②가 갖고 있던 + * 「제어기 흉내내기」를 여기로 옮겨 ③이 그대로 쓴다 — 기하를 두 벌로 만들지 않는다. + * + * DOM·SVG 를 부르지 않는다. 브라우저에서도 Node 에서도 같은 결과가 나와야 한다. + * ========================================================================== */ + +import { computeStructureAreas } from "@util/common_util_cross_structure_areas"; +import type { CrossSection } from "./B06_Section_Api_Fetch"; +import { computeBoxLayout, DEFAULT_BOX_SIDE_ADJUST } from "./B06_Section_UI_Cross_Box_Geom"; +import { DEFAULT_BASIN_ADJUST, ZERO_ADJUST } from "./B06_Section_UI_Cross_Culvert_Types"; +import type { WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types"; +import { computeCardCulvert, culvertLinkFor } from "./B06_Section_UI_Cross_Culvert_Wire"; +import type { + ExtraWallControl, + InletStructureControl, + RevetOffsetControl, +} from "./B06_Section_UI_Cross_Culvert_Wire"; +import { computeFordLayout, DEFAULT_FORD_WALL_ADJUST } from "./B06_Section_UI_Cross_Ford_Geom"; +import { computeRevetmentLayout } from "./B06_Section_UI_Cross_Revetment"; + +/** 같은 측점으로 볼 누가거리 오차(m) — 정본 반올림 자릿수보다 크게 잡는다. */ +const CHAINAGE_TOLERANCE_M = 0.02; + +function storedWallAdjust(section: CrossSection, role: string): WallAdjust { + const stored = section.design?.revet_adjust?.[role]; + return stored ? { ...ZERO_ADJUST, ...(stored as Partial) } : { ...ZERO_ADJUST }; +} + +/* 정본만 읽는 조작값 — 편집하지 않으므로 되받기·토스트는 빈 동작이다. */ +const revetOffset: RevetOffsetControl = { + adjustFor: (section, role) => storedWallAdjust(section, role), + storedAdjustFor: (section, role) => + section.design?.revet_adjust?.[role] ? storedWallAdjust(section, role) : null, + selectedFor: () => null, + highlightFor: () => null, + select: () => undefined, + syncApplied: () => undefined, + update: () => undefined, + reset: () => undefined, +}; + +const extraWalls: ExtraWallControl = { + countFor: (section, side = "outlet") => section.design?.extra_wall_counts?.[side] ?? 0, + setCount: () => undefined, + equalize: () => undefined, + consumeEqualize: () => false, + syncCount: () => undefined, +}; + +const inletStructure: InletStructureControl = { + valueFor: (section) => section.design?.inlet_structure ?? "auto", + adjustFor: (section) => ({ ...DEFAULT_BASIN_ADJUST, ...(section.design?.basin_adjust ?? {}) }), + set: () => undefined, + updateAdjust: () => undefined, + resetAdjust: () => undefined, +}; + +/** 한 측점의 구조물 기하 한 벌 — 설계선 트림과 구조물 그리기가 같은 결과를 나눠 쓴다. */ +export function computeStoredLayouts(section: CrossSection, sections: readonly CrossSection[]) { + const design = section.design; + if (!design) return null; + const designZAt = (chainageM: number): number | null => { + const found = sections.find( + (item) => Math.abs(item.chainage_m - chainageM) <= CHAINAGE_TOLERANCE_M, + ); + return found?.design?.design_elevation_m ?? null; + }; + const link = section.culvert ? undefined : culvertLinkFor(section, sections, designZAt); + const culvert = computeCardCulvert( + section, + section.samples, + null, + revetOffset, + inletStructure, + extraWalls, + link, + ); + const box = computeBoxLayout(section, section.samples, { + left: { ...DEFAULT_BOX_SIDE_ADJUST, ...(design.box_adjust?.left ?? {}) }, + right: { ...DEFAULT_BOX_SIDE_ADJUST, ...(design.box_adjust?.right ?? {}) }, + }); + const ford = computeFordLayout(section, section.samples, { + inlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(design.ford_adjust?.inlet ?? {}) }, + outlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(design.ford_adjust?.outlet ?? {}) }, + }); + // 독립 기슭막이(옛 D군 경로) — 배관 세트가 붙었거나 옆에서 이어져 오면 그쪽이 그린다. + const own = + !section.culvert && !link ? computeRevetmentLayout(section, design.revet_adjust?.own) : null; + return { design, link, culvert, box, ford, own }; +} + +export type StoredLayouts = NonNullable>; + +/** 실제로 그려지는 설계선의 트림 — B06 카드와 **같은 우선순위**로 고른다. */ +export function trimOfLayouts(layouts: StoredLayouts) { + return ( + layouts.culvert?.designTrim ?? + layouts.ford?.designTrim ?? + layouts.box?.designTrim ?? + layouts.own?.designTrim + ); +} + +/** 정본에 얹는 면적 키 — 이 넷만 오간다. */ +export const STRUCTURE_AREA_KEYS = [ + "cut_area_m2", + "fill_area_m2", + "cut_soil_area_m2", + "cut_rock_area_m2", +] as const; + +/** 측점 하나의 폐회로 면적 — 구조물이 없으면 null(표준 계산값이 이미 맞다). */ +function areaRowOf( + section: CrossSection, + sections: readonly CrossSection[], +): Record | null { + const layouts = computeStoredLayouts(section, sections); + if (!layouts) return null; + const trim = trimOfLayouts(layouts); + const design = layouts.design; + if (!trim || !Array.isArray(design.design_line) || design.design_line.length < 2) return null; + const ground = section.samples + .filter((sample) => sample.valid !== false && typeof sample.elevation_m === "number") + .map((sample) => ({ offset: sample.offset_m ?? 0, elevation: sample.elevation_m as number })) + .sort((a, b) => a.offset - b.offset); + const areas = computeStructureAreas({ + designLine: design.design_line as Array<{ offset_m: number; elevation_m: number }>, + ground, + trim, + rockBoundaryOffsetM: + typeof design.rock_boundary_offset_m === "number" ? design.rock_boundary_offset_m : null, + }); + if (!areas) return null; + const round = (value: number): number => Number(value.toFixed(4)); + const row: Record = { + chainage_m: section.chainage_m, + cut_area_m2: round(areas.cutAreaM2), + fill_area_m2: round(areas.fillAreaM2), + }; + // 토사·암 분리는 원래 값이 있을 때만 덮는다 — 화면 규칙과 같다. + if (typeof design.cut_soil_area_m2 === "number") { + row.cut_soil_area_m2 = round(areas.cutSoilAreaM2); + row.cut_rock_area_m2 = round(areas.cutRockAreaM2); + } + return row; +} + +/** + * 구조물이 선 측점의 절·성토 면적 — **카드를 그리지 않은 측점까지** 전부 낸다. + * 화면 그리기(`applyStructureAreas`)와 같은 계산이며, [저장]·[확정]과 초기값 산출 + * (Node 진입점)이 이 한 벌을 함께 쓴다. + */ +export function structureAreaRows( + sections: readonly CrossSection[], +): Array> { + return sections + .map((section) => areaRowOf(section, sections)) + .filter((row): row is Record => !!row); +} + +/** 낸 면적을 측점 자료에 도로 얹는다 — 유토곡선이 고쳐진 면적 위에서 쌓이도록. */ +export function applyStructureAreaRows( + sections: readonly CrossSection[], + rows: ReadonlyArray>, +): void { + for (const row of rows) { + const design = sections.find((item) => item.chainage_m === row.chainage_m)?.design as + Record | undefined; + if (!design) continue; + for (const key of STRUCTURE_AREA_KEYS) { + if (typeof row[key] === "number") design[key] = row[key]; + } + } +} diff --git a/B06_Section/B06_Section_UI_Cross_Design.ts b/B06_Section/B06_Section_UI_Cross_Design.ts index 6e0349aa..a04a81bd 100644 --- a/B06_Section/B06_Section_UI_Cross_Design.ts +++ b/B06_Section/B06_Section_UI_Cross_Design.ts @@ -647,6 +647,19 @@ export function appendCrossDesignOverlay( tick.setAttribute("class", "b06-chart__carriageway-tick"); svg.append(tick); } + // 노폭 라벨(2026-09-06 사용자 지시) — 확폭이 걸린 측점인지 눈으로 바로 알게 한다. + // 확폭이 없으면 규격 폭만, 있으면 「4.5m (규격 3.0 + 확폭 1.5)」로 적는다. + const widened = (design.widening_left_m ?? 0) + (design.widening_right_m ?? 0); + const standardWidth = design.carriageway_standard_width_m; + const label = document.createElementNS(SVG_NS, "text"); + label.setAttribute("x", String((x(edges.left.offset_m) + x(edges.right.offset_m)) / 2)); + label.setAttribute("y", String(toDisplayY(edges.left.elevation_m) - 6)); + label.setAttribute("class", "b06-chart__carriageway-label"); + label.textContent = + widened > 0.001 && typeof standardWidth === "number" + ? `노폭 ${design.carriageway_width_m.toFixed(2)}m (규격 ${standardWidth.toFixed(2)} + 확폭 ${widened.toFixed(2)})` + : `노폭 ${design.carriageway_width_m.toFixed(2)}m`; + svg.append(label); } } diff --git a/B06_Section/B06_Section_UI_Cross_View.ts b/B06_Section/B06_Section_UI_Cross_View.ts index fe7595aa..7000aeac 100644 --- a/B06_Section/B06_Section_UI_Cross_View.ts +++ b/B06_Section/B06_Section_UI_Cross_View.ts @@ -33,6 +33,7 @@ import type { BoxControl } from "./B06_Section_UI_Cross_Box_Panel"; import { createBodyWiring } from "./B06_Section_UI_Cross_View_Bodies"; import { appendFordOverlay, computeFordLayout } from "./B06_Section_UI_Cross_Ford"; import type { FordControl } from "./B06_Section_UI_Cross_Ford_Panel"; +import { computeStructureAreas, type DesignTrim } from "@util/common_util_cross_structure_areas"; import { computeCardCulvert } from "./B06_Section_UI_Cross_Culvert_Wire"; import type { CulvertLink } from "./B06_Section_UI_Cross_Culvert_Wire"; import type { @@ -437,17 +438,16 @@ export function createCrossSectionCard( if (highlightRevet === "own") setOwnActive(true); } } - appendCrossDesignOverlay( - plotLayer, - section.design, - x, - toDisplayY, - drawSamples, + const designTrim = culvertLayout?.designTrim ?? - fordLayout?.designTrim ?? - boxLayout?.designTrim ?? - ownDesignTrim, - ); + fordLayout?.designTrim ?? + boxLayout?.designTrim ?? + ownDesignTrim; + // 구조물이 선 측점의 절·성토 면적 — **그려지는 폐회로**의 넓이로 고쳐 든다 + // (2026-09-06 사용자 확정: 구조물 자체 면적을 빼는 것이 아니다). 그림과 면적이 + // 같은 트림 값을 쓰므로 "그림은 이런데 수량은 저렇다"가 생기지 않는다. + applyStructureAreas(section, designTrim); + appendCrossDesignOverlay(plotLayer, section.design, x, toDisplayY, drawSamples, designTrim); // 암 경계선 = 지면선 복사 + 오프셋(계획선 기준 아님). if (rockBoundary && section.design.geometry_preset === "rock") { appendRockBoundaryOverlay( @@ -638,6 +638,7 @@ export function createCrossSectionCard( adjustOf, outwardOf, heightOfWall, + drawnWallKeys: () => [...culvertWallSpecs.keys()], formOfWall, appliedD: () => culvertAppliedD, pipeLengthM: () => culvertPipeLengthM, @@ -696,3 +697,37 @@ export function createCrossSectionCard( appendCardFooter(card, section, rockBoundary); return card; } + +/** + * 구조물이 만든 폐회로 면적을 측점 설계에 반영한다(2026-09-06 사용자 확정). + * + * 표준 설계선만 보는 기본 계산은 구조물이 있는지 모른다 — 기슭막이·세월교·BOX가 서면 + * 성토 사면이 벽에서 끊기고 그 바깥은 벽·성토부선이 대신 그리므로 폐회로가 달라진다. + * 트림이 없으면(구조물 없는 측점) 아무것도 하지 않는다. + * + * 조작 중 즉시 반영용이다. 정본은 [저장]·[확정] 때 서버가 같은 코드 + * (`B06_Section_Structure_Areas_Node.ts`)로 다시 계산해 얹는다(2026-09-06). + */ +function applyStructureAreas(section: CrossSection, trim: DesignTrim | undefined | null): void { + const design = section.design; + if (!trim || !design || !Array.isArray(design.design_line) || design.design_line.length < 2) { + return; + } + const ground = section.samples + .filter((sample) => sample.valid !== false && typeof sample.elevation_m === "number") + .map((sample) => ({ offset: sample.offset_m ?? 0, elevation: sample.elevation_m as number })) + .sort((a, b) => a.offset - b.offset); + const areas = computeStructureAreas({ + designLine: design.design_line as Array<{ offset_m: number; elevation_m: number }>, + ground, + trim, + rockBoundaryOffsetM: + typeof design.rock_boundary_offset_m === "number" ? design.rock_boundary_offset_m : null, + }); + if (!areas) return; + design.cut_area_m2 = Number(areas.cutAreaM2.toFixed(4)); + design.fill_area_m2 = Number(areas.fillAreaM2.toFixed(4)); + if (typeof design.cut_soil_area_m2 === "number") { + design.cut_soil_area_m2 = Number(areas.cutSoilAreaM2.toFixed(4)); + } +} diff --git a/B06_Section/B06_Section_UI_Cross_View_Structure.ts b/B06_Section/B06_Section_UI_Cross_View_Structure.ts index 3aff0cb9..d00ff419 100644 --- a/B06_Section/B06_Section_UI_Cross_View_Structure.ts +++ b/B06_Section/B06_Section_UI_Cross_View_Structure.ts @@ -59,6 +59,8 @@ export interface StructurePanelContext { /** 화면 좌(◀) 방향을 벽 기준 부호로 환산한다. */ outwardOf: (key: RevetKey) => number; heightOfWall: (key: RevetKey) => number; + /** 지금 이 카드가 그린 벽 목록 — 연동 해제 때 높이를 굳히는 데 쓴다(2026-09-06). */ + drawnWallKeys: () => RevetKey[]; formOfWall: (key: RevetKey) => string; /** 마지막 계산의 실제 적용 d(상하) — d 미지정 벽의 ▲▼ 시작값. */ appliedD: () => Map; @@ -186,7 +188,20 @@ export function structurePanelDeps(ctx: StructurePanelContext): StructurePanelDe }, linkState: () => ctx.isLinked ? { linked: ctx.revetLink?.linkedFor(ctx.section) ?? true } : null, - setLinked: (linked) => ctx.revetLink?.setLinked(ctx.section.chainage_m, linked), + setLinked: (linked) => { + // 연동을 **푸는 순간** 지금 그려진 높이를 이 측점 값으로 굳힌다(2026-09-06 사용자 + // 지시). 예전에는 위치(4축)만 갈리고 높이는 소유 측점 값을 계속 따라가, 소유 + // 측점 높이를 바꾸면 푼 측점까지 같이 움직였다. 굳혀 두면 값이 튀지 않으면서 + // 이후에는 따로 논다. 단 수·형태는 소유 측점을 그대로 따른다(2026-08-30 확정 유지). + if (!linked) { + ctx.drawnWallKeys().forEach((key) => { + if (ctx.adjustOf(key).h !== null && ctx.adjustOf(key).h !== undefined) return; + const height = ctx.heightOfWall(key); + if (height > 0) ctx.revetOffset?.update(ctx.section.chainage_m, key, { h: height }); + }); + } + ctx.revetLink?.setLinked(ctx.section.chainage_m, linked); + }, followGrade: () => ctx.revetLink?.followGradeFor(ctx.structureSpan?.ownerOf(ctx.section) ?? ctx.section) ?? true, setFollowGrade: (follow) => { diff --git a/B06_Section/B06_Section_UI_Page.ts b/B06_Section/B06_Section_UI_Page.ts index 58a27434..c1a96354 100644 --- a/B06_Section/B06_Section_UI_Page.ts +++ b/B06_Section/B06_Section_UI_Page.ts @@ -1,5 +1,7 @@ +import { writeCrossDesignChoice } from "./B06_Section_Cross_Design_Session"; import { CURRENT_PROJECT_ID_KEY, ROUTES } from "@config/config_frontend"; import { leaveForDashboard } from "../A00_Common/b_missing_data_guard"; +import { stateKey } from "../A00_Common/b_page_state"; import { navigateTo } from "../A00_Common/router"; import { createButton, createInputField, showToast } from "@ui/ui_template_elements"; import { createWorkflowLayout } from "@ui/ui_template_workflow_layout"; @@ -12,7 +14,6 @@ import { type WorkflowState, } from "../A00_Common/b_workflow_nav"; import { - computeCrossDesign, fetchSectionContext, getSections, type SectionContextResponse, @@ -24,7 +25,6 @@ import { refreshCrossDesigns } from "./B06_Section_Cross_Refresh"; import { confirmCurrentSections, createRockBoundaryStore, - rockBoundarySessionKey, saveCurrentSections, type SectionPersistContext, } from "./B06_Section_UI_Page_Persist"; @@ -199,9 +199,6 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { // 그룹 제목 행 클릭 시 접기/펼치기(N-4-1). 액션 버튼 행은 collapsible 아님. attachCollapsible(leftForm); - // 측점별 최신 요청 시퀀스 — 늦게 도착한 옛 응답을 폐기해 경합을 방지한다. - const designRequestSeq = new Map(); - /** * 측점 설계 버튼 변경 처리: (1) 선택을 즉시 로컬 반영해 해당 카드만 리프레시(버튼 즉시 반응), * (2) 서버에서 단면적을 계산·저장하고 최신 요청이면 그 카드만 다시 갱신한다. 전체 재렌더 없음. @@ -228,33 +225,19 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { sectionView.refreshCard(chainageM); } - // (2) 서버 계산 — 최신 요청만 반영. 암 경계 오프셋은 세션 우선값을 실어 2단계 무릎을 계산시킨다. - const seq = (designRequestSeq.get(chainageM) ?? 0) + 1; - designRequestSeq.set(chainageM, seq); - try { - const response = await computeCrossDesign(projectId, currentRouteId, { - chainage_m: chainageM, - ...change, - rock_boundary_offset_m: rockBoundaryControl.offsetFor(target), - standard_cross_section: standardPanel?.getValues(), - }); - if (designRequestSeq.get(chainageM) !== seq) return; - target.design = { - ...response.design, - inlet_structure: target.design?.inlet_structure, - basin_adjust: target.design?.basin_adjust, - revet_adjust: target.design?.revet_adjust, - extra_wall_counts: target.design?.extra_wall_counts, - extra_spans: target.design?.extra_spans, - revet_link_detached: target.design?.revet_link_detached, - revet_follow_grade: target.design?.revet_follow_grade, - }; - sectionView.refreshCard(chainageM); - } catch (error) { - if (designRequestSeq.get(chainageM) !== seq) return; - const detail = error instanceof Error ? ` ${error.message}` : ""; - showToast(`${L("B06_Design_Failed")}${detail}`, "error"); - } + // (2) 선택은 **세션 초안**으로 남긴다 — 화면을 오가거나 새로고침해도 남고, + // [저장]·[확정] 때 한 번에 정본으로 나간다(2026-09-06 사용자 확정: 캐시가 저절로 + // 영구저장소로 새면 안 된다). 예전에는 여기서 서버가 계산하고 바로 저장했다. + writeCrossDesignChoice(projectId, currentRouteId, chainageM, { + ground_type: change.ground_type, + section_mode: change.section_mode, + ditch_side: change.ditch_side ?? null, + ditch_type: change.ditch_type, + paved: change.paved, + two_stage_slope: change.two_stage_slope, + }); + // (3) 계산은 브라우저 안에서 — B05·B06 이 같이 쓰는 창구 하나로 돌린다. + await reconcileStaleDesigns({ force: true }); } /** 현재 design 값에서 재계산용 change를 복원한다(암 경계 오프셋 변경 시 재계산 트리거). */ @@ -294,7 +277,7 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { * 없으면 저장분(profile_alignment.edits)을 쓴다. 측점별 사용자 선택값(지반유형·단면유형· * 측구·암 경계)은 서버가 저장분에서 유지하고, 세션에만 있는 암 경계 오프셋은 함께 실어 보낸다. */ - async function reconcileStaleDesigns(): Promise { + async function reconcileStaleDesigns(options?: { force?: boolean }): Promise { if (!sectionDetail || !projectId || currentRouteId === null) return; const draft = readAlignmentDraft(currentRouteId); // 낡음 판정은 B05와 **같은 규칙** 하나뿐이다(공용 판정 — 계획고 어긋남 + @@ -304,7 +287,7 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { // 저장분끼리는 늘 일치해 「낡지 않음」으로 나오는데, B05가 세션에 남긴 편집은 그 안에 // 없어 B06이 재계산을 통째로 건너뛰었다 — 같은 시점에 B05 절토 4,774.1㎥ ↔ B06 // 4,515.0㎥ 로 갈렸다(2026-09-03 실측). 재계산은 브라우저 안에서 끝나 값싸다. - if (!draft && !hasStaleDesigns(sectionDetail)) return; + if (!options?.force && !draft && !hasStaleDesigns(sectionDetail)) return; // 진입 정합은 화면을 잠그지 않는다 — 카드가 도착하는 대로 조용히 갱신된다 // (CLAUDE.md 5장). try { @@ -391,10 +374,7 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { // 암 경계선 오프셋(측점별) 세션 저장소는 저장 흐름 모듈이 맡는다(2026-09-02 분리). const rockStore = createRockBoundaryStore({ - sessionKey: () => - projectId && currentRouteId !== null - ? rockBoundarySessionKey(projectId, currentRouteId) - : null, + sessionKey: () => stateKey("rockb", projectId, currentRouteId), detail: () => sectionDetail, refreshCard: (chainageM) => sectionView.refreshCard(chainageM), recompute: (chainageM) => recomputeIfRock(chainageM), @@ -403,8 +383,10 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { const rockBoundaryControl = rockStore.control; const stationControls = createStationControls({ - sessionKey: (kind) => - projectId && currentRouteId !== null ? `b06:${kind}:${projectId}:${currentRouteId}` : null, + // 키는 등록표(`b_page_state`)가 만든다 — 이름만 넘기면 통·범위·옛 키 이관이 따라온다. + // 형변환을 두지 않는다: 등록표에 없는 이름을 쓰면 **컴파일에서** 걸린다 + // (2026-09-06 `extraspan` 누락으로 B06 이 안 뜬 뒤 막음). + sessionKey: (kind) => stateKey(kind, projectId, currentRouteId), refreshCard: (chainageM) => sectionView.refreshCard(chainageM), detail: () => sectionDetail, crossHalfWidth, @@ -505,9 +487,7 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { /** 표시 반폭 세션 키 — 페이지를 떠났다 와도 조절값이 유지되게 한다. */ const displaySessionKey = (): string | null => - projectId && currentRouteId !== null - ? `b06:cross-display:${projectId}:${currentRouteId}` - : null; + stateKey("cross-display", projectId, currentRouteId); function persistDisplayHalfWidth(): void { const key = displaySessionKey(); @@ -526,13 +506,16 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise { } /** 세션에 남은 선택을 이어받는다(2026-09-04 — 두 화면이 한 페이지처럼). - * 진입당 한 번만 — 재렌더마다 다시 돌면 사용자가 옮긴 스크롤이 튄다. 관 목록이 - * 늦게 오는 몫은 패널 load()가 스스로 다시 세운다. */ - let pickRestored = false; + * **넘김값이 바뀌었을 때만** 적용한다 — 재렌더마다 다시 돌면 사용자가 옮긴 스크롤이 + * 튀고, 진입당 한 번으로 막으면 자료가 늦게 온 경우 영영 안 열린다(2026-09-06). */ + let appliedPick: string | null = null; function restoreStructurePick(): void { - if (pickRestored || !sectionDetail) return; - pickRestored = true; - applyStructurePick(readStructurePick(projectId), sectionDetail, { + if (!sectionDetail) return; + const handoff = readStructurePick(projectId); + const signature = handoff ? `${handoff.at}|${handoff.key ?? ""}` : null; + if (signature === null || signature === appliedPick) return; + appliedPick = signature; + applyStructurePick(handoff, sectionDetail, { focusStation: (stationId) => sectionView.focusStation(stationId), refreshCard: (chainageM) => sectionView.refreshCard(chainageM), revetSelect: (chainageM, key) => stationControls.revetOffset.select(chainageM, key), diff --git a/B06_Section/B06_Section_UI_Page_Ford_Controls.ts b/B06_Section/B06_Section_UI_Page_Ford_Controls.ts index a787fd17..9b2e21cd 100644 --- a/B06_Section/B06_Section_UI_Page_Ford_Controls.ts +++ b/B06_Section/B06_Section_UI_Page_Ford_Controls.ts @@ -8,6 +8,7 @@ * 원천이라 배수관 구간값과 같은 저장기로 되돌려 쓴다. * ========================================================================== */ +import { boxSpanM, pipeDiameterM, wingSlabExtendM } from "@util/common_util_culvert_sets"; import type { CrossDesign, CrossSection } from "./B06_Section_Api_Fetch"; import { DEFAULT_FORD_WALL_ADJUST } from "./B06_Section_UI_Cross_Ford"; import type { FordAdjust, FordWallAdjust, FordWallRole } from "./B06_Section_UI_Cross_Ford"; @@ -150,7 +151,7 @@ export function createFordControls(deps: FordControlDeps): FordControls { const spec = sectionAt(chainageM)?.ford; if (spec) { // 캐시를 먼저 고쳐 즉시 반영한다 — 저장은 늦게 묶어서 간다. - if (patch.pipe_diameter_mm) spec.diameter_m = patch.pipe_diameter_mm / 1000; + if (patch.pipe_diameter_mm) spec.diameter_m = pipeDiameterM(patch.pipe_diameter_mm); if (patch.pipe_count) spec.pipe_count = patch.pipe_count; if (patch.pipe_kind) spec.pipe_kind = patch.pipe_kind; // 월류 폭 = 구체의 도로 진행 방향 길이(`span_m`) — 백엔드 `_ford_set`과 같은 자리. @@ -168,9 +169,7 @@ export function createFordControls(deps: FordControlDeps): FordControls { if (patch.height_m !== undefined) wing.height_m = patch.height_m; if (patch.length_m !== undefined) wing.length_m = patch.length_m; if (patch.angle_deg !== undefined) wing.angle_deg = patch.angle_deg; - wing.slab_extend_m = wing.installed - ? Math.max((wing.length_m ?? 0) * Math.cos(((wing.angle_deg ?? 45) * Math.PI) / 180), 0) - : 0; + wing.slab_extend_m = wingSlabExtendM(wing.installed, wing.length_m, wing.angle_deg); } deps.queuePipeOptions(chainageM, wingOptions(role, patch)); deps.refreshCard(chainageM); @@ -346,7 +345,7 @@ export function createBoxControls(deps: FordControlDeps): { // 캐시 먼저 — 구체 길이(`span_m`)는 백엔드 `_box_set`과 같은 식으로 다시 잡는다. if (patch.body_width_m) { spec.inner_width_m = patch.body_width_m; - spec.span_m = patch.body_width_m + 2 * spec.wall_thickness_m; + spec.span_m = boxSpanM(patch.body_width_m); } if (patch.body_height_m) spec.inner_height_m = patch.body_height_m; } diff --git a/B06_Section/B06_Section_UI_Page_Persist.ts b/B06_Section/B06_Section_UI_Page_Persist.ts index 1117d351..b9476cf7 100644 --- a/B06_Section/B06_Section_UI_Page_Persist.ts +++ b/B06_Section/B06_Section_UI_Page_Persist.ts @@ -17,7 +17,14 @@ import { type SectionDetailResponse, } from "./B06_Section_Api_Fetch"; import { flushPendingStructures } from "../B05_Profile/B05_Profile_Api_Structures"; +import { flushUphillOverrides } from "../B05_Profile/B05_Profile_Api_Fetch"; import { buildCrossPatches, type CrossPatchSources } from "./B06_Section_UI_Page_Patches"; +import { + applyStructureAreaRows, + STRUCTURE_AREA_KEYS, + structureAreaRows, +} from "./B06_Section_Structure_Layouts"; +import { crossDesignChoices } from "./B06_Section_Cross_Design_Session"; import type { StandardCrossSection } from "./B06_Section_Api_Fetch"; import type { RockBoundaryControl } from "./B06_Section_UI_Section_View"; import { computeMassHaul, massHaulPayload } from "@util/common_util_mass_haul"; @@ -166,8 +173,48 @@ export function collectSectionEdits(ctx: SectionPersistContext): { massHaul: Record | undefined; } { const crossPatches = buildCrossPatches(ctx.patchSources()); - // 유토곡선은 화면 표시 내내 프론트 메모리에만 있다가 저장 시점에만 영구 저장된다. const detail = ctx.detail(); + // 구조물 폐회로 면적 — **카드를 그리지 않은 측점까지** 여기서 다 계산해 싣는다 + // (2026-09-06 사용자 확정: 「일단은 브라우저 계산으로」). 카드 그리기가 고쳐 둔 값에 + // 기대면 화면에 안 뜬 측점이 표준값으로 남는다. + const byChainage = new Map(crossPatches.map((patch) => [patch.chainage_m, patch])); + const patchFor = (chainageM: number): CrossSectionPatch => { + const existing = byChainage.get(chainageM); + if (existing) return existing; + const created: CrossSectionPatch = { chainage_m: chainageM }; + byChainage.set(chainageM, created); + crossPatches.push(created); + return created; + }; + // 카드 버튼 선택(지반유형·단면유형·측구·포장·2단 비탈) — 세션 초안이 정본으로 나가는 + // 유일한 길이다(2026-09-06 사용자 확정: 버튼을 누를 때 서버가 저장하지 않는다). + crossDesignChoices(ctx.projectId, ctx.routeId()).forEach((choice, chainage) => { + const patch = patchFor(chainage); + patch.ground_type = choice.ground_type; + patch.section_mode = choice.section_mode; + if (choice.ditch_side !== undefined) patch.ditch_side = choice.ditch_side; + if (choice.ditch_type !== undefined) patch.ditch_type = choice.ditch_type; + if (choice.paved !== undefined) patch.paved = choice.paved; + if (choice.two_stage_slope !== undefined) patch.two_stage_slope = choice.two_stage_slope; + }); + if (detail) { + // 구조물 폐회로 면적 — **카드를 그리지 않은 측점까지** 여기서 다 계산한다 + // (2026-09-06 사용자 확정: 「일단은 브라우저 계산으로」). + applyStructureAreaRows(detail.cross_sections, structureAreaRows(detail.cross_sections)); + // 면적은 **전 측점**을 싣는다 — 브라우저가 만든 값이 곧 작업본이다. 카드 버튼을 + // 바꾸면 구조물이 없는 측점의 면적도 달라지므로 구조물 측점만 보내면 수량이 어긋난다. + for (const section of detail.cross_sections) { + const design = section.design as Record | undefined; + if (!design) continue; + let patch: CrossSectionPatch | null = null; + for (const key of STRUCTURE_AREA_KEYS) { + if (typeof design[key] !== "number") continue; + patch = patch ?? patchFor(section.chainage_m); + patch[key] = design[key] as number; + } + } + } + // 유토곡선은 화면 표시 내내 프론트 메모리에만 있다가 저장 시점에만 영구 저장된다. const context = ctx.context(); const result = detail && context?.earthwork_conversion @@ -194,6 +241,11 @@ async function flushPendingEdits(ctx: SectionPersistContext, projectId: string): // 조정창 구간값은 세션에만 있다 — 정본 payload를 모으기 전에 내보낸다 // (CLAUDE.md 5장: 영구저장은 [저장]·[확정]에서만). await ctx.flushCulvertOptions(); + // B05 3D에서 바꾼 상단측(측구 방향)도 여기서 내보낸다 — 예전에는 B05 [임시저장]에만 + // 실려, B06에서 저장·확정하면 세션에만 남아 옛 방향이 정본에 그대로 있었다 + // (2026-09-06). 서버가 종단 정본과 저장된 횡단 설계를 함께 갱신하므로 아래 + // 횡단 patch 저장보다 **먼저** 나가야 사용자 수정이 위에 얹힌다. + await flushUphillOverrides(projectId).catch(() => undefined); // B05에서 만지고 넘어온 구조물 조작분도 여기서 정본에 남긴다. 실패해도 횡단 // 저장까지 막지는 않는다 — 미저장분은 세션에 남으므로 다시 시도할 수 있다 // (2026-08-29 실측: 타입이 거절되자 sections/save가 아예 나가지 않았다). diff --git a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts index 7d555281..a40eff9c 100644 --- a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts +++ b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts @@ -6,6 +6,7 @@ * 캐시(`section.culvert`·조정창 제어기)만 고친다 — 영구저장은 [저장]·[확정] 몫이다. * ========================================================================== */ +import { pipeDiameterM } from "@util/common_util_culvert_sets"; import { showToast } from "@ui/ui_template_elements"; import type { SectionDetailResponse } from "./B06_Section_Api_Fetch"; import { applyBoxFormOptions, applyFordFormOptions } from "./B06_Section_UI_Page_Ford_Controls"; @@ -63,7 +64,7 @@ export function applyPipeOptionsToCache( }; put(culvert, "pipe_kind", patch.pipe_kind); const diameterMm = num("pipe_diameter_mm"); - if (diameterMm !== undefined) culvert.diameter_m = diameterMm / 1000; + if (diameterMm !== undefined) culvert.diameter_m = pipeDiameterM(diameterMm); // 유입·유출 기슭막이 제원과 집수정 구간값 — 폼 옵션 키를 스펙 자리로 옮긴다. for (const [side, prefix] of [ [culvert.inlet, "inlet"], diff --git a/B06_Section/B06_Section_UI_Page_Structure_Pick.ts b/B06_Section/B06_Section_UI_Page_Structure_Pick.ts index 8682eac3..45f45bcb 100644 --- a/B06_Section/B06_Section_UI_Page_Structure_Pick.ts +++ b/B06_Section/B06_Section_UI_Page_Structure_Pick.ts @@ -38,8 +38,10 @@ export function applyStructurePick( targets: PickTargets, ): void { if (!handoff) return; + // 허용오차는 같은 화면의 다른 대조와 같은 0.05m 다 — 0.01m 로는 3D 가 준 누가거리가 + // 소수점 아래에서 조금만 달라도 그 측점을 못 찾고 조용히 끝났다(2026-09-05 진단). const target = detail?.cross_sections.find( - (section) => Math.abs(section.chainage_m - handoff.at) < 0.01, + (section) => Math.abs(section.chainage_m - handoff.at) < 0.05, ); if (!target) return; // 조정창은 앞칸(측 이름)만 본다 — 뒤칸은 3D 강조를 부재 하나로 좁히는 몫이다. diff --git a/B06_Section/B06_Section_UI_Section_View.ts b/B06_Section/B06_Section_UI_Section_View.ts index d07d48f6..137fde3f 100644 --- a/B06_Section/B06_Section_UI_Section_View.ts +++ b/B06_Section/B06_Section_UI_Section_View.ts @@ -13,6 +13,7 @@ * 외부(Page)에는 `createSectionView`와 `CrossDesignChange` 타입만 노출한다. * ========================================================================== */ +import { readStateRaw, writeStateRaw } from "../A00_Common/b_page_state"; import { createPanelResizer } from "@ui/ui_template_resizer"; import { createWorkflowPanelHandle } from "@ui/ui_template_overlay"; // 가로 스크롤 고정 Y축 — B05와 같은 오버레이를 쓴다(정의처: B05 MassHaul 모듈 + 그 CSS). @@ -59,12 +60,10 @@ import { import { BASE_PANEL_HEIGHT, chartHeights, - MASS_HAUL_VISIBLE_KEY, MAX_PANEL_HEIGHT_RATIO, MIN_LONG_HEIGHT, MIN_PANEL_HEIGHT, PANEL_CHROME_PX, - PANEL_COLLAPSED_KEY, PANEL_HEIGHT_KEY, readVisibleSeries, } from "./B06_Section_UI_Section_View_Panel"; @@ -186,11 +185,11 @@ export function createSectionView( panelToggle.root.classList.add("b06-section__panel-toggle"); panel.append(panelHeader, panelBody, panelToggle.root); // 접힘 상태는 세션에만 남긴다(리사이저와 같은 규칙). - if (sessionStorage.getItem(PANEL_COLLAPSED_KEY) === "true") panel.classList.add("is-collapsed"); + if (readStateRaw("section-panel-collapsed") === "true") panel.classList.add("is-collapsed"); panelToggle.setOpen(!panel.classList.contains("is-collapsed")); panelToggle.root.addEventListener("click", () => { const collapsed = panel.classList.toggle("is-collapsed"); - sessionStorage.setItem(PANEL_COLLAPSED_KEY, String(collapsed)); + writeStateRaw("section-panel-collapsed", String(collapsed)); panelToggle.setOpen(!collapsed); // 펼칠 때는 레이아웃이 잡힌 **다음 프레임**에 그린다 — 그래프 몫을 실측으로 잡기 때문에 // 같은 프레임에 그리면 접혀 있던 0 높이를 읽는다(B05 하단 패널과 같은 처리). @@ -458,7 +457,7 @@ export function createSectionView( const next = applyLegendToggle(visibleSeries, key); visibleSeries.clear(); next.forEach((entry) => visibleSeries.add(entry)); - sessionStorage.setItem(MASS_HAUL_VISIBLE_KEY, JSON.stringify([...visibleSeries])); + writeStateRaw("masshaul-visible", JSON.stringify([...visibleSeries])); drawPanel(); }; diff --git a/B06_Section/B06_Section_UI_Section_View_Panel.ts b/B06_Section/B06_Section_UI_Section_View_Panel.ts index 021a86a1..d847b227 100644 --- a/B06_Section/B06_Section_UI_Section_View_Panel.ts +++ b/B06_Section/B06_Section_UI_Section_View_Panel.ts @@ -1,8 +1,5 @@ -import { - MASS_HAUL_BALANCE_KEY, - MASS_HAUL_DEFAULT_VISIBLE, - normalizeVisibleBasis, -} from "@util/common_util_mass_haul"; +import { MASS_HAUL_DEFAULT_VISIBLE, normalizeVisibleBasis } from "@util/common_util_mass_haul"; +import { readStateRaw, stateKey } from "../A00_Common/b_page_state"; import { MASS_HAUL_HEIGHT, MASS_HAUL_MIN_HEIGHT } from "@util/common_util_mass_haul_view"; import { LONG_HEIGHT } from "./B06_Section_UI_Section_Common"; @@ -11,15 +8,17 @@ export const BASE_PANEL_HEIGHT = LONG_HEIGHT + MASS_HAUL_HEIGHT + PANEL_CHROME_P export const MIN_LONG_HEIGHT = 110; export const MIN_PANEL_HEIGHT = MIN_LONG_HEIGHT + MASS_HAUL_MIN_HEIGHT + PANEL_CHROME_PX; export const MAX_PANEL_HEIGHT_RATIO = 0.8; -export const PANEL_HEIGHT_KEY = "b06:profile-panel-height"; -export const PANEL_COLLAPSED_KEY = "b06:profile-panel-collapsed"; -export const MASS_HAUL_VISIBLE_KEY = "b06:masshaul-visible-v4"; +/* 패널 접힘·높이·유토곡선 범례는 화면 취향(①) — 키는 등록표(`b_page_state`)가 만든다. + 범례 키는 B05 와 **같은 값**이어야 한다(두 화면이 같은 그림의 두 창). */ +export const PANEL_HEIGHT_KEY = stateKey("section-panel-height") ?? ""; -const DEFAULT_VISIBLE_KEYS = [...MASS_HAUL_DEFAULT_VISIBLE, MASS_HAUL_BALANCE_KEY]; +/** 처음 열 때는 **곡선만** — 토량 분배는 범례에서 켠다(2026-09-06 사용자 지시). + * B05 `_UI_Profile_MassHaul` 과 같은 값이어야 한다(두 화면 공용 키). */ +const DEFAULT_VISIBLE_KEYS = [...MASS_HAUL_DEFAULT_VISIBLE]; export function readVisibleSeries(): Set { try { - const raw = sessionStorage.getItem(MASS_HAUL_VISIBLE_KEY); + const raw = readStateRaw("masshaul-visible"); if (!raw) return new Set(DEFAULT_VISIBLE_KEYS); const parsed: unknown = JSON.parse(raw); return Array.isArray(parsed) diff --git a/B06_Section/B06_Section_UI_Standard_Panel.ts b/B06_Section/B06_Section_UI_Standard_Panel.ts index d2154fea..9279ab3b 100644 --- a/B06_Section/B06_Section_UI_Standard_Panel.ts +++ b/B06_Section/B06_Section_UI_Standard_Panel.ts @@ -17,6 +17,13 @@ * 카드에서 이뤄진다(여기서는 값만 보관). * ========================================================================== */ +import { + clearState, + readState, + readStateRaw, + writeState, + writeStateRaw, +} from "../A00_Common/b_page_state"; import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; import { createButton, createInputField, createSelectField } from "@ui/ui_template_elements"; import { buildStandardDiagram } from "./B06_Section_UI_Standard_Diagram"; @@ -32,18 +39,6 @@ function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } -const SESSION_PREFIX = "b06:std-cross:"; -/** config 기본값 사본 — 편집값(`SESSION_PREFIX`)과 수명은 같되 용도가 다르다. */ -const DEFAULTS_PREFIX = "b06:std-cross-default:"; - -function sessionKey(projectId: string): string { - return `${SESSION_PREFIX}${projectId}`; -} - -function defaultsKey(projectId: string): string { - return `${DEFAULTS_PREFIX}${projectId}`; -} - /** * 서버가 내려 준 표준횡단 **config 기본값**을 세션에 둔다(`sections/context` 응답). * @@ -52,47 +47,28 @@ function defaultsKey(projectId: string): string { * 패널을 열지 않는 B05도 이 값으로 계산해야 두 화면 결과가 같다(2026-09-03 로컬 전환). */ export function rememberStandardDefaults(projectId: string, defaults: StandardCrossSection): void { - try { - window.sessionStorage.setItem(defaultsKey(projectId), JSON.stringify(defaults)); - } catch { - /* 세션 저장 실패는 무시 — 계산은 편집값·저장분으로 이어 간다. */ - } + writeState("std-cross-default", defaults, projectId); } /** 기억해 둔 config 기본값. 아직 컨텍스트를 못 받았으면 null. */ export function readStandardDefaults(projectId: string): StandardCrossSection | null { - try { - const raw = window.sessionStorage.getItem(defaultsKey(projectId)); - return raw ? (JSON.parse(raw) as StandardCrossSection) : null; - } catch { - return null; - } + return readState("std-cross-default", projectId); } -const ROCK_DEFAULT_PREFIX = "b06:rock-boundary-default:"; - /** * 암반 경계선 기본 오프셋(config `STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M`)을 기억한다. * 저장분에 경계 오프셋이 없는 옛 암 측점을 서버와 **같은 기본값**으로 다시 계산하려면 * 브라우저에도 이 값이 있어야 한다 — 상수 복제 대신 컨텍스트 응답을 기억하는 방식이다. */ export function rememberRockBoundaryDefault(projectId: string, offsetM: number): void { - try { - window.sessionStorage.setItem(`${ROCK_DEFAULT_PREFIX}${projectId}`, String(offsetM)); - } catch { - /* 세션 저장 실패는 무시. */ - } + writeStateRaw("rock-boundary-default", String(offsetM), projectId); } /** 기억해 둔 암반 경계 기본 오프셋(m). 없으면 null. */ export function readRockBoundaryDefault(projectId: string): number | null { - try { - const raw = window.sessionStorage.getItem(`${ROCK_DEFAULT_PREFIX}${projectId}`); - const parsed = raw === null ? Number.NaN : Number(raw); - return Number.isFinite(parsed) ? parsed : null; - } catch { - return null; - } + const raw = readStateRaw("rock-boundary-default", projectId); + const parsed = raw === null ? Number.NaN : Number(raw); + return Number.isFinite(parsed) ? parsed : null; } /** @@ -105,11 +81,7 @@ export function effectiveStandardCross(projectId: string): StandardCrossSection /** 표준횡단 세션 편집값을 버린다 — B05 [초기화]가 부른다(정의처를 여기 하나로 둔다). */ export function clearStandardCrossSession(projectId: string): void { - try { - window.sessionStorage.removeItem(sessionKey(projectId)); - } catch { - /* 세션 접근이 막혀도 초기화는 계속한다. */ - } + clearState("std-cross", projectId); } /** config 기본값을 깊은 복사해 편집용 초기 상태로 만든다. */ @@ -124,20 +96,11 @@ function cloneDefaults(defaults: StandardCrossSection): StandardCrossSection { * 패널이 없는 화면에서도 **같은 표준 단면값**을 서버로 보내야 두 화면 결과가 같다. */ export function readStandardCrossSession(projectId: string): StandardCrossSection | null { - try { - const raw = window.sessionStorage.getItem(sessionKey(projectId)); - return raw ? (JSON.parse(raw) as StandardCrossSection) : null; - } catch { - return null; - } + return readState("std-cross", projectId); } function writeSession(projectId: string, value: StandardCrossSection): void { - try { - window.sessionStorage.setItem(sessionKey(projectId), JSON.stringify(value)); - } catch { - /* 세션 저장 실패는 무시(용량 초과 등) — 값은 메모리에 유지된다. */ - } + writeState("std-cross", value, projectId); } export interface StandardPanelController { diff --git a/B06_Section/B06_Section_UI_Style_Cross_Areas.css b/B06_Section/B06_Section_UI_Style_Cross_Areas.css index a2c430b5..d6728a14 100644 --- a/B06_Section/B06_Section_UI_Style_Cross_Areas.css +++ b/B06_Section/B06_Section_UI_Style_Cross_Areas.css @@ -147,6 +147,14 @@ stroke-width: 1.2; } +/* 노폭 라벨(2026-09-06) — 차도 위 가운데. 확폭이 걸린 측점을 눈으로 가려내는 표기다. */ +.b06-chart__carriageway-label { + fill: var(--color-royal-amethyst); + font-size: 9px; + text-anchor: middle; + pointer-events: none; +} + /* 암 경계선(설계선 복사 + 오프셋): 리핑암·발파암 구간 점선 */ .b06-chart__rock-boundary { fill: none; diff --git a/B07_DesignDetail/B07_DesignDetail_Router_Support.py b/B07_DesignDetail/B07_DesignDetail_Router_Support.py index fed5bbbd..ef7bfcc3 100644 --- a/B07_DesignDetail/B07_DesignDetail_Router_Support.py +++ b/B07_DesignDetail/B07_DesignDetail_Router_Support.py @@ -9,7 +9,7 @@ import re from pathlib import Path from typing import Any -from B06_Section.B06_Section_Engine_Design import compute_cross_design +from B06_Section.B06_Section_Engine_Design import compute_cross_design, curve_widening_args from B07_DesignDetail.B07_DesignDetail_Engine_Cad import ( DRAWING_FORMAT, build_cross_drawing, @@ -345,6 +345,7 @@ def _cross_design_line( design_elevation_from_longitudinal(longitudinal, float(source.get("chainage_m", 0.0))), ground_type="soil", section_mode="left_cut", + **curve_widening_args(source), ) return design["design_line"] except (ValueError, KeyError, OSError, json.JSONDecodeError): @@ -677,6 +678,7 @@ def _recompute_confirmed_design( ground_type=designation["ground_type"], section_mode=designation["section_mode"], ditch_side=designation.get("ditch_side"), + **curve_widening_args(source), ) design["status"] = "confirmed" return design diff --git a/B07_DesignDetail/B07_DesignDetail_UI_Cad_Structures.ts b/B07_DesignDetail/B07_DesignDetail_UI_Cad_Structures.ts index fa0cef2d..6fcaff42 100644 --- a/B07_DesignDetail/B07_DesignDetail_UI_Cad_Structures.ts +++ b/B07_DesignDetail/B07_DesignDetail_UI_Cad_Structures.ts @@ -14,40 +14,19 @@ import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch"; import { loadSectionDetail } from "../B06_Section/B06_Section_Section_Store"; +import { + computeStoredLayouts as computeLayouts, + type StoredLayouts, +} from "../B06_Section/B06_Section_Structure_Layouts"; import { appendBoxOverlay } from "../B06_Section/B06_Section_UI_Cross_Box"; -import { - computeBoxLayout, - DEFAULT_BOX_SIDE_ADJUST, -} from "../B06_Section/B06_Section_UI_Cross_Box_Geom"; import { appendCulvertOverlay } from "../B06_Section/B06_Section_UI_Cross_Culvert"; -import { - DEFAULT_BASIN_ADJUST, - ZERO_ADJUST, -} from "../B06_Section/B06_Section_UI_Cross_Culvert_Types"; -import type { WallAdjust } from "../B06_Section/B06_Section_UI_Cross_Culvert_Types"; -import { - computeCardCulvert, - culvertLinkFor, -} from "../B06_Section/B06_Section_UI_Cross_Culvert_Wire"; -import type { - ExtraWallControl, - InletStructureControl, - RevetOffsetControl, -} from "../B06_Section/B06_Section_UI_Cross_Culvert_Wire"; import { appendFordOverlay } from "../B06_Section/B06_Section_UI_Cross_Ford"; -import { - computeFordLayout, - DEFAULT_FORD_WALL_ADJUST, -} from "../B06_Section/B06_Section_UI_Cross_Ford_Geom"; import { appendFordPavementOverlay } from "../B06_Section/B06_Section_UI_Cross_Ford_Pavement"; import { appendCrossDesignOverlay, appendPavementOverlay, } from "../B06_Section/B06_Section_UI_Cross_Design"; -import { - appendRevetmentOverlay, - computeRevetmentLayout, -} from "../B06_Section/B06_Section_UI_Cross_Revetment"; +import { appendRevetmentOverlay } from "../B06_Section/B06_Section_UI_Cross_Revetment"; /** 서버가 도면에 실어 보내는 측점별 실좌표(m) → 종이(mm) 변환값. */ export interface CrossPlacement { @@ -440,77 +419,7 @@ function entityBox(entity: Record): number[] | null { return xs.length ? [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)] : null; } -// --------------------------------------------------------------------------- -// 정본(design)만 읽는 조작값 — B07은 편집하지 않으므로 되받기·토스트는 빈 동작이다. -// --------------------------------------------------------------------------- -function storedWallAdjust(section: CrossSection, role: string): WallAdjust { - const stored = section.design?.revet_adjust?.[role]; - return stored ? { ...ZERO_ADJUST, ...(stored as Partial) } : { ...ZERO_ADJUST }; -} - -const revetOffset: RevetOffsetControl = { - adjustFor: (section, role) => storedWallAdjust(section, role), - storedAdjustFor: (section, role) => - section.design?.revet_adjust?.[role] ? storedWallAdjust(section, role) : null, - selectedFor: () => null, - highlightFor: () => null, - select: () => undefined, - syncApplied: () => undefined, - update: () => undefined, - reset: () => undefined, -}; - -const extraWalls: ExtraWallControl = { - countFor: (section, side = "outlet") => section.design?.extra_wall_counts?.[side] ?? 0, - setCount: () => undefined, - equalize: () => undefined, - consumeEqualize: () => false, - syncCount: () => undefined, -}; - -const inletStructure: InletStructureControl = { - valueFor: (section) => section.design?.inlet_structure ?? "auto", - adjustFor: (section) => ({ ...DEFAULT_BASIN_ADJUST, ...(section.design?.basin_adjust ?? {}) }), - set: () => undefined, - updateAdjust: () => undefined, - resetAdjust: () => undefined, -}; - -/** 한 측점의 구조물 기하 한 벌 — 설계선 트림과 구조물 그리기가 같은 결과를 나눠 쓴다. */ -function computeLayouts(section: CrossSection, sections: CrossSection[]) { - const design = section.design; - if (!design) return null; - const designZAt = (chainageM: number): number | null => { - const found = sections.find( - (item) => Math.abs(item.chainage_m - chainageM) <= CHAINAGE_TOLERANCE_M, - ); - return found?.design?.design_elevation_m ?? null; - }; - const link = section.culvert ? undefined : culvertLinkFor(section, sections, designZAt); - const culvert = computeCardCulvert( - section, - section.samples, - null, - revetOffset, - inletStructure, - extraWalls, - link, - ); - const box = computeBoxLayout(section, section.samples, { - left: { ...DEFAULT_BOX_SIDE_ADJUST, ...(design.box_adjust?.left ?? {}) }, - right: { ...DEFAULT_BOX_SIDE_ADJUST, ...(design.box_adjust?.right ?? {}) }, - }); - const ford = computeFordLayout(section, section.samples, { - inlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(design.ford_adjust?.inlet ?? {}) }, - outlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(design.ford_adjust?.outlet ?? {}) }, - }); - // 독립 기슭막이(옛 D군 경로) — 배관 세트가 붙었거나 옆에서 이어져 오면 그쪽이 그린다. - const own = - !section.culvert && !link ? computeRevetmentLayout(section, design.revet_adjust?.own) : null; - return { design, link, culvert, box, ford, own }; -} - -type Layouts = NonNullable>; +type Layouts = StoredLayouts; /** * 설계선(+포장층)을 그린다. **구조물이 깎아 낸 설계선**(designTrim)을 B06 카드와 같은 diff --git a/common_util/common_util_cross_design.ts b/common_util/common_util_cross_design.ts index 3aaeebee..5e137e28 100644 --- a/common_util/common_util_cross_design.ts +++ b/common_util/common_util_cross_design.ts @@ -25,7 +25,12 @@ import { splitCutAreas, trapezoidAreas } from "./common_util_cross_design_areas"; // 단면 기하(노면·측구·사면 설계고)는 파일이 700줄을 넘어 떼어냈다(2026-09-04). -import { SectionGeometry, type ResolvedGroup } from "./common_util_cross_design_geometry"; +import { + CURVE_WIDENING_MAX_WIDTH_M, + SectionGeometry, + curveWideningM, + type ResolvedGroup, +} from "./common_util_cross_design_geometry"; /** 지반유형 → 표준단면 프리셋 키. 짝: config `SECTION_GROUND_TYPE_PRESET`. */ const GROUND_TYPE_PRESET: Record = { @@ -77,6 +82,12 @@ export interface CrossDesignOptions { ditchEnabled?: boolean | null; /** 세월교 월류 높이만큼 노면을 통째로 내린다(m). */ surfaceDropM?: number; + /** 이 측점의 평면 곡선반경(m) — 곡선부 확폭을 정하는 입력. 직선이면 null. */ + planRadiusM?: number | null; + /** 곡선 **바깥쪽**("left"/"right") — 확폭이 붙는 쪽(2026-09-06 사용자 확정). */ + curveOuterSide?: "left" | "right" | null; + /** 저장된 확폭량(m) — 곡선 앞뒤 테이퍼가 얹힌 값. 있으면 반경 표값 대신 쓴다. */ + curveWideningM?: number | null; } export interface CrossDesignEdge { @@ -96,6 +107,11 @@ export interface CrossDesignResult { fill_slope_ratio: number; roadbed_width_m: number; carriageway_width_m: number; + /** 규격 차도 폭(확폭 전, m) — 확폭 라벨·수량이 둘을 나눠 쓴다(2026-09-06). */ + carriageway_standard_width_m?: number; + /** 곡선부 확폭(m) — 붙은 쪽만 값이 있다. */ + widening_left_m?: number; + widening_right_m?: number; cross_slope_pct: number; ditch: Record; ditch_enabled: boolean; @@ -254,8 +270,24 @@ export function computeCrossDesign( // 2단계 절토는 암 프리셋에서만, 암반 경계 오프셋이 있을 때만 켠다. const enableTwoStage = presetKey === "rock" && (options.twoStageSlope ?? true) && rockBoundaryOffsetM !== null; + // 곡선부 확폭 — 표는 하한이고, 확폭을 더한 유효너비가 법정 상한(5m)을 넘지 않게 자른다. + // 짝: 파이썬 `compute_cross_design`. 표·상한 값은 config 한 곳에서 온다. + const outerSide = options.curveOuterSide; + // 저장된 확폭량(테이퍼 포함)이 있으면 그것을 쓰고, 없으면 반경 표값으로 되돌아간다. + let widening = + outerSide === "left" || outerSide === "right" + ? typeof options.curveWideningM === "number" && Number.isFinite(options.curveWideningM) + ? options.curveWideningM + : curveWideningM(options.planRadiusM) + : 0; + if (widening > 0) { + widening = Math.min(widening, Math.max(CURVE_WIDENING_MAX_WIDTH_M - group.road_width_m, 0)); + } + const geometry = new SectionGeometry({ designElevationM: centerElevation, + wideningLeftM: outerSide === "left" ? widening : 0, + wideningRightM: outerSide === "right" ? widening : 0, group, sectionMode, ditchSide: resolvedDitchSide, @@ -355,7 +387,11 @@ export function computeCrossDesign( two_stage_slope: geometry.twoStage, fill_slope_ratio: round4(geometry.fillRatio), roadbed_width_m: round4(geometry.leftExtent + geometry.rightExtent), - carriageway_width_m: round4(group.road_width_m), + carriageway_width_m: round4(geometry.halfRoadLeft + geometry.halfRoadRight), + // 규격 폭과 확폭을 따로 남긴다 — 횡단도 라벨·수량 산출이 둘을 나눠 쓴다(짝: 파이썬). + carriageway_standard_width_m: round4(group.road_width_m), + widening_left_m: round4(geometry.halfRoadLeft - geometry.halfRoad), + widening_right_m: round4(geometry.halfRoadRight - geometry.halfRoad), cross_slope_pct: round4(crossSlopePct), ditch: ditchSpec, ditch_enabled: geometry.hasDitch, @@ -372,12 +408,12 @@ export function computeCrossDesign( }, carriageway_edges: { left: { - offset_m: round4(geometry.halfRoad), - elevation_m: round4(geometry.roadZ(geometry.halfRoad)), + offset_m: round4(geometry.halfRoadLeft), + elevation_m: round4(geometry.roadZ(geometry.halfRoadLeft)), }, right: { - offset_m: round4(-geometry.halfRoad), - elevation_m: round4(geometry.roadZ(-geometry.halfRoad)), + offset_m: round4(-geometry.halfRoadRight), + elevation_m: round4(geometry.roadZ(-geometry.halfRoadRight)), }, }, design_elevation_m: round4(centerElevation), diff --git a/common_util/common_util_cross_design_geometry.ts b/common_util/common_util_cross_design_geometry.ts index 466ead9b..1ff67234 100644 --- a/common_util/common_util_cross_design_geometry.ts +++ b/common_util/common_util_cross_design_geometry.ts @@ -35,9 +35,42 @@ export function sideRole(sectionMode: string): [string, string] { throw new Error(`지원하지 않는 단면유형입니다: ${sectionMode}`); } +/** + * 곡선부 너비 확폭표 — **짝: `config_system_design.CURVE_WIDENING_TABLE_M`** + * (별표2 Ⅰ.2.나.(4)). `[반경 하한, 반경 상한(미만), 확폭(m)]`이고 45m 이상은 확폭이 없다. + * 두 벌이 한 세트이므로 값을 고칠 때는 파이썬 쪽도 함께 고친다. + */ +const CURVE_WIDENING_TABLE_M: ReadonlyArray = [ + [10, 13, 2.25], + [13, 14, 2.0], + [14, 15, 1.75], + [15, 18, 1.5], + [18, 20, 1.25], + [20, 25, 1.0], + [25, 30, 0.75], + [30, 40, 0.5], + [40, 45, 0.25], +]; + +/** 확폭을 더한 뒤의 유효너비 상한(m) — 짝: `CURVE_WIDENING_MAX_WIDTH_M`. */ +export const CURVE_WIDENING_MAX_WIDTH_M = 5.0; + +/** 평면 곡선반경으로 확폭량(m)을 정한다. 직선·45m 이상·값 없음은 0. */ +export function curveWideningM(planRadiusM: number | null | undefined): number { + if (planRadiusM === null || planRadiusM === undefined || !Number.isFinite(planRadiusM)) return 0; + const found = CURVE_WIDENING_TABLE_M.find( + ([low, high]) => planRadiusM >= low && planRadiusM < high, + ); + return found ? found[2] : 0; +} + /** 짝: `_SectionGeometry`. 노면 → 측구 → 사면 순으로 offset 의 설계고를 계산한다. */ export class SectionGeometry { + /** 규격 차도 반폭(확폭 전) — 수량·표기 기준. */ halfRoad: number; + /** 좌(+)·우(−) 차도 반폭 — 곡선부 확폭이 **한쪽에만** 붙어 좌우가 갈린다(2026-09-06). */ + halfRoadLeft: number; + halfRoadRight: number; leftExtent: number; rightExtent: number; zCenter: number; @@ -70,12 +103,17 @@ export class SectionGeometry { rockBoundaryOffsetM: number | null; twoStageSlope: boolean; ditchEnabled: boolean | null; + /** 곡선부 확폭(m) — 붙는 쪽만 값이 있고 반대쪽은 0이다. */ + wideningLeftM?: number; + wideningRightM?: number; }) { const { group } = params; const halfRoad = group.road_width_m / 2; this.halfRoad = halfRoad; - this.leftExtent = halfRoad + group.shoulder_left_m; - this.rightExtent = halfRoad + group.shoulder_right_m; + this.halfRoadLeft = halfRoad + Math.max(params.wideningLeftM ?? 0, 0); + this.halfRoadRight = halfRoad + Math.max(params.wideningRightM ?? 0, 0); + this.leftExtent = this.halfRoadLeft + group.shoulder_left_m; + this.rightExtent = this.halfRoadRight + group.shoulder_right_m; this.zCenter = params.designElevationM; this.cutRatio = Math.max(group.cut_slope_ratio, 1e-6); this.fillRatio = Math.max(group.fill_slope_ratio, 1e-6); diff --git a/common_util/common_util_cross_structure_areas.ts b/common_util/common_util_cross_structure_areas.ts new file mode 100644 index 00000000..f3ec9fc5 --- /dev/null +++ b/common_util/common_util_cross_structure_areas.ts @@ -0,0 +1,156 @@ +/* ============================================================================= + * common_util_cross_structure_areas.ts + * 구조물이 선 자리의 **절·성토 면적** — 지반선과 「실제로 그려지는 설계선」이 이루는 + * 폐회로의 넓이다(2026-09-06 사용자 확정: 구조물 자체 면적을 빼는 것이 아니다). + * + * 왜 따로 있나 — 기본 면적 계산(`common_util_cross_design.ts`)은 지반선과 **표준 설계선**의 + * 차이만 적분한다. 그 계산은 구조물이 있는지조차 모른다. 그런데 기슭막이·세월교·BOX암거가 + * 서면 성토 사면이 벽에서 끊기고 그 바깥은 벽·성토부선이 대신 그린다 — 화면에 그려지는 + * 폐회로가 달라지므로 면적도 달라져야 한다. + * + * 여기서는 **그리는 쪽이 이미 만든 트림 값**(`designTrim`)을 그대로 받는다. 화면과 면적이 + * 같은 입력을 쓰므로 "그림은 이런데 수량은 저렇다"가 생기지 않는다. + * + * 파이썬 짝은 만들지 않는다 — 서버도 **이 파일을 그대로 실행**한다 + * (`B06_Section_Structure_Areas_Node.ts` → 번들, 2026-09-06). 전처리 체인 끝과 + * [저장]·[확정] 때 서버가 돌려 정본에 얹으므로, 브라우저를 한 번도 안 열어도 값이 선다. + * ========================================================================== */ + +import { splitCutAreas, trapezoidAreas } from "./common_util_cross_design_areas"; + +/** 트림 경계 바로 바깥에 찍는 점의 간격(m) — 벽면을 수직으로 만들기 위한 값. */ +const BOUNDARY_EPS_M = 1e-6; + +/** 그리는 쪽이 넘겨 주는 트림 — 배수관·세월교·BOX 세트가 같은 모양으로 낸다. */ +export interface DesignTrim { + minOffset: number; + maxOffset: number; + minElevation?: number; + maxElevation?: number; + /** 트림 바깥(−offset 쪽)을 대신 그리는 폴리라인 — 노견에서 벽까지의 성토부선. */ + minSlope?: { points: Array<{ offset: number; elevation: number }> }; + /** 트림 바깥(+offset 쪽) 폴리라인. */ + maxSlope?: { points: Array<{ offset: number; elevation: number }> }; +} + +export interface StructureAreaInput { + /** 표준 설계선(측점 저장분) — 트림 안쪽은 이 선을 그대로 쓴다. */ + designLine: Array<{ offset_m: number; elevation_m: number }>; + /** 지반선 샘플(유효한 것만, 오프셋 오름차순). */ + ground: Array<{ offset: number; elevation: number }>; + trim: DesignTrim; + /** 암반 경계선 오프셋(m, 절대값). 있으면 절토를 토사/암으로 나눈다. */ + rockBoundaryOffsetM?: number | null; +} + +export interface StructureAreaResult { + cutAreaM2: number; + fillAreaM2: number; + cutSoilAreaM2: number; + cutRockAreaM2: number; +} + +/** 오프셋 오름차순 폴리라인의 선형 보간기. 범위 밖은 끝값을 문다. */ +function interpolator( + points: Array<{ offset: number; elevation: number }>, +): ((offset: number) => number) | null { + if (points.length === 0) return null; + const sorted = [...points].sort((a, b) => a.offset - b.offset); + return (offset: number): number => { + if (offset <= sorted[0].offset) return sorted[0].elevation; + const last = sorted[sorted.length - 1]; + if (offset >= last.offset) return last.elevation; + for (let index = 1; index < sorted.length; index += 1) { + const right = sorted[index]; + if (offset > right.offset) continue; + const left = sorted[index - 1]; + const span = right.offset - left.offset; + const ratio = span > 1e-9 ? (offset - left.offset) / span : 0; + return left.elevation + (right.elevation - left.elevation) * ratio; + } + return last.elevation; + }; +} + +/** + * 구조물이 선 뒤의 절·성토 면적. 트림 바깥은 구조물이 그리는 폴리라인을 따르고, 그 선이 + * 없으면 트림 경계 표고에서 끊어 **지반선에 붙인다**(그 바깥은 손대지 않은 원지반이라 + * 면적이 0이 된다). + */ +export function computeStructureAreas(input: StructureAreaInput): StructureAreaResult | null { + const design = interpolator( + input.designLine.map((point) => ({ offset: point.offset_m, elevation: point.elevation_m })), + ); + const ground = interpolator(input.ground); + if (!design || !ground || input.ground.length < 2) return null; + + const { trim } = input; + const minSlope = trim.minSlope?.points?.length ? interpolator(trim.minSlope.points) : null; + const maxSlope = trim.maxSlope?.points?.length ? interpolator(trim.maxSlope.points) : null; + const minSlopeRange = trim.minSlope?.points?.length + ? [ + Math.min(...trim.minSlope.points.map((p) => p.offset)), + Math.max(...trim.minSlope.points.map((p) => p.offset)), + ] + : null; + const maxSlopeRange = trim.maxSlope?.points?.length + ? [ + Math.min(...trim.maxSlope.points.map((p) => p.offset)), + Math.max(...trim.maxSlope.points.map((p) => p.offset)), + ] + : null; + + /** 이 오프셋에서 **실제로 그려지는** 설계선 표고. 폐회로의 위쪽 경계다. */ + const drawnZ = (offset: number): number => { + if (offset < trim.minOffset) { + if (minSlope && minSlopeRange && offset >= minSlopeRange[0] && offset <= minSlopeRange[1]) { + return minSlope(offset); + } + // 구조물이 그리는 선이 닿지 않는 바깥 — 원지반 그대로(면적 0). + return ground(offset); + } + if (offset > trim.maxOffset) { + if (maxSlope && maxSlopeRange && offset >= maxSlopeRange[0] && offset <= maxSlopeRange[1]) { + return maxSlope(offset); + } + return ground(offset); + } + return design(offset); + }; + + // 적분 격자 = 지반 샘플 ∪ 설계선 꼭짓점 ∪ 트림 경계 ∪ 구조물 폴리라인 꼭짓점. + // 꺾이는 자리를 모두 넣어야 사다리꼴 적분이 모서리를 잘라먹지 않는다. + const lo = input.ground[0].offset; + const hi = input.ground[input.ground.length - 1].offset; + const grid = new Set(); + const add = (offset: number): void => { + if (offset >= lo && offset <= hi) grid.add(Math.round(offset * 1e6) / 1e6); + }; + input.ground.forEach((sample) => add(sample.offset)); + input.designLine.forEach((point) => add(point.offset_m)); + add(trim.minOffset); + add(trim.maxOffset); + // 트림 경계에서 그려지는 선은 **수직으로 끊긴다**(벽면). 경계 바로 바깥 점을 함께 넣어 + // 사다리꼴이 그 단차를 비스듬히 이어 붙이지 않게 한다 — 안 넣으면 격자 한 칸만큼 + // 없는 면적이 생긴다(실측: 벽 안쪽 6.25㎡ 가 7.5㎡ 로 잡혔다). + add(trim.minOffset - BOUNDARY_EPS_M); + add(trim.maxOffset + BOUNDARY_EPS_M); + trim.minSlope?.points.forEach((point) => add(point.offset)); + trim.maxSlope?.points.forEach((point) => add(point.offset)); + const offsets = [...grid].sort((a, b) => a - b); + if (offsets.length < 2) return null; + + const diffs = offsets.map((offset) => ground(offset) - drawnZ(offset)); + const [cutArea, fillArea] = trapezoidAreas(offsets, diffs); + const rock = input.rockBoundaryOffsetM; + const [cutSoil, cutRock] = + typeof rock === "number" && Number.isFinite(rock) + ? splitCutAreas(offsets, diffs, Math.abs(rock)) + : [cutArea, 0]; + return { + cutAreaM2: cutArea, + fillAreaM2: fillArea, + cutSoilAreaM2: cutSoil, + cutRockAreaM2: cutRock, + }; +} diff --git a/common_util/common_util_culvert_sets.ts b/common_util/common_util_culvert_sets.ts new file mode 100644 index 00000000..368d7af2 --- /dev/null +++ b/common_util/common_util_culvert_sets.ts @@ -0,0 +1,357 @@ +/* ============================================================================= + * common_util_culvert_sets.ts + * 배수관 세트(배관·기슭막이·보호공·세월교·BOX암거·물넘이포장) 제원 — **브라우저 몫**. + * + * ⚠ 파이썬 `B06_Section/B06_Section_Engine_Culvert.py` 와 **한 벌**이다(2026-09-06). + * 한쪽만 고치면 화면과 저장본이 갈린다. 거울 테스트: `tmp/tests/test_b06_culvert_sets_mirror.py` + * + * 왜 짝으로 두나(CLAUDE.md 5장 「계산 자리」) — 이 계산은 종횡단 **상세를 읽을 때마다** + * 서버에서 돈다. 매 요청 도는 자리라 Node 왕복(코리도·구조물 면적 방식)이 비싸다. + * 그래서 세 갈래 중 ①(파이썬·TS 짝 + 거울 테스트)을 골랐다. + * + * 값을 새로 만들지 않는다 — **정본(관 지점 옵션) + 레지스트리 기본값**만 조합한다. + * 상수 사본을 두면 B05 폼과 갈라지므로 기본값은 레지스트리에서만 꺼낸다. + * ========================================================================== */ + +/** 관 지점 정본 1건 — `pipe_points.json` 의 한 줄(브라우저는 API 로 같은 것을 받는다). */ +export interface CulvertPipePoint { + chainage_m: number; + facility?: string; + options?: Record | null; +} + +/** 레지스트리 타입별 옵션 기본값 — `type_id → { 옵션키: 기본값 }`. */ +export type CulvertRegistryDefaults = Record>; + +/** 세트 제원 — 파이썬이 내는 dict 와 같은 모양이라 키를 그대로 쓴다. */ +export type CulvertSetSpec = Record; + +/* ── 파이썬 짝과 같은 상수 (근거 주석은 파이썬 쪽에 있다) ───────────────── */ +const CHAINAGE_TOLERANCE_M = 0.02; +const SECTION_KEYS: Record = { + ford: "ford", + box: "box", + ford_pavement: "ford_pavement", +}; +/** 폭 절반만큼 옆 측점에도 걸치는 종류 — 물넘이포장만. */ +const SPAN_LINKED_TYPES = new Set(["ford_pavement"]); + +export const MIN_PIPE_COVER_M = 0.5; +export const APRON_LENGTH_FACTOR = 2.0; +export const APRON_THICKNESS_M = 0.45; +export const REVET_FACE_SLOPE = 0.3; +export const INLET_STRUCTURE_BASIN = "집수정"; +export const FORD_SLAB_THICKNESS_M = 0.3; +export const FORD_WALL_THICKNESS_M = 0.2; +export const FORD_DEFAULT_WIDTH_M = 10.0; +export const FORD_PAVEMENT_DEFAULT_WIDTH_M = 5.0; +export const BOX_COVER_M = 0.5; + +/** 시설 종류 — 파이썬 `common_util_drainage_pipes` 의 상수와 같은 문자열. */ +const FACILITY_PIPE = "pipe"; +const FACILITY_BOX = "box_culvert"; +const FACILITY_FORD_PAVEMENT = "ford_pavement"; +const FACILITY_FORD_BRIDGE = "ford_bridge"; +const FACILITY_REVET = "revetment"; + +/** 숫자 옵션 하나를 정리한다. 문자열 저장분(관경 "1000")도 받는다 — 파이썬 `_number`. */ +function num(value: unknown, fallback: number | null): number | null { + if (typeof value === "boolean") return fallback; + if (typeof value === "number") return Number.isFinite(value) ? value : fallback; + if (typeof value === "string") { + const parsed = Number(value.trim()); + return value.trim() !== "" && Number.isFinite(parsed) ? parsed : fallback; + } + return fallback; +} + +/** 파이썬 `round(x, n)` 자리에 쓰는 반올림. */ +function round(value: number, digits: number): number { + return Number(value.toFixed(digits)); +} + +function text(value: unknown): string | null { + return value === null || value === undefined || value === "" ? null : String(value); +} + +/** + * 유입("inlet")·유출("outlet") 한쪽의 부속 제원. + * 구조가 집수정이면 기슭막이·보호공을 만들지 않는다 — 화면은 라벨만 쓴다. + */ +function sideSpec( + options: Record, + defaults: Record, + side: string, +): CulvertSetSpec { + const structure = text(options[`${side}_type`]) ?? text(defaults[`${side}_type`]) ?? "기슭막이"; + const spec: CulvertSetSpec = { role: side, structure }; + if (structure === INLET_STRUCTURE_BASIN) { + spec.basin_length_m = num( + options.inlet_basin_length_m, + num(defaults.inlet_basin_length_m, 2.0), + ); + spec.basin_before_m = num( + options.inlet_basin_before_m, + num(defaults.inlet_basin_before_m, null), + ); + spec.basin_after_m = num(options.inlet_basin_after_m, num(defaults.inlet_basin_after_m, null)); + return spec; + } + + const height = num( + options[`${side}_revet_height_m`], + num(defaults[`${side}_revet_height_m`], null), + ); + const length = num( + options[`${side}_revet_length_m`], + num(defaults[`${side}_revet_length_m`], null), + ); + const form = text(options[`${side}_revet_form`]) ?? text(defaults[`${side}_revet_form`]); + const before = num( + options[`${side}_revet_before_m`], + num(defaults[`${side}_revet_before_m`], null), + ); + const after = num(options[`${side}_revet_after_m`], num(defaults[`${side}_revet_after_m`], null)); + spec.revet_form = form; + spec.revet_height_m = height; + spec.revet_length_m = length; + spec.revet_before_m = before; + spec.revet_after_m = after; + spec.face_slope = REVET_FACE_SLOPE; + // 보호공은 기슭막이 바닥의 세굴 방지 구조 — 낙차고(기슭막이 높이)에 종속한다. + if (height !== null && height > 0) { + spec.apron_length_m = round(height * APRON_LENGTH_FACTOR, 3); + spec.apron_thickness_m = APRON_THICKNESS_M; + } + return spec; +} + +/** 관 1개소의 세트 제원(관 + 유입·유출 기슭막이 + 보호공). */ +function culvertSet( + options: Record, + registry: CulvertRegistryDefaults, +): CulvertSetSpec { + const defaults = registry.pipe ?? {}; + const diameterMm = num(options.pipe_diameter_mm, num(defaults.pipe_diameter_mm, 1000.0)); + return { + type: "pipe", + pipe_kind: text(options.pipe_kind) ?? text(defaults.pipe_kind), + diameter_m: pipeDiameterM(diameterMm), + min_cover_m: MIN_PIPE_COVER_M, + inlet: sideSpec(options, defaults, "inlet"), + outlet: sideSpec(options, defaults, "outlet"), + }; +} + +/** + * 독립 기슭막이 한쪽 벽 제원 — 배관 벽과 **같은 옵션 키**(`{role}_revet_*`)를 쓴다. + * 역할 키가 없으면 B05 폼이 한 벌로 담던 옛 키(`length_m`…)로 폴백한다. + */ +function revetSide(values: Record, role: string): CulvertSetSpec { + const height = num(values[`${role}_revet_height_m`], num(values.height_m, null)); + const form = text(values[`${role}_revet_form`]) ?? text(values.form); + const spec: CulvertSetSpec = { + role, + structure: "기슭막이", + revet_form: form, + revet_height_m: height, + revet_length_m: num(values[`${role}_revet_length_m`], num(values.length_m, null)), + revet_before_m: num(values[`${role}_revet_before_m`], num(values.before_m, null)), + revet_after_m: num(values[`${role}_revet_after_m`], num(values.after_m, null)), + face_slope: REVET_FACE_SLOPE, + }; + if (height !== null && height > 0) { + spec.apron_length_m = round(height * APRON_LENGTH_FACTOR, 3); + spec.apron_thickness_m = APRON_THICKNESS_M; + } + return spec; +} + +/** 독립 기슭막이 1개소 — 배관 세트 모양이되 **관을 숨긴다**(hidden_pipe). */ +function revetSet(values: Record): CulvertSetSpec { + return { + type: "pipe", + hidden_pipe: true, + side: String(values.side ?? "양쪽"), + tiers: Math.trunc(num(values.tiers, 1.0) || 1), + pipe_kind: null, + diameter_m: 0.3, + min_cover_m: 0.0, + inlet: revetSide(values, "inlet"), + outlet: revetSide(values, "outlet"), + }; +} + +/** 관경(㎜) → 관 지름(m). 파이썬 `_culvert_set`·`_ford_set` 과 같은 반올림. */ +export function pipeDiameterM(diameterMm: number | null | undefined): number { + return round((num(diameterMm, 1000.0) ?? 1000.0) / 1000.0, 3); +} + +/** BOX암거 도로 진행 방향 길이 = 내공 폭 + 측벽 두 장. */ +export function boxSpanM(innerWidthM: number): number { + return innerWidthM + 2 * FORD_WALL_THICKNESS_M; +} + +/** 날개벽이 만드는 바닥판 연장량 = 길이 × cos(벌어짐각). 안 세우면 0. */ +export function wingSlabExtendM( + installed: boolean, + lengthM: number | null | undefined, + angleDeg: number | null | undefined, +): number { + if (!installed) return 0; + const extend = (lengthM ?? 0) * Math.cos(((angleDeg ?? 45) * Math.PI) / 180); + return round(Math.max(extend, 0.0), 3); +} + +/** + * 날개벽 한쪽 제원 + 그 각도가 만드는 바닥판 연장량. + * 연장량 = 길이 × cos(각도) — 각도는 관축(계류 방향) 기준 벌어짐각이다. + */ +function wingSpec( + values: Record, + defaults: Record, + side: string, +): CulvertSetSpec { + const prefix = `wing_${side}`; + const install = values[prefix] ?? defaults[prefix]; + const length = num(values[`${prefix}_length_m`], num(defaults[`${prefix}_length_m`], 0.0)); + const angle = num(values[`${prefix}_angle_deg`], num(defaults[`${prefix}_angle_deg`], 45.0)); + const height = num(values[`${prefix}_height_m`], num(defaults[`${prefix}_height_m`], 0.0)); + const installed = String(install ?? "").trim() !== "없음"; + return { + installed, + height_m: height, + length_m: length, + angle_deg: angle, + slab_extend_m: wingSlabExtendM(installed, length, angle ?? 0), + }; +} + +/** 세월교 1개소의 세트 제원(관 + 양측 측벽 + 바닥판 + 날개벽 연장). */ +function fordSet( + values: Record, + registry: CulvertRegistryDefaults, +): CulvertSetSpec { + const defaults = registry.ford_bridge ?? {}; + const diameterMm = num(values.pipe_diameter_mm, num(defaults.pipe_diameter_mm, 1000.0)); + const width = num(values.ford_width_m, num(defaults.ford_width_m, null)); + const count = num(values.pipe_count, num(defaults.pipe_count, null)); + const depth = num(values.ford_height_m, null); + return { + type: "ford", + pipe_kind: text(values.pipe_kind) ?? text(defaults.pipe_kind), + diameter_m: pipeDiameterM(diameterMm), + pipe_count: count ? Math.max(Math.trunc(count), 1) : 1, + span_m: width && width > 0 ? width : FORD_DEFAULT_WIDTH_M, + // 월류 높이 — 구체 위 노면은 이만큼 낮게 앉는다. 없으면 0 = 내리지 않는다. + overflow_depth_m: depth && depth > 0 ? depth : 0.0, + slab_thickness_m: FORD_SLAB_THICKNESS_M, + wall_thickness_m: FORD_WALL_THICKNESS_M, + min_cover_m: MIN_PIPE_COVER_M, + wing_in: wingSpec(values, defaults, "in"), + wing_out: wingSpec(values, defaults, "out"), + }; +} + +/** 물넘이포장 1개소 — 구조물이 아니라 **파인 노면**이라 형상이 다르다. */ +function fordPavementSet( + values: Record, + registry: CulvertRegistryDefaults, +): CulvertSetSpec { + const defaults = registry.ford_pavement ?? {}; + const width = num(values.ford_width_m, num(defaults.ford_width_m, null)); + const depth = num(values.ford_height_m, null); + return { + type: "ford_pavement", + span_m: width && width > 0 ? width : FORD_PAVEMENT_DEFAULT_WIDTH_M, + // 노선 중심에서 잰 깊이. 없으면 화면이 파임을 그리지 않는다(수치를 지어내지 않는다). + depth_m: depth && depth > 0 ? depth : null, + slope_pct: num(values.ford_slope_pct, null), + }; +} + +/** BOX암거 1개소의 세트 제원(구체 + 날개벽 연장). */ +function boxSet( + values: Record, + registry: CulvertRegistryDefaults, +): CulvertSetSpec { + const defaults = registry.box_culvert ?? {}; + const innerWidth = num(values.body_width_m, num(defaults.body_width_m, 2.0)); + const innerHeight = num(values.body_height_m, num(defaults.body_height_m, 2.0)); + const wall = FORD_WALL_THICKNESS_M; + const slab = FORD_SLAB_THICKNESS_M; + return { + type: "box", + inner_width_m: innerWidth || 2.0, + inner_height_m: innerHeight || 2.0, + wall_thickness_m: wall, + slab_thickness_m: slab, + top_thickness_m: slab, + cover_m: BOX_COVER_M, + span_m: boxSpanM(innerWidth || 2.0), + wing_in: wingSpec(values, defaults, "in"), + wing_out: wingSpec(values, defaults, "out"), + }; +} + +/** 관 지점 목록 → 누가거리(소수 2자리)별 세트 제원. */ +export function buildCulvertSets( + points: readonly CulvertPipePoint[], + registry: CulvertRegistryDefaults, +): Map { + const sets = new Map(); + for (const point of points) { + const chainage = num(point.chainage_m, null); + if (chainage === null) continue; + const values = (point.options ?? {}) as Record; + const facility = point.facility || FACILITY_PIPE; + let spec: CulvertSetSpec; + if (facility === FACILITY_FORD_BRIDGE) spec = fordSet(values, registry); + else if (facility === FACILITY_BOX) spec = boxSet(values, registry); + else if (facility === FACILITY_FORD_PAVEMENT) spec = fordPavementSet(values, registry); + else if (facility === FACILITY_REVET) spec = revetSet(values); + else spec = culvertSet(values, registry); + sets.set(round(chainage, 2), spec); + } + return sets; +} + +/** 측점 자료에 세트를 얹는다(파이썬 `attach_culvert_sets`). 얹은 개수를 돌려준다. */ +export function attachCulvertSets( + sections: Array>, + sets: ReadonlyMap, +): number { + if (sets.size === 0) return 0; + let attached = 0; + for (const section of sections) { + const chainage = num(section.chainage_m, null); + if (chainage === null) continue; + for (const [pipeChainage, spec] of sets) { + // 연동 대상 종류만 폭의 절반까지 옆 측점에 걸친다. + let reach = CHAINAGE_TOLERANCE_M; + if (SPAN_LINKED_TYPES.has(String(spec.type))) reach += (num(spec.span_m, 0) ?? 0) / 2; + if (Math.abs(chainage - pipeChainage) <= reach) { + section[SECTION_KEYS[String(spec.type)] ?? "culvert"] = spec; + attached += 1; + break; + } + } + } + return attached; +} + +/** 레지스트리 응답(타입 목록) → 기본값 표. 옵션 정의가 유일한 기본값 출처다. */ +export function registryDefaults( + types: ReadonlyArray<{ + type_id: string; + options: ReadonlyArray<{ key: string; default: unknown }>; + }>, +): CulvertRegistryDefaults { + const table: CulvertRegistryDefaults = {}; + for (const type of types) { + const entry: Record = {}; + for (const option of type.options) entry[option.key] = option.default; + table[type.type_id] = entry; + } + return table; +} diff --git a/common_util/common_util_mass_haul_view.ts b/common_util/common_util_mass_haul_view.ts index 4ef8c6fc..06149fb2 100644 --- a/common_util/common_util_mass_haul_view.ts +++ b/common_util/common_util_mass_haul_view.ts @@ -51,6 +51,11 @@ export interface MassHaulAxis { viewRange?: { fromM: number; toM: number }; /** 세로창 버티기·부드러운 이동 상태. 넘기면 창이 한 칸에 확 튀지 않는다(2026-09-04). */ window?: MassHaulWindowState; + /** + * 측점 세로선을 그리지 않는다. 곡선 전체를 한 화면에 눌러 담는 보기(토량 분배)에서는 + * 측점선이 촘촘해 곡선을 덮기만 하고 자리도 못 읽는다(2026-09-06 사용자 지시). + */ + hideStations?: boolean; } /** @@ -535,7 +540,7 @@ export function createMassHaulChart( // 측점선 — 종단도와 같은 자리에 서고, 눌러서 측점을 고를 수 있다(3자 선택 동기화). // 라벨은 바로 위 종단면도가 이미 달고 있어 여기서는 생략한다(중복 표기 방지). - for (const station of longitudinal.stations) { + for (const station of axis.hideStations ? [] : longitudinal.stations) { const stationX = x(station.chainage_m); const selected = station.station_id === selectedStationId; const marker = svgElement("g", { diff --git a/common_util/common_util_node_bundle.py b/common_util/common_util_node_bundle.py new file mode 100644 index 00000000..4e85515c --- /dev/null +++ b/common_util/common_util_node_bundle.py @@ -0,0 +1,103 @@ +"""브라우저용 TS 를 **서버에서 그대로 실행**하기 위한 공통 배관(2026-09-06 분리). + +CLAUDE.md 5장 「계산 자리」 — 같은 계산을 파이썬으로 다시 짜지 않고, 화면이 쓰는 TS 를 +Node 진입점으로 감싸 서버가 부른다. 코리도(`B05_Profile_Corridor_Prebuild`)가 첫 사례고 +구조물 면적(`B06_Section_Structure_Areas_Prebuild`)이 뒤따르면서, 번들 빌드·실행 배관이 +두 벌이 되어 여기로 모았다. **계산은 이 파일에 없다** — 실행 껍데기만 있다. +""" + +from __future__ import annotations + +import json +import logging +import os +import subprocess +import tempfile +from pathlib import Path +from typing import Any + +logger = logging.getLogger(__name__) + +ROOT = Path(__file__).resolve().parents[1] +# 번들이 낡았는지 재는 대상 — 기하 계통이 걸쳐 있는 폴더. +SOURCE_DIRS = ("B05_Profile", "B06_Section", "common_util") +# 번들 만들기·실행 상한(초). 실측 번들 실행 0.1초, 빌드 3초 수준이라 넉넉하다. +BUILD_TIMEOUT_S = 300 +RUN_TIMEOUT_S = 600 + + +def node_env() -> dict[str, str]: + """config/node_modules를 쓰는 프론트엔드 프로세스 환경(main.py와 같은 규약).""" + env = os.environ.copy() + node_modules = ROOT / "config" / "node_modules" + env["PATH"] = f"{node_modules / '.bin'}{os.pathsep}{env.get('PATH', '')}" + env["NODE_PATH"] = str(node_modules) + return env + + +def bundle_stale(bundle: Path) -> bool: + """번들이 없거나 TS 원본보다 오래됐으면 참. + + 번들이 낡으면 서버와 화면이 **다른 값**을 만든다 — 이 판정이 그것을 막는 유일한 + 장치다. 개발 중에는 `npm run build`를 따로 돌리지 않으므로 여기서 스스로 갱신한다. + """ + if not bundle.is_file(): + return True + built_at = bundle.stat().st_mtime + for directory in SOURCE_DIRS: + for path in (ROOT / directory).rglob("*.ts"): + if path.stat().st_mtime > built_at: + return True + return False + + +def build_bundle(npm_script: str) -> bool: + result = subprocess.run( # noqa: S602 — 고정 명령, 사용자 입력 없음 + f"npm run {npm_script}", + shell=True, + cwd=str(ROOT), + env=node_env(), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + timeout=BUILD_TIMEOUT_S, + ) + if result.returncode != 0: + logger.error("Node 번들 빌드 실패(%s):\n%s", npm_script, result.stderr) + return False + return True + + +def run_node(bundle: Path, input_path: Path, output_path: Path) -> int: + result = subprocess.run( # noqa: S603 — 고정 실행 파일, 인자는 임시 파일 경로뿐 + ["node", str(bundle), str(input_path), str(output_path)], + cwd=str(ROOT), + env=node_env(), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + timeout=RUN_TIMEOUT_S, + ) + if result.returncode != 0: + logger.warning( + "Node 실행 실패(%s, 끝 코드 %s): %s", bundle.name, result.returncode, result.stderr + ) + return result.returncode + + +def run_bundle_json(bundle: Path, npm_script: str, payload: dict[str, Any]) -> Any | None: + """입력을 JSON 으로 넘겨 실행하고 결과 JSON 을 돌려준다. 실패는 None. + + 결과가 작을 때만 쓸 것 — 코리도처럼 큰 산출물은 파일로 받아 그대로 옮겨야 한다. + """ + if bundle_stale(bundle) and not build_bundle(npm_script): + return None + with tempfile.TemporaryDirectory(prefix="node_bundle_") as workdir: + source = Path(workdir) / "input.json" + result = Path(workdir) / "output.json" + source.write_text(json.dumps(payload, default=float), encoding="utf-8") + if run_node(bundle, source, result) != 0: + return None + return json.loads(result.read_text(encoding="utf-8")) diff --git a/config/config_system_design.py b/config/config_system_design.py index 881ce871..c239ab33 100644 --- a/config/config_system_design.py +++ b/config/config_system_design.py @@ -420,6 +420,43 @@ NATURAL_SPOIL_MIN_GROUND_SLOPE = 1.0 / 1.5 # 위 5-3의 경로탐색(평면) 기준(FOREST_ROAD_MAX_GRADE 등)과는 별개의 값이므로 # 서로 혼용하지 않는다. # ───────────────────────────────────────────────────────────────────────── +# ── 곡선부 너비 확폭 (별표2 Ⅰ.2.나.(4) / Ⅰ.3.다.(4)) ───────────────────── +# 평면 곡선반경 R(m) 구간별 **확대 기준(m)**. 원문은 "다음의 기준 이상으로 확대"라 이 값이 +# 하한이다. 45m 이상은 확폭하지 않는다. 경계는 "이상 ~ 미만". +# 확폭 방향 = **곡선 바깥쪽 편측**(2026-09-06 사용자 확정 — 회전 시 차량이 밀리는 쪽). +# 법령·교본에 방향 규정이 없어 사용자가 정한 값이며, 도면 실물로 재확인할 여지가 있다. +CURVE_WIDENING_TABLE_M: tuple[tuple[float, float, float], ...] = ( + (10.0, 13.0, 2.25), + (13.0, 14.0, 2.00), + (14.0, 15.0, 1.75), + (15.0, 18.0, 1.50), + (18.0, 20.0, 1.25), + (20.0, 25.0, 1.00), + (25.0, 30.0, 0.75), + (30.0, 40.0, 0.50), + (40.0, 45.0, 0.25), +) +# 확폭을 더한 뒤의 **유효너비 상한**(m, 별표2 Ⅰ.2.다.(1) 비고 — "최대 5미터까지"). +# 넘으면 그 자리에서 자르고 화면이 경고한다. +CURVE_WIDENING_MAX_WIDTH_M = 5.0 + +# 곡선 앞뒤에서 확폭을 0 → W 로 잇는 길이(m). 별표2에는 확폭량 표만 있고 붙이는 방식이 +# 없어, 실무 관행(곡선 시·종점 앞뒤 10m 직선 테이퍼)을 따른다(2026-09-06 사용자 지시). +# 측점 간격(기본 20m)이 이보다 넓으면 화면에서는 측점 간 보간이 대신 이어 준다. +CURVE_WIDENING_TAPER_M = 10.0 + + +def curve_widening_m(plan_radius_m: float | None) -> float: + """평면 곡선반경으로 확폭량(m)을 정한다. 직선·45m 이상·값 없음은 0.""" + if plan_radius_m is None: + return 0.0 + radius = float(plan_radius_m) + for low, high, widening in CURVE_WIDENING_TABLE_M: + if low <= radius < high: + return widening + return 0.0 + + FOREST_ROAD_PROFILE_CRITERIA = { # 설계속도(km/h)별 법정 기준 "design_speed": { @@ -442,6 +479,17 @@ FOREST_ROAD_PROFILE_CRITERIA = { "min_curve_length_m": 20.0, }, }, + # 평면 최소곡선반지름(m, 별표2 Ⅰ.2.다.(1)) — 설계속도·지형별. **경로탐색 제약이 아니라 + # 위반 표시 기준**이다(2026-09-06 사용자 확정: 자동탐색은 쓰지 않고 계획노선을 직접 + # 고친다). 탐색이 쓰는 등급별 상수(FOREST_ROAD_MIN_CURVE_R_M)와 혼용하지 않는다. + "min_plan_radius_m": { + 40: {"normal": 60.0, "special": 40.0}, + 30: {"normal": 30.0, "special": 20.0}, + 20: {"normal": 15.0, "special": 12.0}, + }, + # 배향곡선(Hair Pin) 중심선 반지름 하한(m, 별표2 Ⅰ.2.다.(2)). 이보다 급하면 **경고만** + # 낸다 — 자동 보정·차단은 하지 않는다(2026-09-06 사용자 확정). + "hairpin_min_radius_m": 10.0, # 임도 종류 → **기본** 설계속도(km/h). 임도는 속도를 낼 수 없는 노선이라 20이 # 기본이다(2026-08-19 사용자 확정). 별표2상 간선·산불진화는 20~40 범위에서 # 설계자가 고르고, 작업임도는 20 이하이므로 20 고정이다. 사용자가 화면에서 고른 diff --git a/package.json b/package.json index a5e66137..7e20859b 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "type": "module", "scripts": { "dev": "node ./config/node_modules/vite/bin/vite.js --configLoader runner", - "build": "node ./config/node_modules/typescript/bin/tsc --noEmit && node ./config/node_modules/vite/bin/vite.js build --configLoader runner && npm run build:corridor && npm run build:b07-cad", + "build": "node ./config/node_modules/typescript/bin/tsc --noEmit && node ./config/node_modules/vite/bin/vite.js build --configLoader runner && npm run build:corridor && npm run build:server-calc && npm run build:b07-cad", "build:corridor": "node ./config/node_modules/vite/bin/vite.js build --configLoader runner --ssr ../B05_Profile/B05_Profile_Corridor_Node.ts --outDir ../config/corridor_node", + "build:server-calc": "node ./config/node_modules/vite/bin/vite.js build --configLoader runner --ssr ../B06_Section/B06_Section_Server_Calc_Node.ts --outDir ../config/server_calc_node", "install:b07-cad": "npm --prefix B07_DesignDetail/openwebcad install", "build:b07-cad": "npm run install:b07-cad && npm --prefix B07_DesignDetail/openwebcad run build", "preview": "node ./config/node_modules/vite/bin/vite.js preview --configLoader runner", diff --git a/resources/knowledge/04_참조_법령기준_목록.md b/resources/knowledge/04_참조_법령기준_목록.md index d80036ca..6ec93081 100644 --- a/resources/knowledge/04_참조_법령기준_목록.md +++ b/resources/knowledge/04_참조_법령기준_목록.md @@ -331,6 +331,7 @@ - [임도기술교본 (2019)](original/임도기술교본/) — 임도 설계·시공 해설. §1~§4 등록표의 인용 출처 스캔 기반 - [사방기술교본 (2023)](original/사방기술교본/) — 사방 설계 해설 (md 47건) +- [산림과임업기술(임도) 발췌본]() — 인쇄면 371~546쪽. 발행정보 미확인·폐지 법령 수록 과거 자료로, 비교·연혁 확인에만 사용 ## 9. 포맷·실무 검증자료 (현행 기준 아님) diff --git a/resources/knowledge/README.md b/resources/knowledge/README.md index 60240e75..983344e7 100644 --- a/resources/knowledge/README.md +++ b/resources/knowledge/README.md @@ -30,6 +30,7 @@ ├─ _품질점검_보고서.md QC 이력·잔여 ├─ _이미지 목록(표 변환 검토용).md pic/ 이미지 164개 (표 변환 판단 체크리스트) ├─ 임도기술교본/ 2020년 발간 확정본. 갱신하지 않는다 + ├─ 산림과임업기술(임도)/ 출처 미상 과거 기술자료 발췌본. 비교·연혁 확인용 ├─ 사방기술교본/ 2023년 개정판. 원문 PDF + 한글교정 PDF + 장별 md 47건 + 그림 328건 │ └─ 원문/ 원본·한글교정 PDF, 글리프매핑 json, 작업가이드 — 갱신하지 않는다 ├─ 법률/ 행정규칙/ 표준시방서/ 명칭별 폴더 (사방사업법 3법·사방 고시 3건 포함) diff --git a/resources/knowledge/original/_pipeline/data/qc_report.json b/resources/knowledge/original/_pipeline/data/qc_report.json index 054c2a2d..70450d8b 100644 --- a/resources/knowledge/original/_pipeline/data/qc_report.json +++ b/resources/knowledge/original/_pipeline/data/qc_report.json @@ -1,4 +1,76 @@ [ + { + "file": "법률/사방사업법 시행령/별표/별표1_사방사업 타당성평가의 기준·방법·대상사업 등(제4조의2 관련).md", + "issues": { + "띄어쓰기": 0.566 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표10_기초번호판의 세부규격(제12조제2항 관련).md", + "issues": { + "띄어쓰기": 0.176 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표13_건물번호판의 구성(제17조제2항 관련).md", + "issues": { + "띄어쓰기": 0.671 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표14_건물번호판의 세부규격(제17조제2항 관련).md", + "issues": { + "띄어쓰기": 0.266 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표16_국가지점번호판의 표시사항 및 세부규격(제24조제1항 관련).md", + "issues": { + "띄어쓰기": 0.209 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표18_사물주소판의 구성(제26조제3항 관련).md", + "issues": { + "띄어쓰기": 0.577 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표1_도로명판의 크기(제4조제2항 관련).md", + "issues": { + "띄어쓰기": 0.415 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표22_내부도로 도로명판의 구성(제31조제1항제1호가목 관련).md", + "issues": { + "띄어쓰기": 0.476 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표24_내부도로 기초번호판의 구성(제31조제1항제1호나목 관련).md", + "issues": { + "띄어쓰기": 0.608 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표28_내부도로 사물주소판의 구성(제31조제1항제1호라목 관련).md", + "issues": { + "띄어쓰기": 0.634 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표2_도로명판의 구성(제5조제2항 관련).md", + "issues": { + "띄어쓰기": 0.743 + } + }, + { + "file": "법률/주소정보시설규칙/별표/별표3_도로명판의 세부규격(제5조제2항 관련).md", + "issues": { + "띄어쓰기": 0.273 + } + }, { "file": "행정규칙/임도 품셈 적용기준 (현 산림사업 표준품셈)/별표/별표0_산림사업 표준품셈.md", "issues": { diff --git a/resources/knowledge/original/_pipeline/pdf2md.py b/resources/knowledge/original/_pipeline/pdf2md.py index 8e7ea80e..898bcb01 100644 --- a/resources/knowledge/original/_pipeline/pdf2md.py +++ b/resources/knowledge/original/_pipeline/pdf2md.py @@ -84,25 +84,31 @@ MIN_IMG = 40 # 이 픽셀보다 작은 이미지는 무시(안내문 아이콘 def _images(page, pno, doc, picdir, stem): - """페이지 이미지를 pic/에 저장하고 (rect, ref) 리스트 반환.""" + """PDF 화면에 보이는 이미지 영역을 렌더링하고 (rect, ref) 리스트 반환. + + 원시 xref를 직접 저장하면 이미지 마스크가 검게 나오거나 이미지 위에 별도로 + 그려진 문자·선이 빠질 수 있다. 페이지의 실제 배치 사각형을 렌더링하여 화면과 + 같은 합성 결과를 보존한다. + """ out = [] idx = 0 for im in page.get_images(full=True): xref = im[0] rects = page.get_image_rects(xref) r = rects[0] if rects else pymupdf.Rect(0, 0, 0, 0) + if r.is_empty or r.is_infinite: + continue try: - px = pymupdf.Pixmap(doc, xref) + source = pymupdf.Pixmap(doc, xref) except Exception: continue - if px.width < MIN_IMG or px.height < MIN_IMG: + if source.width < MIN_IMG or source.height < MIN_IMG: continue idx += 1 picdir.mkdir(parents=True, exist_ok=True) fn = f"{stem}_p{pno + 1}_{idx}.png" try: - if px.n - px.alpha >= 4: # CMYK 등 → RGB - px = pymupdf.Pixmap(pymupdf.csRGB, px) + px = page.get_pixmap(matrix=pymupdf.Matrix(2, 2), clip=r, alpha=False) px.save(str(picdir / fn)) except Exception: continue diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/1. 총론.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/1. 총론.md new file mode 100644 index 00000000..bd7fb4cb --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/1. 총론.md @@ -0,0 +1,117 @@ +# 1. 총론 + +### 가. 도로와 임도 + +도로(Highway, Road, Street)는 보행자와 차량의 통행을 위한 공공용 시설로서 철도와 같이 육상교통을 분담하는 중요한 교통시설이다. 교통(Transport)은 사람이나 물건이 한 장소에서 다른 장소로 이동하는데 필요한 편의를 제공하는 행위로서, 이용통로에 따라 육상교통, 수상교통, 항공교통으로 대별되며, 그 중 육상교통은 도로교통과 철도교통으로 구분된다. 도로법 제2조 제1항에서“도로라 함은 일반의 교통에 공용(供用)되는 도로로서 제11조에 열거한 것”이라고 하고, 농어촌도로는 농어촌도로정비법 제2조 제1항에서“농어촌도로라 함은 도로법에 규정되지 아니한 도로로서 농어촌지역 주민의 교통편익과 생산·유통활동 등에 공용(供用)되는 공로중 제4조에 열거되고 제6조의 규정에 의하여 고시된 도로”라고 대인과 대물을 위하여 제공되는 도로 임을 명시하고 있다. 반면에 임도는 산림법 제10조의 4에서“산림의 효율적인 개발·이용의 고도화 또는 임업의 기계화 등 임업의 생산기반 정비를 촉진하기 위하여 필요한 시설”이라고 대물을 위하여 제공되는 목적도의 개념을 밝히고 있다. 도로가 시설주체, 부지장소, 구조재료, 이용목적에 따라서 구분되는데 반하여 임도는 기능, 이용집약도, 설치위치와 목적에 따라서 구분하고 있다. 도로는 국토의 기능을 증대시키는 사회기반 시설로서 전국간선도로망에서부터 지역개발과 주변토지 이용을 활성화시키는 지역내의 도로망에 이르기까지 유기적인 망(網 : Network)을 이루어 타교통시설과 상호기능을 보완해 나간다. 따라서 도로는 이동의 신속성, 안전성, 쾌적성, 편리성 및 경제성을 도모하여 국토발전의 기반과 생활기반의 정비, 생활환경의 개선에 큰 역할을 하고 있다. 임도는 지역도로망의 한 부분으로서 산림경영의 합리화, 산림의 공익적 기능 증진 및 농산촌 진흥을 위한 기반시설로서 산림이라는 공간에 도로를 매개체로 시장 또는 생산·생활공간과 연결시켜 준다. + +### 나. 기능 + +임도의 기능은 크게 이동기능, 접근기능, 공간기능의 3가지로 구분된다. 이동기능은 교통류를 신속하고 원활하게 처리해 주는 기능으로서 임내 또는 주변 토지에서 생산된 물류를 신속하게 유통시키고, 사람들의 왕래와 여가활동을 위하여 신속성, 안정성, 편리성을 도모하는 것으로서 간선임도, 연결임도(Access Forest Road)가 여기에 해당된다. 접근기능은 임지이용의 활성화를 촉진시키는 기능으로서 임내의 구석구석까지 접근하여 산림 작업과 생산활동에 직접 이용되는 것으로서 지선임도, 경영임도(Management Forest Road)가 이에 해당된다. 공간기능은 제한된 공간을 갖는 집약적인 임업에서 집재, 집적, 주차 등의 공공용지나 휴양림에서 광장 등의 생활공간으로 사용된다. + +![총론_그림5-2-1_임도의기능과이용특성](<../pic/총론_그림5-2-1_임도의기능과이용특성.png>) + +그림 5-2-1. 임도의 기능과 이용특성 + +이동성과 접근성은 (그림 5-2-1)에서 보는 바와 같이 서로 상반되게 나타난다. 즉, 이동기능을 크게 할 경우에는 접근기능이 큰 임도에 비하여 통행량이 많고, 통행길이도 길며, 속도도 빨라져야 하므로, 임도의 구조와 규격을 상대적으로 양호하게 하여야 그 기능에 알맞는 교통류가 형성 될 것이다. 앞으로 지속적인 경제성장에 따라 국민소득과 생활수준이 향상되어 자동차대수는 계속 증가될 것이며 차량도 고속화, 대형화, 중량화 추세에 있으므로 임도의 질적 향상이 시급하고 또한 환경영향 평가 문제가 대두되고 있으므로 합리적인 임도계획을 수립함과 동시에 많은 기술향상이 요망된다. + +### 다. 효과와 경제성 + +임도는 연결되는 도로와 설치하는 산자락의 위치에 따라서 임지의 활용성, 경제성 및 관리성이 달라진다. 따라서 임도를 어떻게 시설하는 것이 가장 튼튼하고 경제성이 있는 임도가 될 것인가? 하는 것은 매우 중요한 일이다. + +#### 1) 설치위치에 따른 효율성과 경제성 + +우리나라의 임도는 시설당시의 정책적, 입지적 또는 사회적인 상황에 따라서 설치위치별로 많은 변화를 가져왔다. '70년대 이전에는 연기매각을 위한 수확의 목적으로 계곡부와 산기슭에 많이 분포되어 있던 임목들을 벌출하기 위하여 계곡부-산기슭에 임도를 주로 시설하였고, 80년대에는 임업기계훈련원을 통한 한독협력사업의 일환으로 서구식의 임도시설방법에 많은 영향을 받아 주로 산허리에 시설되었으며, 90년대에는 간선임도 위주 정책의 일환으로 연결임도를 많이 시설한 결과 산꼭대기에 임도가 많이 시설되었다. 따라서 우리나라 산야에는 산기슭에 위치하고 있는 임도가 약 27%, 산허리에 약 42%, 산정부에 약 31%로 분포되어 있지만 계곡부-산기슭-산허리-산꼭대기로 이어져 순환되는 노선이 대부분이다. 설치 위치에 따른 효율성은 입지적인 상태에 따라 다르지만 대체적으로 접근거리단축효과는 임도개설전을 기준(100%)으로 볼 때 계곡임도는 12~30%, 능선임도는 9~13%, 산복임도는 8~16%, 복합(계곡-능선)임도는 12~20%로서 산복임도와 능선임도가 다른 임도에 비하여 크게 나타났다. 임지의 이용면적 확대효과는 임도개설전을 기준으로 계곡임도는 9∼15배, 능선임도는 12∼19배, 산복임도는 13∼19배, 복합임도는 11∼16배로서 산복임도가 가장 효과가 큰 것으로 나타났다. ㎥당 임목수집비는 계곡임도가 14천원~21천원이 소요되는데 비하여 능선임도는 40-113%, 산 복임도는 53~77%, 복합임도는 55~136%가 소요되어 산복임도가 저렴하게 작업할 수 있었다. + +또한 ㎥당 운재비는 계곡임도가 1,300~1,600원이 소요되는데 비하여 능선임도는 107%까지 산복임도는 102%까지, 복합임도는 195%까지 증가하여 계곡임도가 운반비를 절감할 수 있는 시스템이었다. 따라서 임도는 산복부에 시설하는 것이 다른 위치에 시설하는 것보다 효율성과 경제성이 큰 것으로 나타났다. + +#### 2) 임도의 연결상태 + +모든 도로는 가급적 시장 또는 도시방향으로 가까이 갈수록 상급의 도로구조와 연결되는 것이 진·출입과 교통류의 흐름을 원활하게 할 수 있을 것이다. 그러나 현실적으로 임도와 연결되는 도로의 상태를 보면, 진입로는 공도가 34%, 농도 또는 마을도가 66%를 차지하고 있으나, 진출로는 공도가 19%, 농도 또는 마을도가 40%로서 59%는 순환이 가능하지만 나머지 41%는 타 도로와 연결되지 않고 임지내에서 끝난다. 이들 진출입에 연결되는 도로 가운데 공도와 농도는 비교적 구조가 양호하였지만 마을도의 경우에는 임도의 규격보다 열악한 구조를 가진 도로(진입로의 49%, 진출로의 61%)가 많은 것으로 나타났다. 이는 진·출입로가 병목현상에 의하여 원활한 교통 소통이 어려울 것으로 추정되므로 금후 임도의 구조·규격보다 열악한 진출입 구간에 대한 연결도로의 정비 또는 시공시 연결부분을 보완할 수 있는 제도적인 장치가 필요할 것으로 사료된다. + +#### 3) 임도의 활용형태 + +임도를 활용하는 차량의 주간 교통량은 노선당 평균 45.6회/주로서 활용형태를 살펴보면 일상 생활에 활용되는 경우가 34%, 농림업이 27%, 타산업이 9%로서 생활 및 작업과 관계되는 통행이 대부분을 차지하고 있었지만 휴양목적으로 이용되는 자동차의 비율이 22%나 나타난 것은 유의깊은 사안이다. 그러나 이용빈도는 200일이상 연중통행하는 것은 11%에 불과하였고 대부분이 50일 이내를 통행하였으며, 활용구간 또한 전구간을 통행하는 자동차는 17%에 불과하였고 대부분이 50%이내의 구간을 활용하고 있는 것으로 나타났다. 이는 임도의 시·종점 가까운 곳에 마을, 농경지, 축사 및 농공시설이 산재하여 있기 때문에 물류의 이동순로가 시·종점 연결방향으로 분산되기 때문이다. 통행하는 자동차의 종류는 화물차가 30%, 이륜차 14%, 경운기 4%로서 임도구조에 영향을 많이 받지 않는 작업에 관계되는 자동차의 통행이 약 1/2정도를 차지하고 있었으며, 또한 승용차의 통행량이 52%나 되어 마을주민들의 통행에도 많이 기여하고 있다. 또한 평일(10~13%)보다 주말(20~23%)에 활용이 더 많은 것은 앞에서 언급한 사안과 결부할 때 임도의 활용성면에서 주목할 만하다. 이와 같이 농어촌도로망과 연계되어 주민 교통편의의 목적으로 활용되는 구간은 임도의 구조를 다르게 적용하여 농어촌 도로망과 연계되는 하나의 교통망을 형성하게 할 수 있도록 조치하여야 할 것이다. + +### 라. 종류 +#### 1) 기능에 따른 구분 +- ① 지선임도(시업임도, 경영임도, Management Forest Road) : 조림, 육림, 수확 및 보호관리 등 임업경영의 목적으로 시설되는 임도 +- ② 간선임도(연결임도, 도달임도, Access Forest Road) : 산원까지 접근, 유역간의 연결, 농어촌도로망과 연계되어 지역경제활동에 기여하는 등 임업적 목적보다는 공익적 목적에 비중을 더 두고 시설되는 임도 +#### 2) 이용집약도에 따른 구분 +- ① 주임도(Main Forest Road) : 집재장 또는 부임도로부터 공도까지 연결되는 영구적인 임도 +- ② 부임도(Secondary Forest Road, Subsidiary Forest Road) : 집재장 또는 작업도로부터 주임도 또는 공도까지 연결되는 영구적인 임도 +- ③ 작업도(Skidding Road, Strip Road) : 임지 또는 운재로로부터 집재장, 부임도 또는 주임도까지 연결되는 일시적인 임도 +- ④ 운재로(Skidding Trail, Haul Road) : 임지에서부터 집재장 또는 작업도까지 연결되는 일시적인 임도로서 임목만 제거하고 대규모의 토양이동은 하지 않는다. +#### 3) 설치위치에 따른 구분 +- ① 주계곡임도(Main Vally Forest Road) +- ② 부계곡임도(Secondart Vally Forest Road) +- ③ 사면임도(Slope Forest Road) +- ④ 능선임도(Mountain Ridge Forest Road) +- ⑤ 산정임도(Mountain and Hill Tops Forest Road) +- ⑥ 분지임도(Vally Basins Forest Road) +#### 4) 규정에 의한 구분 +- ① 1급임도 : 유효너비 4m 이하 +- ② 2급임도 : 유효너비 3m 이하 +### 마. 노망의 운송체계 + +산림을 통과하고 있는 도로는 도로법에 의한 고속국도, 일반국도, 특별시도·광역시도, 지방도, 시도, 군도, 구도, 농어촌도로정비법에 의한 면도, 리도, 농도 등 여러 종류의 공도와 사도법에 의한 사도, 타 법령에 의하여 시설되는 목적도(目的道)가 있다. 임도는 산림내 또는 산림에 연결 시설하는 차도이므로 임내에 있을 수도 있고 임외에서 공도와 임지를 연결할 수도 있다. 따라서 임도망은 임산물이 임지에서 생산되어 공도를 경유하여 시장이나 제재공장 등 수요처까지 운반될 수 있는 연결노망의 일부분이라고 할 수 있을 것이다. 도로(공도)에서부터 임내까지 도달하는 것을 임내 접근수단이라고 하고, 산림내에서 생산되는 임산물이 공도를 거쳐 시장·공장 등 수요처까지 운반하는 것을 반출 또는 운송수단이라고 하며 그 운송체계는 (그림 5-2-2)와 같이 임산물이 생산된 위치와 임도망의 상태에 따라서 여러 가지의 경로로 가정할 수 있다. + +![총론_그림5-2-2_임내생산물의운송체계](<../pic/총론_그림5-2-2_임내생산물의운송체계.png>) + +운재로 작업도 임산물 집 재 + +- ② +- ① +- ③ 2급임도 +- ④ 공 도 +- ⑤ 그림 5-2-2의 ①과 같이 임산물이 지예집재·가선집재 등의 집재작업 과정을 + +통하여 간단하게 공도로 수송될 수 있는 산림이 있는가 하면 ⑤의 운송체계와 같이 집재, 운재로, 작업도, 2급임도, 1급임도를 거쳐야만 비로소 공도로 수송될 수 있는 산림이 있을 것이다. + +- ① , ②, ③과 같이 기존도로(임도)에 운재로와 작업도를 시설하여 반출하는 운송체계와 같은 + +노망형태를 세부노망형태라고 하며, 완구릉지 또는 산림내에 공도밀도가 높아서 간단한 시설로서 임목을 수송할 수 있는 지역에 해당된다. ④, ⑤와 같이 2급임도 또는 1급임도를 시설하여 반출하는 운송체계의 노망형태를 기본노망형태라고 하며, 오지 또는 산악림과 같이 공도밀도가 낮은 지역에 해당된다. 특히 ⑤와 같은 운송체계로서 시설하는 1급임도는 임업적 효과보다는 공익적 효과가 더 클 경우가 많다. 임도망을 편성할 경우에는 기본임도망의 단계만 취급하고 세부노망의 형태는 그 지역에서 시 업을 실행할 경우에 별도로 계획을 수립하여야 한다. 임도밀도가 점차적으로 높아져서 적정한 노망이 형성되게 되면 대부분의 임지가 ①∼③같은 운송체계로 변화하게 되므로 임내접근을 용이하게 함은 물론 임산물의 운송비를 저렴하게 하여 산림의 생산성을 더욱 향상시킬 수 있을 것이다. 임도망을 편성하고자 하는 대상지에 어떤 노망체계를 적용하는 것이 합리적일 것인가 하는 것은 대단히 어렵지만 대상지의 입지상태와 계획임도의 구조를 면밀히 검토하여 가장 합리적인 형태를 적용하여야 할 것이다. + +### 바. 임도망과 집·운재 + +집·운재방법은 (그림 5-2-3)과 같이 문화의 발달정도, 지형과 산림의 상태, 산림작업기술의 수준, 제품의 규격 및 판매기준 등에 따라서 많은 영향을 받게 된다. 관류{Flume, 철포이용, 뚝(언)이용 등 포함}뗏목(편류 : Rafting), 벌류(Floating)수운(Water Transportation)선박(Shipping)활로(Chute, 토수라, 목수라, 프라스틱수라, 알루미늄수라 등) 지예{Skidding, Off Road, 인력, 동물(소, 말 등), 임업용트랙터, 트랙터장치용원치류, 스키더류, 가선집재기 등}육운(Land Transportation)도로(On Road, 인력나르기, 우마차, 목마, 트럭류, 트랙터류, 포워더, 트레일러류)궤도(Rail Way, 산림철도, 산림궤도)삭도(Cable Way, 가선집재기류, 가공삭도, 철선운반 등)공운(Air Transportation)항공(Air Borne, 헬리곱터, 기구)그림 5-2-3. 집·운재방법과 종류 옛날에는 토수라, 목수라 등의 방법으로 집재하산하여 주로 관류, 뗏목, 벌류 등의 방법으로 운재하였다. 그러나 근래에는 도로교통과 자동차공업의 발달로 인하여 집재, 운재방법이 육운은 대부분 기계화 또는 자동차화 되고 있고, 수운은 대부분 선박에 의존하고 있지만 앞으로 기구(氣球)나 헬리콥터에 의한 공운의 발달이 주목된다. 육운의 방법으로 합리적인 임업경영을 하기 위한 필수적인 시설은 적정임도망이 되도록 노망 체계를 구축하는 것이다. 이는 산림작업 환경개선과 산림작업의 기계화에 의하여 노동력을 경감하고 노동의 질을 향상시켜 산림작업의 합리화와 능률화에 기여한다. 따라서 지형과 자연경관 및 산림작업성이 잘 조화될 수 있도록 노망을 계획하여야 하며 임도가 임지의 경사의 상부에 배치되느냐 경사의 하부에 배치되느냐에 따라서 집재방법과 집재비용은 달라진다. 임도가 경사의 상부에 배치되어 있다면 상향집재방법을 채택하여 임목을 집재하여야 할 것이고 경사의 하부에 배치되어 있다면 하향집재방법을 채택하여야 할 것이다. 주요집재수단에 대한 작업한계선은 (표 5-2-1)과 같다. 표 5-2-1. 집재수단별 최대집재거리 및 작업안전 한계기울기 + +| 집 재 수 단 | | | | 하향집재 | | 상향집재 | | 비 고 | | +|---|---|---|---|---|---|---|---|---|---| +| | | | | 최 대 | 작업한계 | 최 대 | 작업한계 | | | +| | | | | 집재거리 | 기울기 | 집재거리 | 기울기 | | | +| | | | | (m) | (%) | (m) | (%) | | | +| 인 력 | 보조도구이용 | | | 100(200) | 45(65) | | | | | +| | 수라(LOG-LINE) | | | 150(200) | 40(60) | | | | | +| 자 동 차 류 | 트 랙 터 | 농용 트랙터 | | 300(500) | 25(60) | 100 | 10(15) | | | +| | | 개조 트랙터 | | 500(800) | 40(60) | 150 | 15 | | | +| | | 임업용트랙터 | | 800(1,000) | 45(60) | 200(250) | 20(25) | | | +| | 포 워 더 | | | 2,000 | 35(40) | 1,500 | 20(25) | 습윤지역은궤도식을이용(60%까지가능) | | +| | 프로세서, 하베스터 | | | 50 | 30(40) | 50(50) | 10(15) | | | +| 가 선 류 | 기계톱 윈치 | | | 50 | 35 | 50(100) | 45 | high-lead 방식 | | +| | 트랙터 윈치 | | | 150(200) | 100 | 150(200) | 120 | high-lead 방식 | | +| | 고정식가선집재기 | | | 1,000(2,000) | 100 | 1,000(2,000) | 120 | standing skyline 방식 | | +| | 타워형 가 선 집재기 | | 단거리집재기 | 300 | 100 | 400 | 120 | | | +| | | | 중거리집재기 | 500 | 100 | 800 | 120 | | | +| | | | 장거리집재기 | 500(800) | 100 | 1,000 | 120 | | | +| * ( ) 내의 숫자는 특수한 경우의 최대치임. | | | | | | | | | | +| ** 자료: Sedlak(1985,1987), Murphy(1979), Heinrich(1982), Trzesniowski(1985), FAO(1976), | | | | | | | | | | +| Studier and Binkley(1982), Sundberg and Silversides(1988), スリ-エ硏究會(1991), 김(1993) | | | | | | | | | | + +#### 1) 하향집재 +- ① 인력집재 : 수피가 있는 임목의 지예집재는 경사도가 80%이상, 수피가 없는 임목은 60%이상이면 가능하나 적설이나 지표가 젖어 있을 경우에는 32%에서도 가능하다. +- ② 동물집재 : 평탄지에서 가능하고 동물의 종류나 임목의 중량에 따라서 경사도 35%까지 가능하다. +- ③ 농용트랙터 : 경사도 30%까지 가능하고 바퀴에 체인을 감거나 안전탑과 같은 특수장치를 부착하면 40%까지 가능하다. +- ④ 스키더 : 바퀴에 체인을 감는 경우에는 경사도 50%까지, 단거리의 건조한 지반에서는 60%까지 가능하다. +- ⑤ 중력식 케이블크레인 시스템 : 상단부에 설치하여 작업할 경우에는 경사도 20%이상 지형에서도 가능하다. +#### 2) 상향집재 +- ① 인력집재 : 일반적으로 적용할 수 없다. +- ② 동물집재 : 가벼운 적재와 단거리 집재는 경사도 10%까지 가능하다. +- ③ 농용트렉터 : 경사도 20%까지 가능하다. +- ④ 스키더 : 경사도 25%까지 가능하다. +- ⑤ 케이블에 의한 지예집재 : 장애물이 없는 지형에서는 30m까지 가능하고 특별한 경우에는 100m, 쌍드럼으로 설치된 것은 300m까지도 가능하다. +- ⑥ 케이블크레인 시스템 : 상단부에 설치할 경우에는 경사도 20%까지 가능하다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 1~7쪽 (인쇄면 371~377쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/2. 임도구조.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/2. 임도구조.md new file mode 100644 index 00000000..0175af71 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/2. 임도구조.md @@ -0,0 +1,332 @@ +# 2. 임도구조 + +임도의 구조(Forest Road Structure)를 계획하고자 할 때에는 토목적인 면, 경제적인 면 및 환경적인 면을 고려하여야 하며, 임산물의 종류, 집재방법, 수송시기 및 수량에 따라서도 구조나 규격이 달라질 수 있다. 임도상을 운행할 수 있는 차량의 제원(諸元)은 (표 5-2-2)와 같이 자동차의 종류에 따라 다르므로 이용목적에 따라 통행할 수 있는 자동차 가운데 최대의 규격을 적용한다. 표 5-2-2. 설계차량의 제원(단위:m) + +| 구 분 종 류 | 길이 | 너비 | 높이 | 앞내민거리 | 앞뒤바퀴 거 리 | 뒤내민거리 | 최소회전 반 지 름 | +|---|---|---|---|---|---|---|---| +| 소형 자동차 | 4.7 | 1.7 | 2.0 | 0.8 | 2.7 | 1.2 | 6.0 | +| 보통 자동차 | 13.0 | 2.5 | 4.0 | 2.5 | 6.5 | 4.0 | 12.0 | +| 세미트레일러 연결차 | 16.7 | 2.5 | 4.0 | 1.3 | 전: 4.2
후: 9.0 | 2.2 | 12.0 | + +### 가. 자동차 설계속도 + +설계속도(design speed)는 계획하는 노선의 경제성에 따라 결정되고 있으나 다음과 같이 설정되고 있는 것이 일반적이다. + +- ① 평지보다 산지인 경우를 낮게 한다. +- ② 장거리교통보다 단거리교통인 경우를 낮게 한다. +- ③ 교통량이 많은 노선보다 적은 노선인 경우를 낮게 한다. 자동차의 설계속도는 앞차 앞면과 후속차 앞면의 간격과 그 곳을 통행하는 교통량으로부터 + +산출되고 있지만, 임도는 보통 1차선으로 시설되고 있어 자동차의 교행이 어려우므로 대피소간의 왕복거리와 교통량으로 산출한다. + +$$V=\frac{N\cdot d}{1,000}$$ + +- $V$: 자동차의 주행속도 또는 설계속도(km/hr) +- $N$: 시간당 교통량(대/hr) +- $d$: 차두간격($4.5+0.186V+0.00154V^2$) 또는 대피소 간의 왕복거리(m) + +(예제) 서산군 관내에 시설되는 임도의 설계속도를 산출하기 위하여 주위의 실정을 검토한 바 대피소 간격은 300m, 시간당 교통량은 50대/hr로 나타났다. + +$$V=\frac{50\times(300\times2)}{1,000}=30\,\mathrm{km/hr}$$ +### 나. 차도폭 +#### 1) 1차선일 경우 +##### 가) 설계속도에 의할 경우 + +$$W=B+\frac{V}{50}+0.5$$ + +- $W$: 차도폭(m) +- $B$: 자동차의 폭(m) +- $V$: 설계속도(km/hr) + +(예제) 설계속도가 30km/hr이고 자동차폭이 2.5m일 때 차도폭은 다음과 같다. + +$$W=2.5+\frac{30}{50}+0.5=3.6\,\mathrm{m}$$ +##### 나) 길가(路端)와 자동차의 간격에 의할 경우 + +$$W=B+2(b-b')$$ + +- $b'=0.3$m: 자동차 바퀴와 가장자리의 간격 +- $b=K_1V$: 자동차 바퀴에서 길가까지의 간격($K_1=0.01411$) + +(예제) 자동차폭 2.5m, $b'=0.3$m, 설계속도 30km/hr일 때 $b=0.01411\times30=0.4233$m이다. +- ② 차도폭(W) = 2.5+2×(0.4233-0.3) = 2.75m +#### 2) 2차선일 경우 + +$$W=2(B+b)+b_0-2b'$$ + +- $b=K_1V$($K_1=0.01411$) +- $b'=0.3$m +- $b_0=K_2V^2$($K_2=0.00016$) + +(예제) 자동차폭 2.5m, $b'=0.3$m, 설계속도 40km/hr일 때: + +- ① $b=0.01411\times40=0.5644$m +- ② $b_0=0.00016\times40^2=0.256$m +- ③ 차도폭(W) = 2×(2.5+0.5644)+0.256-(2×0.3) = 5.78m +### 다. 곡선반지름(radius of curve) +#### 1) 운반되는 통나무의 길이에 의할 경우 + +곡선부를 통과하는 트럭의 앞바퀴와 적재된 화물의 끝부분은 노측구조의 장애로 인하여 교통에 저해받지 않을 만큼 충분한 여유노폭이 있어야 한다. + +$$R=\frac{\ell^2}{4B}$$ + +- $R$: 곡선반지름(m) +- $\ell$: 통나무길이(m) +- $B$: 노폭(m) + +(예제) 길이 20m의 전간목을 노폭 4m인 임도에서 운반할 때 $R=20^2/(4\times4)=25$m이다. + +#### 2) 원심력과 타이어 마찰계수에 의할 경우 + +곡선부를 주행하는 자동차에 가해지는 원심력은 횡방향력이 타이어와 노면의 마찰력에 대한 한계를 넘지 않아야 한다. + +$$R=\frac{V^2}{127(i+f)}$$ + +- $V$: 설계속도(km/hr) +- $i$: 곡선부 외쪽물매(%/100) +- $f$: 가로미끄러짐에 대한 노면과 타이어의 마찰계수 + +| 구 분 | 마찰계수 | 구 분 | 마찰계수 | +|---|---|---|---| +| 자 갈 도 | 0.4∼0.5 | 콘크리트 포장도 | 0.4∼0.6 | +| 빙 설 면 | 0.2∼0.3 | 아스팔트 포장도 | 0.4∼0.8 | +| ※ 임도의 설계속도가 40km/hr 이하일 때는 0.15를 적용 | | | | + +(예제) 설계속도 40km/hr, 외쪽물매 6%, $f=0.15$일 때: + +$$R=\frac{40^2}{127\times(0.06+0.15)}=60.0\,\mathrm{m}$$ + +표 5-2-3. 설계속도와 곡선반지름(m) + +| 설 계 속 도 (km/hr) | 외 쪽 물 매 (%) | | | | +|---|---|---|---|---| +| | 5 | 6 | 7 | 8 | +| 40 | 63 | 60 | 57 | 55 | +| 30 | 35 | 34 | 32 | 31 | +| 20 | 16 | 15 | 14 | 14 | +| ※ 가로미끄러짐 마찰계수 0.15 적용 | | | | | + +### 라. 곡선부 확폭 + +자동차의 뒷바퀴는 뒷차축에 직각으로 장치되어 있어 (그림 5-2-4)와 같이 항상 앞바퀴보다 안쪽으로 기울어져서 곡선부를 통과하므로 앞바퀴와 뒷바퀴는 각각 다른 궤도를 그리면서 주행한다. 따라서 곡선부의 내각이 예각일 경우에는 이러한 현상이 더욱 심하기 때문에 곡선부의 안쪽으로 그 만큼 더 확폭(Widening of Road)을 하여야 한다. + +#### 1) 트럭일 경우 + +$$\varepsilon=\frac{L^2}{2R}-0.5$$ + +![임도구조_그림5-2-4_자동차바퀴의구동형](<../pic/임도구조_그림5-2-4_자동차바퀴의구동형.png>) + +- $\varepsilon$: 확폭량(m) +- $R$: 중심선의 곡선반지름(m) +- $L$: 차량 앞면에서 뒷차축까지 거리(m, 8m 적용) + +(예제) 광릉시험림 내 임도의 최소곡선반지름이 20m일 때 굴곡부의 확폭량은 $\varepsilon=8^2/(2\times20)-0.5=1.1$m이다. +#### 2) 세미트레일러(semi-trailler)연결차일 경우 + +$$\varepsilon=\varepsilon_1+\varepsilon_2=\frac{L_1^2}{2R}+\frac{L_2^2}{2R'}$$ + +- $R'=R-\varepsilon_1$ +- $L_1$: 세미트레일러 앞면에서 제2차축까지 거리(m) +- $L_2$: 제2차축에서 최후 차축까지 거리(m) + +(예제) $L_1=6.7$m, $L_2=11.5$m, $R=20$m일 때: + +- ① $\varepsilon_1=6.7^2/(2\times20)=1.12$m +- ② $R'=20-1.12=18.88$m, $\varepsilon_2=11.5^2/(2\times18.88)=3.50$m +- ③ 확폭량(ε) = ε1+ε2 = 1.12+3.50 = 4.62m +### 마. 완화구간 + +자동차의 원활한 통행을 위하여 다음 구간에 대하여는 (그림 5-2-5)와 같이 완화구간을 설치하지만, 이정량(移程量)이 20cm이하일 경우에는 설치하지 아니한다. + +- ① 직선부와 곡선부, 혹은 곡율이 다른 곡선부의 연결구간에 설치 +- ② 외쪽물매와 직선부의 횡단물매 또는 외쪽물매 상호간의 연결구간에 설치 +- ③ 곡선부·확폭구간과 직선부의 연결구간에 설치 + +$$L=\frac{0.036V^3}{R}$$ + +- $L$: 완화구간의 길이(m) +- $R$: 곡선반지름(m) +- $V$: 설계속도(km/hr) + +표 5-2-4. 설계속도별 완화구간의 길이(m) + +| 설 계 속 도(km/hr) | 20 | 30 | 40 | 50 | 60 | +|---|---|---|---|---|---| +| 완화구간의 길이(m) | 20 | 25 | 35 | 40 | 50 | + +![임도구조_그림5-2-5_완화구간의형태](<../pic/임도구조_그림5-2-5_완화구간의형태.png>) + + +### 바. 물매 + +물매의 표현방법은 다음과 같다. +- ① 각도 : 수평을 0°, 수직을 90°로 하여 그 사이를 90등분한 것 +- ② 1 : n 또는 1 / n : 높이 1에 대하여 수평거리 n으로 나눈 것 +- ③ n % : 수평거리 100에 대한 n의 고저차를 갖는 백분율 +- ④ n ‰ (per mill) : 수평거리 1000에 대한 n의 고저차를 갖는 천분율 +- ⑤ 비탈물매 : 수직높이 1에 대한 수평거리의 비(比)로서 하할법 또는 할푼법이라 함 ※ 15/100 = 15% = 150‰ = tan 8°31' 50.8" = 1/6.67 = 6할 7푼 +#### 1) 곡선부 외쪽물매(片勾配)의 산출 + +자동차가 원심력에 의하여 도로의 바깥쪽으로 뛰쳐나가려는 힘이 생기므로 이를 방지하기 위하여 곡선부에서는 외쪽물매(Super Elevation, Oneway Grade)를 설치한다. 외쪽물매는 노면 바깥쪽이 안쪽보다 높게 설치되도록 횡단선형을 조정한다. + +$$i=\frac{V^2}{127R}-f$$ + +- $i$: 곡선부의 외쪽물매(%/100) +- $V$: 설계속도(km/hr) +- $R$: 곡선반지름(m) +- $f$: 가로미끄러짐에 대한 노면과 타이어의 마찰계수 + +표 5-2-5. 설계속도별 곡선반지름별 한계 외쪽물매(%) + +| 설계속도(km/hr) | 곡 선 반 지 름(m) | | | | | | | +|---|---|---|---|---|---|---|---| +| | 12 | 15 | 20 | 30 | 35 | 40 | 45 | +| 20 30 40 | 8 | 3∼5 | 8 | 8 | 5∼6 | 3∼5 8 | 8 | + +(예제) 설계속도 40km/hr, 곡선반지름 50m, $f=0.15$이면 $i=40^2/(127\times50)-0.15\fallingdotseq0.102=10.2$%이다. 10.2%는 8%를 초과하므로 현지 여건에 따라 8% 이하가 되도록 곡선반지름을 키우거나 설계속도를 낮춰야 한다. + +#### 2) 횡단물매의 산출 +- ① 횡단물매(Cross Grade, Cross-Fall)의 결정은 노면배수와 교통안전의 두 가지 측면으로 고려할 수 있다. 노면배수의 측면에서 볼 때는 노면이 평활하면 배수상태가 불량하고 반대로 노정(路頂)을 높게 하거나 외쪽물매를 크게 하면 주행안전성에 영향을 미친다. +- ② 횡단물매는 포장의 재료, 노체의 종류 및 시공방법에 따라 다르지만 교통으로 인한 마모가 적은 재료를 사용한 노면은 내구력이 크므로 노정고(路頂高)가 낮아도 된다. +- ③ 횡단물매는 노정고와 차도폭의 1/2로서 산출하거나, 외쪽물매인 경우는 양 노단높이(路端高)의 차와 노폭으로 산출하며 백분율 또는 분수로 표시한다. +- ④ 횡단물매의 형상은 직선, 원호, 2차 포물선, 쌍곡선 등이 있으나, 아스팔트 포장도는 쌍곡선, 자갈도는 포물선, 콘크리트 포장도는 직선이 주로 사용되고 있다. +#### 3) 합성물매의 산출 + +종단물매와 외쪽물매 또는 횡단물매를 제곱하여 합한 값의 제곱근을 합성물매(合成勾配: Composite Gradient)라고 한다. 합성물매는 다음 식으로 산출한다. + +$$S=\sqrt{i^2+j^2}$$ + +- $S$: 합성물매(%) +- $i$: 외쪽물매 또는 횡단물매(%) +- $j$: 종단물매(%) + +대개 합성물매는 12% 이하로 하는 것이 좋으며 부득이한 경우에도 13∼15% 이하로 하는 것이 좋다. 합성물매로 산출한 종단물매는 표 5-2-6과 같다. + +표 5-2-6. 한계 합성물매와 외쪽물매에 의한 종단물매(%) + +| 한계합성물매(%) | 외쪽물매 또는 횡단물매(%) | | | | | | +|---|---|---|---|---|---|---| +| | 8 | 6 | 5 | 4 | 3 | 2 | +| 12 | 8.9 | 10.4 | 10.9 | 11.3 | 11.6 | 11.8 | +| 13 | 10.2 | 11.5 | 12.0 | 12.4 | 12.6 | 12.8 | +| 15 | 12.6 | 13.7 | 14.1 | 14.5 | 14.7 | 14.9 | + +(예제) 산악지 임도에서 종단물매 9%의 구간에 곡선부의 외쪽물매를 7%로 설치하고자 할 때 합성물매를 산출하여라. + +$$S=\sqrt{7^2+9^2}=11.4\%$$ + +#### 4) 종단물매의 산출 + +임도의 구조 중 노폭이나 곡선반지름 및 다른 구조시설은 임도의 시공후에도 개수나 보수에 의하여 구조변경이 가능하지만, 종단물매의 변경은 전 노선을 조정하여야 하는 재시공을 의미하기 때문에 임도의 축조 중 가장 중요한 부분은 종단물매(Longitudinal Grade, Gradient)라고 할 수 있다. 자동차의 종류에 따라서 종단물매를 오를 수 있는 능력의 차이가 크기 때문에 모든 자동차에 대하여 설계속도를 보장할 수 있는 일정한 기준을 세운다는 것은 사회적, 경제적인 견지에서 볼 때 불가능하다. 이 때문에 종단물매의 일반치는 승용차에서는 대개 설계속도 정도로, 보통자동차에서는 설계속도의 약 50∼80% 정도로 오를 수 있는 상태를 조건으로 설정하여 정한다. 노선계획시 물매를 높게 하면 임도우회율이 적어지므로 연장이 짧아져서 임도시설비가 감소될 수 있지만 자동차의 통행에 지장을 초래함은 물론 강우로 인한 피해가 많아져서 유지관리비가 증가한다. 반면에 물매를 낮게 하면 임도우회율이 커지므로 연장이 길어져서 시설비는 증가될 수 있지만 자동차 통행의 안정성이 도모되고 유지관리비가 감소하기 때문에 더 경제적일 수 있다. 노면배수가 불량하면 연약노면으로 변하여 노면의 형상이 변하기 쉽고, 차륜(車輪)에 의한 바퀴자국(軌跡)으로 인한 유로(流路)가 발생하여 노면재해를 가중시킨다. 이를 방지하기 위한 물 매를 최소물매라고 하며 3% 이상으로 설치하는 것이 좋다. 토사도 또는 사리도에서 노면배수, 노면의 안정성 등 자연재해예방을 위하여 4∼8% 정도로 설치하는 것이 바람직하고 부득이 하더라도 10%를 초과하지 않도록 한다. + +##### 가) 곡선부 적정종단물매의 산출 +- ① 외쪽물매 6%미만일 경우 : G - (80 / R) > S +- ② 외쪽물매 6% 이상일 경우: $G-(120/R)>S$ + +여기서 $G$는 설계기준에 의한 최대 종단물매(%), $R$은 곡선반지름(m), $S$는 완화구간을 포함한 곡선길이의 종단물매(%)이다. + +(예제) 종단물매 6%, 곡선반지름 50m, 외쪽물매 6%, 2급임도 표준물매 9%일 때 $9-(120/50)=6.6>6$%이므로 이 구간의 물매는 수정할 필요가 없다. +##### 나) 합성물매에서 곡선부 종단물매의 산출 + +$$j=\sqrt{S^2-i^2}$$ + +(예제) 광릉시험림 임도는 합성물매를 12% 이하로 설정한다. 외쪽물매를 6%로 적용할 때 종단물매는 다음과 같다. + +$$j=\sqrt{12^2-6^2}=10.4\%\fallingdotseq10\%$$ +##### 다) 물매곡율비의 산출 + +곡선부의 내각이 예각일 경우에는 급한 곡선이 설정되기 때문에 곡선부를 통과하는 자동차의 안정성에 영향을 크게 미치게 된다. 물매곡율비는 다음 식으로 산출한다. + +$$K=\frac{R}{I}$$ + +- $R$: 곡선반지름(m) +- $I$: 종단물매(%) +- $K$: 물매곡율비 + +| 구 분 | 물매곡율비 | 구 분 | 물매곡율비 | +|---|---|---|---| +| 평탄지 도로 | 7.5 이상 | 산악지 도로 | 4.0 이상 | +| 구릉지 도로 | 6.0 이상 | 임 도 | 3.0 이상 | + +일반적으로 외거(External Distance)는 교점(Intersection Point)에서 중곡점(Middle of Curve)까지의 거리로써, 그것의 크기는 내각의 크기에 반비례한다. 곡선반지름 10m 기준으로 볼 때 외거의 크기는 내각이 55°이면 11.657m, 105°는 2.605m, 135°는 0.824 m, 155°는 0.234m로서 내각이 클수록 교점과 중곡점은 가까워지므로 곡선반지름을 크게 적용할 수 있다. 따라서 산악지 지형조건에서는 내각이 예각에 가까울 경우에는 외거가 커지므로 곡선반지름을 크게 설치할 수 없기 때문에 구조를 보완하여 자동차 통행의 안정성이 보장될 수 있도록 물 매곡율비를 적용한다. 예를들면 물매곡율비(곡선반지름/종단물매)를 3.0이상으로 유지시키도록 설치·시공하려면 곡선반지름이 10m일 때 종단물매는 3%내외로 조정할 수 밖에 없고, 내각이 105°이상으로 클 경우에는 곡선반지름을 20m로 하여도 6%내외, 155°이상일 경우에는 직선부와 거의 같도록 설치하여도 된다. + +### 사. 가시거리 +#### 1) 제동정지 가시거리(stopping S.D.)의 산출 +##### 가) 대상물이 고정되어 있을 경우 + +$$S=0.694V+\frac{0.00394V^2}{f}$$ + +- $S$: 가시거리(m) +- $V$: 주행속도(km/hr) +- $f$: 타이어와 노면의 가로미끄러짐 마찰계수 + +| 노면상태 | 설계속도(km/hr) | | | +|---|---|---|---| +| | 30 | 35 | 50 | +| 건 조 | 0.65 | 0.64 | 0.61 | +| 습 윤 | 0.44 | 0.40 | 0.35 | + +※ 0.694는 운전수의 반응시간($t$)이 2.5초일 때 $t/3.6$으로 산출한 값이며, 0.00394는 중력가속도($g$)가 9.8m/sec²일 때 $1/(2g\times3.6^2)$으로 산출한 값이다. + +표 5-2-7. 제동정지 가시거리(m) + +| 노면상태 | 설계속도(km/hr) | V(km/hr) | f | 0.694·V | 0.00394·V2/f | S(m) | +|---|---|---|---|---|---|---| +| 건 조 | 30 35 50 | 30 35 50 | 0.65 0.64 0.61 | 21 24 35 | 5 8 16 | 26 32 51 | +| 습 윤 | 30 35 50 | 28 33 46 | 0.44 0.40 0.35 | 19 23 32 | 7 11 24 | 26 34 56 | + +##### 나) 양쪽에서 마주오는 자동차가 동시에 정지할 경우 + +$$S=1.388V+\frac{0.00788V^2}{f}$$ + +(예제) 설계속도 40㎞/hr일 때 마찰계수($f$)=0.40이라면 제동정지 가시거리는 얼마인가? + +- ① 양방향에서 주행할 경우: $S=1.388\times40+(0.00788\times40^2)/0.40=87.40\,\mathrm{m}$ +- ② 대상물이 고정되어 있는 경우 : S = 0.694×40+0.00394×402/0.40 = 43.52m +#### 2) 곡선부 가시거리의 산출 + +(그림 5-2-6의 ㉠)과 같이 곡선부의 안쪽에 절토부가 있을 때에는 시야가 가려지므로 (그림 5-2-6의 ㉡)과 같이 층따기를 하여 시야를 넓혀야 할 필요가 있다. + +$$S=Q\cdot R=0.01754\theta R$$ + +$$d=R\left\{1-\cos\left(\frac{\theta}{2}\right)\right\}=R\left\{1-\cos\left(\frac{28.7S}{R}\right)\right\}$$ + +- $S$: 가시거리(m) +- $Q$: 호도법에 의한 중심각 +- $R$: 곡선반지름(m) +- $d$: 중심선에서 안쪽으로 층따기를 하여야 할 거리(m) + +![임도구조_그림5-2-6_굴곡부의가시거리확보방법_01](<../pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_01.png>) + +![임도구조_그림5-2-6_굴곡부의가시거리확보방법_02](<../pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_02.png>) + +그림 5-2-6. 굴곡부의 가시거리 확보방법 + +(예제) 산림경영시범단지 내의 임도시설 시 안전거리를 산출하려고 한다. 곡선의 내각이 45°, 반지름이 40m일 때 가시거리($S$)와 안쪽 층따기 거리($d$)를 구하여라. + +- ① $S=0.01754\times45\times40=31.57\,\mathrm{m}$ + +- ② d=40×{1-cos(45°/2)}=3.0m +### 아. 주요 국가의 임도구조 + +주요 국가의 임도규정에 규정된 구조는 (표 5-2-8)과 같다. 표 5-2-8. 각국의 임도구조 + +| 구 분 | 단위 | 우리나라 | 일본 | 중국 | 미국 | 캐나다 | 독일 | 오지리 | 스위스 | | 스웨덴 | 노르웨이 | 영국 | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +| 등 급 구 분 | | 2 | 3 | 4 | 4 | 6 | 3 | 2 | 3 | | 6 | 4 | | +| 설 계 속 도 | ㎞/hr | 20∼40 | 20∼40 | 20∼50 | | 55∼79 | | | 30∼60 | | 20∼60 | 25 | | +| 차도폭 | m | 3∼4 | 2∼4 | 3∼6.5 | 3.7∼5.5 | 6.1∼9.7 | 3∼9 | 4.5∼5.5 | 3∼3.6 | | 4∼7 | 3∼4 | 3.2∼4.7 | +| 갓길폭 | m | 0.50 (0.25) | 0.50 (0.25) | | 0.60 | 0.90∼1.20 | 0.75∼1.00 | 0.75 | | | | 0.25∼0.50 | 0.50 | +| 최 소 곡 선 반지름 | m | 15∼60 (12∼40) | 15∼60 (8∼40) | 15∼120 (20∼60) | 15.2∼30.5 | | 20∼50 (16) | 12∼16 | 13.5∼120 (8∼10) | | 25∼150 | 20∼60 | 15∼45 | +| 최 급 종 단 물 매 | % | 7∼9 (14) | 7∼9 (14) | 800 - 4 500 - 5 400 - 6 300 - 7 250 - 8 150 - 9 100 -10 | A300 - 8 150 - 10 B450 - 10 150 - 12 C300 - 16 | 8∼9 (10) | 6∼8 (10) | 9∼12 (12∼ 16) | 3∼10 (12) | | 8∼12 (14) | 10∼15 (11∼18) | 10 | +| 최저종 단물매 | % | | | | 2 | | 2 | 2∼4 | 3 | | | | | +| 최 대 역물매 | % | 6∼10 | | | A300 - 6 150 - 8 B450 - 8 150 - 10 C300 - 12 | 3∼12 | | 6∼10 | | | | 7∼12 (8∼13) | | +| 횡 단 물 매 | % | 3∼5 | 3∼5 | | | | | | 3 | | | | | +| 안 전 시 거 | m | 20∼40 | 20∼40 | 40∼230 (15∼100) | 76∼122 | | | | 28∼145 | | 40∼ 130(150) | 20∼50 | | +| 대피소 간 격 | m | 300∼500 | 300∼500 | 200∼300 (500) | 230 | | | | 150∼250 | | | 150∼400 | | +| 측구등 | m | | | | 폭 0.9 깊 이 0.5 | | 폭 0.4∼0.45 | 암 거 최소경 0.3∼0.6 | | | | 폭 0.5∼1.5 깊 이 0.5∼0.8 | | +| ※ 자료: 피해 예방을 위한 임도의 구조 개선. 임연연보50 , 1994. | | | | | | | | | | | | | | + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 8~18쪽 (인쇄면 378~388쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/3. 임도계획.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/3. 임도계획.md new file mode 100644 index 00000000..6e1940d1 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/3. 임도계획.md @@ -0,0 +1,623 @@ +# 3. 임도계획 + +임도의 계획은 임도망을 계획하고자 하는 구역 안에 임도를 어느 정도의 밀도로서 어떻게 배치하는 것이 경제적이고 이용효율성이 높은 임도를 시설할 수 있는가를 알기 위하여 필요하다. 임도의 계획은 계획기간에 따라서 장기계획, 단기계획, 시공계획의 단계로 구분된다. + +- ① 장기 계획 지역 전체를 대상으로 하는 5년 이상의 계획기간으로서 해당지역 내의 목표임도밀도에 해당 + +되는 모든 노선을 임도망으로 편성하며 각 임도간의 상대적인 타당성, 경제성 및 문제점의 크기에 따라 우선순위와 투자계획을 수립한다. + +- ② 단기 계획 해당 노선 또는 구간을 대상으로 하는 5년 이내의 계획기간으로서 사업실행을 주목적으로 하 + +는 타당성 조사가 이에 해당한다. + +- ③ 시공 계획 공사실행을 위한 개별 사업계획으로 계약서류와 공사설계도·서 작성을 위한 실시설계가 이 + +에 해당된다. + +### 가. 임도망 +#### 1) 임도망 계획시 검토사항 + +임도의 계획은 임도를 매개체로 통행되는 교통류와 개발되는 유역에 활동요인을 부과하는 것이므로 통행의 목적, 개발목적, 자연경관, 지형, 작업조건 및 사회적 환경조건과 조화를 이룰 수 있도록 하여야 한다. 따라서 각각의 노선을 결정하고 평가를 할 경우에는 각각의 대안노선에 대하여 사회적, 경제적, 기술적 요인 등 세가지 측면에서 검토하고 그 결과에 따라 가장 적정한 노선을 선정한다. + +##### 가) 사회적 요인 + +다음 항목을 충분히 조사하여 관계기관과 협의·조정하고 지역주민의 의견도 수렴한다. +- ① 산림경영의 현황과 금후계획 예측 +- ② 도시집락, 촌락, 경작지와 관계(노선통과에 따른 분석) +- ③ 주택, 식수 등의 주거환경과 관계(접근에 의한 소음, 오염 등의 피해, 경관저해 등의 환경 문제) +- ④ 유적, 매장문화재, 절, 묘지 등 민족유산과 관계(통과에 의한 파괴) +- ⑤ 자연경관, 자연생태계와 관계(자연환경의 파괴) +- ⑥ 자연조건의 변화(수리, 기상의 변화에 따른 수해, 냉해 등) +- ⑦ 지역의 장래 계획과 관계(타 개발사업계획 검토) +##### 나) 경제적 요인 + +임도계획의 타당성 여부를 공사비와 유지관리비 등의 투자적인 측면과 그 투자에 따라 얻어지는 경제적인 편익에 대해서 계량적으로 평가·검토한다. + +- ○ 개략 계획 단계에서 경제적 요인 검토 +- ① 노망 전체 또는 개개노선에 대해서 경제성 여부를 따져서 경제적 타당성을 판단한다. +- ② 편익에는 집·운재비 감소, 통근시간 단축, 임산물의 가치성 향상 등의 직접적인 편익과 주변지역에 미치는 영향 등의 간접적인 편익으로 구분한다. +- ○ 기본 계획 단계에서 경제적 요인 검토 +- ① 임도망 계획으로 설정된 각각의 노선 또는 하나의 노선내에 일부구간에 대한 비교노선이 있는 경우와 시점, 종점의 설치위치 등에 대하여 경제적 평가를 하거나, 주요구조물의 기본형식에 대해서도 공사비와 유지관리비 등의 경제성을 검토한다. +- ② 비교노선이 비교적 길어서 각 구간에 대한 이해관계가 다를 경우에는 각각에 대한 평가가 필요하다. 특히 장거리 노선의 통과위치가 다를 경우에는 개략계획과 마찬가지로 간접적인 편익과 그 이외의 사회적 효과도 포함하여 검토한다. +- ○ 실시 설계 단계에서 경제적 요인 검토 +- - 선형과 도로구조물의 설계에 대한 공사비와 유지관리비를 비교하는 것이 주체가 되는 것으로 기본계획 등에서 검토된 경제성 분석의 내용을 최종적으로 확인한다. +##### 다) 기술적 요인 +- ○ 교통 기술적 요인 교통의 안전성과 원활한 이동성의 관점에서 다음과 같이 검토 평가한다. +- ① 지역도로망의 연계성 검토 : 지역도로망으로서 적합성, 시·종점 교통처리방안, 병목현상(Bottle Neck) 방지 등을 검토한다. +- ② 설계속도와 선형설계의 검토 : 일정구간에 대한 동일한 설계속도의 적용이 가능한 선형, 직진성(Directness) 등을 검토한다. +- ③ 집재장, 회전장, 대피소 등의 검토 : 집재작업 등 산림작업의 수행 중 차량교행, 지체 등으로 인하여 교통이 지체되거나 중단되는 일이 없도록 간격과 구조를 검토한다. +- ④ 교통용량 및 활용수준을 분석한다. +- ○ 구조 기술적 요인 시공성과 안전성 및 유지관리상의 문제점을 다음과 같이 검토 평가한다. +- ① 지질, 토질 등 자연조건 : 시공중 또는 시공후의 유지관리측면을 고려하여 재해우려지역, 단층·파쇄대지역, 벼랑(Cliff, Bluff)지대, 대규모 절토지, 연약지반, 깊은 계곡부 등의 통과 여부를 검토한다. +- ② 하천, 큰 계곡의 도하지점 : 수리, 수문, 지질, 하폭, 여울목 등을 고려한다. +- ③ 타 도로 및 철도와의 접속 : 교차부의 선형 및 가시거리 등을 검토한다. +- ④ 대능선의 통과 : 우회, 절개 등에 대한 비교 검토를 실시한다. +- ○ 작업적 요인 작업성 및 활용성을 다음과 같이 검토 평가한다. +- ① 설치 위치 : 활용가능 자동차 및 기계장비의 종류, 작업방법 등을 검토한다. +- ② 산림생산성 향상성 : 지형(경사도, 기복도 등), 임상, 경급, ha당 재적 등을 검토한다. +#### 2) 노선 계획시 검토사항 + +노선계획은 임도계획의 기초를 이루는 가장 중요한 단계로서 당해노선이 통과하게 될 유역의 입지환경과 경제효과, 교통 및 구조기술상의 특질, 경제성 등의 요구조건에 가장 부합되도록하기 위한 과정으로서 개략계획-기본계획-실시설계의 순서로 실행된다. + +##### 가) 개략 계획 +- ① 개략계획은 임도망계획에서 구상된 어느 한 노선에 대한 현지 노선선정작업의 준비단계로서 1/50,000 또는 1/25,000 지형도에 주요 지역도로망과 구역내로 통과 또는 연접되는 농도, 마을도로, 경작지도로까지 확인하고 임산물의 반출순로와 주변 교통체계상의 특성을 비교·분석하여 각 노선의 통제점(Control Point)을 감안하는 예비노선대를 설정하고, 노선의 특성을 파악 분석하여 노선계획대를 결정한다. +- ② 평면선형은 설정된 설계속도에 대응하는 종단물매와 평면곡선반경 이상으로 설정될 수 있는지를 점검하여 볼 필요가 있다. 지형이 험준한 곳에서는 종단선형이 중요하므로 등고선의 높이를 읽어 종단계획도를 개략적으로 작성하여 개략적인 물매나 교량 설치위치와 길이, 토공의 난이도 등을 파악한다. +- ③ 각 노선별로 길이와 주요구조물이 확정되면 개략공사비를 산출하고 사회성, 경제성, 기술성 등을 종합평가하여 노선계획대를 결정하여 지형도에 디바이더를 이용하여 예비노선을 작도한다. +##### 나) 기본 설계 +- ① 개략계획단계에서 설정된 노선계획대에 따라 1/5,000 또는 1/1,200 지형도에서 예비노선에 대한 선형을 보다 세밀히 검토하여 공사비를 산출하고 경제성분석 등을 수행하여 최적노선을 결정한다. +- ② 지형도에 사회적조건과 자연적조건, 지질, 지역계획, 가옥, 묘지 등 각종 현황조사자료를 이용하여 세부적인 통제점을 표시하고, 평면선형을 그리고, 종단면도를 작성하여 종단선형의 상황에 따라서 평면선형을 수정한 후 평면도를 확정한다. 이렇게 입체적인 선형이 결정되면 100m마다 횡단면도를 작성하여 개략적인 임도를 설계한다. +- ③ 교량 등 주요 구조물의 규모와 대략적인 구조형식을 결정할 때에는 지질조사와 함께 시공상의 난이도를 검토하여 개략적인 공사비를 이 단계에서 적산한다. +- ④ 비교노선이 있는 경우에는 먼저 선형을 그려서 노선연장, 각종 지장물, 기하구조적 조건, 절·성토 높이 및 균형, 구조물 길이, 시공조건, 유지관리조건 등을 고려하여 2∼3개의 대안을 만들고, 공사비와 편익비 등을 계산하여 비교노선간의 우열을 판정한 후 최적노선을 결정한다. +##### 다) 실시 설계 + +기본설계의 결과를 기초로 통제점을 확인하고 각 구간마다 설계기준으로 제시된 기준에 맞게 설계한다. 중심선은 20m 간격으로 측점을 부설하여 체계적인 공사실행을 하기 위한 설계도·서를 작성하고, 용지폭을 결정하여 부지를 확정하며 공사비를 산정한다. + +### 나. 임도밀도 + +노망의 성숙도를 나타내는 양적지표로서 임도밀도(Forest Road Density)의 개념이 이용되고 있다. 이것은 산림의 단위면적당 임도연장(m/ha)으로 나타내며 산림의 개발정도와 사업의 집약 도를 나타내어 준다. 임도밀도를 산출하는 방법으로는 해석적인 방법과 경험적인 방법의 2가지로 크게 구분할 수 있다. 이들 두 방법의 공통점은 경제성을 기초하여 임업경영에 대한 지출을 최소화하는데 주안점을 두고 임도밀도를 산출하는 것이다. 일반적으로 임도밀도를 산출할 경우에는 구역내의 생산가능임지에 대한 면적만 적용하고 비생산임지의 면적은 제외시키며, 임도연장도 임업생산기능과 관계가 없는 산림구역외의 임도연장은 제외한다. 임도밀도는 기본임도밀도, 적정임도밀도, 임목생산 임도밀도, 노망시스템 임도밀도, 기계화 임도밀도 등 용도에 따라 여러가지로 산출하여 이용하고 있다. + +#### 1) 기본임도밀도 + +기본임도밀도(Minimum Forest Road Density)는 조림부터 수확까지 산림작업에 투입되는 노동 인력들이 작업장까지 왕복통근에 소요되는 보행경비, 즉 비생산노무경비를 임도시설에 전환하여 사회간접자본화하는 개념으로 Minami kata(南方)에 의하여 제창되었다. + +$$d_o=\sqrt{\frac{5\eta' C_wN_w}{V_wr_o}}$$ + +- $d_o$: 기본임도밀도(m/ha) +- $C_w$: 노동단가(원/hr) +- $N_w$: 조림부터 수확까지 투입 노동량(인/ha) +- $V_w$: 평균보행속도(km/hr) +- $r_o$: 임도개설비(원/m) +- $\eta'$: 보행우회계수(1.0∼1.5) + +(예제) $r_o=44,548$원/m, $C_w=5,000$원/hr, $\eta'=1.25$, $V_w=2$km/hr이고 노동투입량이 인공림 300인/ha, 천연림 200인/ha일 때: + +- ① 인공림: $d_o=\sqrt{(5\times1.25\times5,000\times300)/(2\times44,548)}=10.3\,\mathrm{m/ha}$ +- ② 천연림: $d_o=\sqrt{(5\times1.25\times5,000\times200)/(2\times44,548)}=8.4\,\mathrm{m/ha}$ +#### 2) 적정임도밀도 + +임도의 개설이 늘어감에 따라 임도밀도가 증가되어 집재비, 조재비, 관리비는 낮아지지만 임도개설비, 임도 유지관리비, 운재비는 증가한다. Matthews는 생산원가관리이론을 적용하여 임업 생산비 중에서 임도개설연장의 증감에 따라서 현격하게 변화되는 주벌의 집재비용과 임도개설 비의 합계를 가장 최소화시키는 적정임도밀도(Optimum Forest Road Density)와 적정임도간격(Optimum Forest Road Spacing)을 구명하였다. (그림 5-2-7)은 임도개설비와 집재비용의 합계 + +![임도계획_그림5-2-7_적정임도가격산출모식도](<../pic/임도계획_그림5-2-7_적정임도가격산출모식도.png>) + +합계비용 비용에 대한 손익분기점(Break-even Point)을 나집 재 비m3당타내고 있다. 즉, 임도간격이 크게 되면 단위재적 비당의 임도비용은 감소하지만 집재거리가 길어져용(원/m + +- 3) 임도간격이 넓어지면 단위재적당 집재비용은 증가한다. 임도개설비와 집재비용의 합계는 임도간격이 지나치게 좁거나 넓으면 증가하며, 어느 한 지점에서 최소가 된다. 이 지점이 적정임도간격이다. Matthews는 임도우회율과 집재거리우회율 등을 고려하여 다음 식으로 산출하였다. + +여 적정임도밀도를 산출하였다. + +$$d=\sqrt{\frac{VE\eta\eta'}{r}}$$ + +- $d$: 적정임도밀도(m/ha) +- $r$: 임도개설비(원/m) +- $E$: 집재비(원/m/m³) +- $V$: 생산예정재적(m³/ha) +- $\eta$: 임도우회계수(1.0∼2.0) +- $\eta'$: 집재우회계수(1.0∼1.5) + +기계화 집재장비를 사용할 경우 집재비는 $E=(c\,t\,1,000)/L$로 산출한다. 여기서 $c$는 장비운영비(원/분), $t$는 작업왕복시간(분/m), $L$은 장비의 평균적재량(m³)이다. + +(예제) 평균 임목축적 183m³/ha에 벌채율 70%, 조재율 80%를 적용하면 원목생산예정량은 $183\times0.7\times0.8=102.5$ m³/ha이다. 임도개설비 44,548원/m, 집재비 320원/m/m³일 때: + +$$d=50\sqrt{\frac{102.5\times320\times1.5\times1.25}{44,548}}=58.7\,\mathrm{m/ha}$$ + +※ 임목축적 증가에 따른 적정임도밀도의 변화: 그림 5-2-8과 같이 경북 봉화 소재 국유림과 광릉시험림을 대상으로 경제성을 감안한 ha당 임목축적별 적정임도밀도를 산출한 결과, 임목축적이 46, 60, 100, 150, 200m³/ha로 증가함에 따라 적정임도밀도는 각각 7.7, 10, 16, 23, 29m/ha까지 증가하는 것으로 나타났다. 임목축적이 60m³/ha가 될 때까지는 기본임도밀도인 10m/ha로 가능하지만, 그 이상 증가하면 적정임도밀도 수준까지 계획적으로 설치하여야 한다. + +![임도계획_그림5-2-8_ha당임목축적별적정임도밀도](<../pic/임도계획_그림5-2-8_ha당임목축적별적정임도밀도.png>) + +그림 5-2-8. ha당 임목축적별 적정임도밀도 + +#### 3) 지선임도밀도(Feeder Road Density) + +입지조건에 따라서 집재방법과 운재시스템이 다르기 때문에 임도의 효율성을 계수로서 정하고 이 계수와 현실적으로 그 산림에 적용될 수 있는 집재장비의 최대집재거리로서 경험적인 임도밀도를 산출하는 방법이다. D = a / s여기서, D : 지선임도밀도(m/ha) s : 평균집재거리(㎞)a : 임도효율계수 + +| 구 분 | 임도효율계수 | 구 분 | 임도효율계수 | +|---|---|---|---| +| 기복이약간있는평지 | 4∼5 | 경 사 지 | 7∼9 | +| 구 릉 지 | 5∼7 | 급 경 사 지 | 9 이상 | + +(예제 1) 경사지에서 트랙터 평균집재거리가 500m일 때 지선임도밀도는 $D=8/0.5=16$m/ha이다. + +(예제 2) 구릉지에서 임도밀도가 20m/ha일 때 적합한 집재장비의 평균집재거리는 $6/20=0.3$km, 즉 300m이다. + +#### 4) 기설임도의 임도밀도(Existing Road Density) 산정 + +$$D(\mathrm{m/ha})=\frac{\text{시설거리}(\mathrm{m})}{\text{구역 산림면적}(\mathrm{ha})}$$ + +(예제) 광릉시험림 내 1996년 말 임도시설거리가 45km이고 산림면적이 2,218ha이면 $D=45,000/2,218=20.3$m/ha이다. +#### 5) 임도간격, 집재거리, 평균집재거리의 산출 +##### 가) 적정임도간격의 산출 + +$$ORS=200\sqrt{\frac{RC}{Q\cdot EC}}$$ + +- $ORS$: 적정임도간격(m) +- $RC$: 임도개설비(원/m) +- $EC$: 집재비(원/m/m³) +- $Q$: 원목생산예정량(m³/ha) + +(예제) $RC=44,548$원/m, $EC=320$원/m/m³, $Q=183$m³/ha일 때 $ORS=200\sqrt{44,548/(183\times320)}\fallingdotseq174$m이다. +##### 나) 적정임도밀도에서 임도간격의 산출 + +$$RS=\frac{10,000}{ORD}$$ + +여기서 $RS$는 임도간격(m), $ORD$는 적정임도밀도(m/ha)이다. $ORD=58.7$m/ha이면 $RS=10,000/58.7=170.4$m이다. +##### 다) 적정임도밀도에서 집재거리(Skidding Distance)의 산출 + +$$SD=\frac{10,000/ORD}{2}=\frac{5,000}{ORD}$$ + +(예제) $ORD=58.7$m/ha이면 $SD=5,000/58.7=85.2$m이다. +##### 라) 적정임도밀도에서 평균집재거리(Average Skidding Distance)의 산출 + +$$ASD=\frac{10,000}{4ORD}=\frac{2,500}{ORD}$$ + +여기서 $ASD$는 평균집재거리(m), $ORD$는 적정임도밀도(m/ha)이다. + +(예제) $ORD=58.7$m/ha일 때 $ASD=2,500/58.7=42.6$m이다. + +【참고】임도간격, 집재거리, 평균집재거리의 관계 +- ① 임도간격은 임도와 임도사이의 거리로 표현된다. +- ② 집재거리는 양쪽의 임도에서 서로 집재작업이 실행되므로 평지림의 경우 임도간격의 1/2이 된다. +- ③ 평균집재거리는 임도변의 집재작업(최소집재거리)과 집재한계선(최대집재거리)까지 집재작업이 동일하게 실행되므로 평지림의 경우 집재거리의 1/2이 되고 임도간격의 1/4이 된 +- 다. +- ④ 기본 계산식은 평지림을 기준으로 정립된 것이므로 산악지에 적용할 경우에는 임도와 집 재우회계수(η, η′)를 계상하여야 한다. +##### 마) 지형조건별 임도간격 + +표 5-2-9. 오스트리아의 경험적 임도간격 + +(단위:m) + +| 산지경사 | 지 형 | 집 재 방 법 | 산림경 영규모(ha) | | | +|---|---|---|---|---|---| +| | | | 대 규 모 | 중 규 모 | 소 규 모 | +| | | | (2,000이상) | (200∼2,000) | (200이하) | +| 0∼15% | 평탄지 | 차량형집재기 상·하향집재 | 500∼600 | 400∼500 | 300∼400 | +| 15∼30% | 구릉지 | 차량형집재기 상·하향집재 | 500 | 300∼400 | 300 | +| 30∼60% | 구릉지 산악지 | 차량형집재기(집재로이용) 가선에의한상향집재 중력에의한하향집재 | 300∼400 | 300 | 200∼250 | +| 60% 이상 | 험준지 | 가선에의한상향집재 중력에의한하향집재 | 500 | 300∼400 | 300 | +| * 자료: Sedlak (1985, 1987) | | | | | | + +### 다. 임도규격과 비용 +#### 1) 적정임도규격(Optimum Road Standard)의 산출 + +$$ORST=\sqrt{\frac{Q\cdot L}{K}}$$ + +- $ORST$: 적정임도규격(km/hr) +- $Q$: 임도교통 운재량(m³) +- $L$: 트럭의 시간당 비용(원/hr/대) +- $K$: 트럭속도를 1km/hr 높이는 데 필요한 임도개설비 증가액(원/km) + +(예제) $Q=500\times102.5=51,250$m³, $L=7,750$원/hr, $K=1,000,000$원/km이면 $ORST=\sqrt{(51,250\times7,750)/1,000,000}\fallingdotseq20$km/hr이다. +#### 2) ㎥당 소요 임도비용(road cost)의 산출 +##### 가) 임도밀도가 적정치일 경우 + +R·ORD·(1+η)·(1+η′)RC =1,000V 여기서, RC : 임도비용(원/㎥) R : 임도개설비(원/km)ORD : 적정임도밀도(m/ha) V : 원목생산예정량(㎥/ha) +##### 나) 임도밀도가 적정치가 아닐 경우 + +$$RC=\frac{R\cdot RD\cdot(1+\eta)\cdot(1+\eta')}{1,000V}$$ + +여기서 $RD$는 실제 임도밀도(m/ha)이다. + +(예제) 앞 예제의 조건에서 $RC=(44,548,000\times58.7)/(1,000\times120.5)\fallingdotseq25,512$원/m³이다. +### 라. 임도망 편성 +#### 1) 설치위치별 임도망 + +임도망을 계획하고자 할 경우에는 입지조건에 따라서 여러가지의 노망형이 있을 수 있지만 다음과 같은 사항을 착안하여 합리적인 노망이 될 수 있도록 한다. + +- ① 항구성의 원칙 : 산림이 항구적으로 유지되는 것과 같이 임도도 항구적으로 유지될 수 있도록 견고하게 시설한다. +- ② 임지종속성의 원칙 : 입지에 따라서 평면선형, 종단선형, 횡단선형 등 여러 가지의 조건이 다르므로 국지적인 입지조건에 부합되도록 시설한다. +- ③ 다양성의 원칙 : 임업적·경제적 기능도 중요하지만 생태적, 환경적, 공익적인 기능도 함께 수용할 수 있도록 계획한다. +##### 가) 계곡임도형 + +임지는 하단부로부터 점차적으로 개발하는 것이 일반적이므로 계곡임도는 임지개발의 중추적인 역할을 한다. 홍수로 인한 유실을 방지하고 임도시설비용을 절감하기 위하여 계곡하단부에 설치하지 않고 약간 위인 산록부의 사면에 최대홍수위보다 10m 높게 설치한다. 횡단사면은 항상 높은 지지력을 유지하여야 하므로 비교적 간단한 사면처리방법으로도 설치할 수 있는 곳이 바람직하다. 그림 5-2-9는 계곡부에 급경사면이 있어 쉽게 산록부나 산복부로 노선을 이동시킬 수가 없거나 계상의 물매가 너무 급하여 계곡을 따라 계속적인 노선선정이 불가능한 경우에 흔히 설치할 수 있는 형으로서 배향곡선(Hairpin Curve)을 설치하여 상류 쪽으로 계속 진행한다. 그림 5-2-10은 큰 지류가 있는 계곡부에서 흔히 설치할 수 있는 일반적인 형태로서 주계곡의 계상물매가 한계 종단물매 이내이고 지류를 우회하여 노선을 설치할 수 있는 곳이다. 그림 5-2-11은 편평한 주계곡을 따라 주임도에서 분기하는 지선(부)임도의 연결형이다. 그림 5-2-11의 ㉠형은 소계곡의 계상물매가 주계곡과의 연결부위 물매가 완만한 경우에 설치할 수 있고, ㉡형은 연결부위 물매가 급한 경우에 주계곡 상단부에서 배향곡선으로 우회하여 소계곡으로 진입하는 형태이다. + +![임도계획_그림5-2-9_급경사지역의계곡임도](<../pic/임도계획_그림5-2-9_급경사지역의계곡임도.png>) + +그림 5-2-9. 급경사지역의 계곡임도(사행형) + +![임도계획_그림5-2-11_편평한주계곡의계곡임도](<../pic/임도계획_그림5-2-11_편평한주계곡의계곡임도.png>) + +![임도계획_그림5-2-10_중경사지역의계곡임도](<../pic/임도계획_그림5-2-10_중경사지역의계곡임도.png>) + +그림 5-2-10. 중경사지역의 계곡임도 + +그림 5-2-11. 편평한 주계곡의 계곡임도 + +##### 나) 사면임도 + +사면임도는 계곡임도에서 시작되어 산록부와 산복부에 설치하는 임도로서 노선선정은 하단부로부터 점차적으로 계획하여 진행한다. 동일한 사면에서 부득이 배향곡선(Hairpin Curve)을 설치하여야 할 경우에는 가능한 한 그 수를 최소한으로 줄여야 한다. 왜냐하면 배향곡선을 설치하면 산림생산면적이 감소되어 임도의 이용율을 저하시킬 뿐만 아니라 토사유출을 유발하여 임지훼손의 원인이 되므로 가능한 한 경사도가 40% 이하되는 사면에 설치하되 동일사면에 1개 이상 설치하지 아니하도록 한다. (그림 5-2-12)는 산지의 사면이 발달되고 완경사 지형인 평활한 사면형태에서 흔히 설치할 수 있는 임도망형으로서 노선을 일정한 간격으로 배치하여 서로 연결할 수 있도록 배치한다. (그림 5-2-13)은 사면은 발달되어 있으나 경사도가 급하고 사면장이 긴 지형에 흔히 설치할 수 있는 노선형으로서 사행형으로 되는 임도망형이며 노선의 배치형태를 보면 주임도는 계곡부에서 배향곡선을 이용하여 산복부로 진행하고 부임도는 배향곡선의 가장자리에서 각각 분지하여 설치된다. + +![임도계획_그림5-2-13_급경사긴사면의사행형](<../pic/임도계획_그림5-2-13_급경사긴사면의사행형.png>) + +![임도계획_그림5-2-12_완경사지형의평형노망](<../pic/임도계획_그림5-2-12_완경사지형의평형노망.png>) + + +##### 다) 능선임도 + +능선임도는 축조비용이 적고 토사 유출도 적지만 가선집재방법과 같은 상향집재시스템에 의하지 않고는 산림을 개발할 수 없다. 능선임도에서 중력식 집재방법을 이용하는 한가지 방법은 (그림 5-2-14)와 같이 어골형의 형태로서, 능선임도에서 사면의 하향으로 완물매 또는 등고선물매로서 임도를 구축하는 것이다. 만약, 계곡의 기부가 늪(沼)이나 험준한 암석지대로 인하여 접근할 수 없거나 또는 능선에 부락이 위치하고 있을 때는 (그림 5-2-15)와 같은 능선임도를 구축할 필요가 있다. + +![임도계획_그림5-2-14_능선임도의어골형](<../pic/임도계획_그림5-2-14_능선임도의어골형.png>) + +간선 능선 + +![임도계획_그림5-2-15_능선임도형](<../pic/임도계획_그림5-2-15_능선임도형.png>) + + +##### 라) 산정부 개발형 + +산정부의 개발은 산정부 주위를 순환하는 노망을 설치하는 것이 적절하게 산림을 개발할 수 있는 방법으로 이용될 수 있는 경우가 많다. 산정부의 사면이 발달된 곳에서 (그림 5-2-16)과 같은 순환임도를 설치하여 하향 또는 가선에 의한 상향집재 방법으로 수확작업의 실행이 가능하며, 특히 상단부 사면이 발달한 반면에 중복 부의 사면경사도가 급한 곳에 흔히 설치할 수 있는 노망형이다. 이때 순환임도의 시점과 종점은 능선부에 있는 안부(鞍部, Saddle)가 가장 적당한 곳이 된다. + +![임도계획_그림5-2-16_산정부순환임도형](<../pic/임도계획_그림5-2-16_산정부순환임도형.png>) + +그림 5-2-16. 산정부 순환임도형 + +##### 마) 계곡분지의 개발형 + +산지 계곡부의 상류에 위치하는 막장부의 분지는 (그림 5-2-17)과 같이 순환임도망의 설치방법에 의하여 산림을 개발하는 것이 적정한 경우가 많다. 이때에 설치하는 임도의 물매는 너무 급하지 않아야 한다. (그림 5-2-17)의 ㉠형은 계곡기부의 사면이 발달되어 부채모양으로 펼쳐진 곳으로서 사면의 경사도가 완만하고 편평한 곳에서 흔히 설치할 수 있는 노망형이며, (그림 5-2-17)의 ㉡형은 ㉠형과 같은 지형조건으로서 사면의 길이가 길고 하단부의 경사도가 급한 곳에서 흔히 설치할 수 있는 노망형이다. + +##### 바) 반대편 능선부 산림개발형 + +동일유역에서 통상적인 노망으로는 임도건설비가 과다하게 소요 되어 경제적인 타당성이 없기 때문에 계곡임도를 개설할 수 없는 경우의 임지에 대하여는 산림에서 생산되는 임목을 상향 수송이 가능하도록 다른 사면에 개설된 임도의 안부를 경유하여 완물매(역물매로 설치됨 : 6%이하)의 임도를 개설하지 않으면 안된다. 이러한 경우에서는 (그림 5-2-18)과 같이 계곡의 발달이 거의 없거나, 늪(沼) 또는 암석 급경사지 등의 원인으로서 경제적으로 임도설치가 곤란한 지역에서는 반대편에서 생산된 임목을 사면임도를 통하여 안부(鞍部 : Saddle)를 넘어 역물매로서 수송하여야 할 필요가 있는 곳에서 흔히 설치될 수 있는 노망형이다. 계류 + +![임도계획_그림5-2-18_반대사면으로부터의임도이용형](<../pic/임도계획_그림5-2-18_반대사면으로부터의임도이용형.png>) + +계곡 능선 급경사암석지형 + +![임도계획_그림5-2-17_계곡분지의순환임도형](<../pic/임도계획_그림5-2-17_계곡분지의순환임도형.png>) + + +#### 2) 양각기 계획법(Divider Step Method)에 의한 도상 임도망 편성 +##### 가) 작업원리 +- ① 양각기의 1폭(S)을 임도의 영선(Zero Line)에 대한 수평거리(D)로 하고 등고선간격(1/25,000지형도 : 10m, 1/50,000지형도 : 20m)을 높이(h)로 간주하여 종단물매(G)를 산출한 후 지형도상에서 적정한 노선을 선정하는 노망계획방법이다. +- ② (그림5-2-19)에서 수평거리 100m에 대한 높이 p m 가 G % 라고 한다면 D : h = 100 : G 에서 D = 100·h / G 여기서, D : 양각기 1폭에 대한 실거리(m) h : 등고선 간격(m) G : 물매(%) ※도상거리(d) = 실거리(ℓ)÷축척의 분모수 + +![임도계획_그림5-2-19_양각기에의한물매설정](<../pic/임도계획_그림5-2-19_양각기에의한물매설정.png>) + +G%hP100D 그림5-2-19. 양각기에 의한 물매설정 + +- ③ 위 식에서 물매별 양각기의 1폭에 대한 실거리를 산출한 바 (표 5-2-10)과 같다. 표 5-2-10. 종단물매별 양각기의 폭(1/25,000지형도, 등고선간격=10m의 경우) + +| 종단물매 (G) | 실 거 리 (ℓ) | 도 상 거 리(d) | | | 종단물매 (G) | 실 거 리 (ℓ) | 도 상 거 리(d) | | | +|---|---|---|---|---|---|---|---|---|---| +| | | 1 폭 | ½ 폭 | ¼ 폭 | | | 1 폭 | ½ 폭 | ¼ 폭 | +| % 2 3 4 5 6 7 | m 500 333 250 200 167 143 | mm 20.0 13.3 10.0 8.0 6.7 5.7 | mm 10.0 6.7 5.0 4.0 3.3 2.9 | mm 5.0 3.3 2.5 2.0 1.7 1.4 | % 8 9 10 11 12 13 | m 125 111 100 91 83 77 | mm 5.0 4.4 4.0 3.6 3.3 3.1 | mm 2.5 2.2 2.0 1.8 1.7 1.5 | mm 1.2 1.1 1.0 | + +(예제) 1/25,000 지형도(등고선간격 ; 10m)에서 양각기 계획법으로 임도망을 편성하고자 한 + +- 다. 종단물매를 7%로 계획할 때 도상거리는 몇 m인가? (풀이) ① 실거리(ℓ) = (100×10) / 7 = 142.86m +- ② 1/25,000 지형도에서의 도상거리(d) = 142.86m/250 = 5.7mm +##### 나) 작업기준 +- ① 임산물은 근주로 부터 임도까지 직선거리로 가장 가까운 임도변에 집재되는 것으로 가정한다. +- ② 임도는 동일한 간격을 유지하고 평행하여 교차되지 아니하는 것으로 가정한다 +- ③ 임산물을 운송하기 위한 임도는 산림의 상단부에서 우회하여 계곡부로 내려오는 것이 정상이지만 급경사지 형에 설치되는 부임도는 능선에 설치될 수도 있다. +- ④ 일반적으로 임산물이 임도변까지 집재되는 과정은 집재비에 큰 영향을 미치기 때문에 상향, 하향 또는 양방향 등 집재방향을 먼저 검토하여야 한다. +- ⑤ 만약 가선이나 장비 등을 이용하는 집재방법으로 실행할 경우에는 실제 임목집재비 뿐만 아니라 그 장비투입비용도 포함하여 집재비용을 추정한다. +- ⑥ 임도는 가끔 임산물이나 노동력의 수송에 대한 편익 이외에도 또 다른 목적으로 이용될 수 있다. 예를 들면 산화관리, 수렵, 여행, 산촌주민의 편익 등으로서 이들의 편익을 금원화하기는 매우 어려울 것이나, 학자에 따라서는 이들 편익에 대한 대가로서 임도비용을 25∼50% 공제하거나 유지관리비를 부담하게 하기도 한다. +- ⑦ 임도의 시설이 주변환경을 해치게 될 경우에는 그 비용을 사정하여 임도비용에 부가할 수 임산물 운반을 고려한 일반적인 임도망은 산복을 완만하게 우회하면서 낮은 도 있다. 계곡부의 도로와 연결하는 것이 유리하다. 그러나 산복경사가 매우 급하면 부임도를 사면에 설치할 경우 절·성토와 붕괴위험이 커지므로, 지형조건에 따라 능선부에 부임도를 설치할 수도 있다. 이 경우 아래쪽 임목은 가선 등을 +##### 다) 작업방법 + +이용하여 능선임도로 상향집재해야 한다. +- ① 지형도(1/25,000, 1/5,000)를 준비하여 계획구역을 설정하고 생산임지와 비생산임지를 구분한 후 주요 사업계획지, 주교통방향이나 임목의 반출순로 등을 도시한다. +- ② 노선의 통제점(control point) 즉 유리점(시점, 종점, 배향곡선 설치가능지, 안부, 여울목 +##### 등) 과 불리점(늪, 불안정된 사면, 암석지, 홍수범람지, 소유경계 등) 및 역물매 지역을 도 + +시한다. +- ③ 각 노선에 대한 예비노선을 ①과 ②의 사항과 노선의 특성을 파악 분석하여 계획노선대를 도시한다. +- ④ 양각기의 폭(s)을 (표 5-2-10)을 참고하여 지형도의 축척에 알맞게 조정한다. 이때 양각기 1개로서 상황에 따라 조정 사용하면 오차의 발생이 크므로 5∼6개의 양각기를 준비하여 사용이 빈번한 물매에 해당되는 것은 그 폭을 고정시켜 사용하면 오차를 줄일 수 있으며 작업진행도 빠르고 편리하다. +- ⑤ 시점부와 종점부의 결정은 대단히 중요하므로 기설도로에 대한 절·성토사면형태, 평면선형 등에 대한 현지조건을 검토하고, 시점으로 부터 계획코자 하는 물매로 경유하여야 할 유리점은 통과하고 피하여야 할 불리점은 피하면서 한폭 한폭씩 (그림 5-2-20)과 같이 진행한다. + +![임도계획_그림5-2-20_양각기사용예](<../pic/임도계획_그림5-2-20_양각기사용예.png>) + +그림 5-2-20. 양각기 사용(예) + +- ⑥ 굴곡이 심한 지형에서는 계곡과 능선을 건너 뛰면 우회율이 너무 커져서 도상거리와 실거리의 오차가 커지므로 양각기의 폭을 (표 5-2-10)의 우단과 같이 1/2폭 또는 1/4폭으로 조정 작업하고, 등고선의 간격이 조밀하여 작업이 어려운 경우에는 확대경을 사용하면 편리하다. +- ⑦ 이와 같이 작업하여 통과 목표지점에 도달되지 아니하였거나 불리점을 피하지 못하여 노선의 계획이 미흡할 경우에는 그 구간 또는 전노선을 선형이 적정하게 될 때까지 되풀이하여 실행한다. +- ⑧ 이와같은 작업이 완료되면 작업과정을 노선별 내역서(표 5-2-11)에 기재하고 임도망 계획도(그림 5-2-21)에 도시한다. + +| 범 례 | | +|---|---| +| | 시험림경계 | +| | 기설임도 | +| | 시설계획 | +| | 지 방 도 | + +| 번호 | 노선명 | 연장 (km) | 비 고 | +|---|---|---|---| +| 1 1-1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 육림로 (관찰로) 장현로 수목원로 소리로 능내로 음현로 접동로 직동로 마명로 장승로 거목로 평화로 폭포로 천참로 소리2로 용암로 민락로 안말로 | 6.7 1.1 3.3 2.8 3.8 3.4 2.0 4.1 5.5 7.7 3.3 1.8 2.2 1.7 3.1 7.3 3.4 1.9 0.8 | '65-'66시설 '90시설 기설운재로개수 '83시설 '82-'85시설 '84시설 '85시설 '85-'86시설 '87-'89시설(4.5km) '90-'91‘,95시설 '91시설 '92,'94시설 '91-'92시설(4.1km) | +| 계 | | 65.9 | (30m/ha) | +| 시 설 | | 44.8 | (20m/ha) | +| 계 획 | | 21.1 | (10m/ha) | + +![임도계획_그림5-2-21_임도망계획도](<../pic/임도계획_그림5-2-21_임도망계획도.png>) + +그림 5-2-21. 임도망계획도(예:광릉시험림) + +표 5-2-11. 노선별 내역서(예:광릉시험림) + +| 임 도 명 | 임반 번호 | 임도 종류 | 임도표고 | | | 구 간 | | 임도 연장 (km) | 비 고 | +|---|---|---|---|---|---|---|---|---|---| +| | | | 시점 | 최고점 | 종점 | 거리 | 종단물매 | | | +| | | | (m) | (m) | (m) | (m) | (%) | | | +| 직동로 계 | 11, 12 | 2급 | 500 | 570 | 570 | 770 200 970 | 9 5 | 0.97 | 직동로'89 시설분종점에서 마명로종점(죽엽산안부) | +| 마명로 계 | 1∼8 | 2급 | 210 | 570 | 570 | 170 200 2,760 1,820 200 5,150 | 3 5 7 9 5 | 5.15 | 접동로정상에서분지 직동로종점(죽엽산안부) 연결 | +| 거목로 계 | 26-29 | 2급 | 160 | 170 | 135 | 330 1,330 165 1,825 | 3 - 3 3 | 1.83 | 능내로에서분지 장승로와연결 | +| 평화로 계 | 38-40 45 | 2급 | 120 | 160 | 120 | 1,170 1,000 2,170 | 3 - 3 | 2.17 | 소리로에서분지 육림로와연결 | +| 폭포로 계 | 45 50-51 | 2급 | 200 | 200 | 80 | 1,720 1,720 | - 7 | 1.72 | 천참로에서분지, 장현로와연결 | +| 소리2로 계 | 43 46-49 | 2급 | 385 | 420 | 240 | 700 400 1,330 770 3,200 | 5 - 9 - 5 - 9 | 3.20 | 소리봉아래에서연장 천참로와연결 | +| 용암로 계 | 58-59 42 58-62 | 2급 | 380 | 380 | 270 | 1,000 430 670 1,330 3,430 | - 3 - 7 9 - 9 | 3.43 | 소리로에서분지 용암리지방도와연결 | +| 민락로 계 | 33, 35 57 | 2급 | 300 | 340 | 340 | 570 1,320 1,890 | 7 3 | 1.89 | 육림로에서분지 민락동상단부 | +| 안말로 계 | 30-31 | 2급 | 140 | 170 | 160 | 570 200 770 | 7 - 5 | 0.77 | 육림로에서분지 안말상단부 | +| 합 계 | | | | | | | | 21.13 | | + +#### 3) 현지의 노선부설(Forest Road Alignment) 및 수정 +##### 가) 작업기준 + +도상계획에 의한 각 임도노선은 현지조사(답사, 예측)에 의하여 현지의 국지적인 입지조건에 부합되도록 수정한다. 이는 개개 노선에 대한 세부계획을 정확하고 자세하게 수립하므로서 측량·설계 작업을 보다 신속하고 편리하게 수행할 수 있게 한다. 따라서 노선계획을 적정하게 수행하여 합리적인 노선을 배치하기 위하여는 노선의 측량작업을 현지에서 직접 실행하는것 보다 도상계획에 의한 개략계획을 먼저 실행한 후 측량작업에 임하는 것이 훨씬 경제적이고 효과적이다. + +##### 나) 작업방법 +- ① 임도망 계획도·서, 고도계(Altimeter), 경사측정기(Clinometer), 표지테이프(MarkingTape), 줄자, 표지판(Clinometer Target), 지지봉(Clinometer Rod) 등을 준비한다. +- ② 구역이 너무 크면 효율적인 작업이 될 수 없으므로 작업이 가능할 정도의 소구역으로 분할하여 작업조별로 세부일정을 수립하며, 차량, 헬리콥터, 측정기구 등의 필요한 장비를 준비한다. +- ③ 노선내 주요 설치물(집재장, 배향곡선, 교량 등)의 설치가 가능한 완경사 지형, 안부, 여울목 등의 유리지점과 불리지점에 대한 현지 부합 상태를 조정하여 불합리한 선형은 수정한다. +- ④ 도상의 계획노선을 현지 지형상에 정확한 지점을 찾아 부설하는 식으로 작업하지 말고, 현지 지형에 따라서 적정하게 설치될 수 있는 노선을 우선하여 도상의 불합리한 계획노선을 수정한다는 생각으로 작업한다. +- ⑤ 노선은 가능한한 자연지형에 순응되도록 하되 토공량이 적고 절토량과 성토량이 짧은 구간내에서 균형이 이루어지도록 한다. +- ⑥ 최소 곡선반지름, 최소 및 최대 종단물매 등의 일정한 제한치를 정하고 그 범위내에서 작업하되, 가능한 한 종단물매가 완만하고 배수가 완전히 되도록 한다. +- ⑦ 노선의 부지는 구입조건이나 가격의 차이가 있으므로 가능한한 부지확보에 지장이 없도록 적정하게 노선을 선정하고 산간부는 가급적 양지쪽을 선택한다. +- ⑧ 표고상 계속 상향물매로 설치하여야 할 종단선형 구간에 하향물매 구간을 설치하거나 반대로 하향물매로 설치하여야 할 구간에 상향물매 구간을 가급적 설치하지 않는다. +- ⑨ 계곡을 건너야 할 경우에는 최대 홍수시에 범람이 되어도 하류쪽 노면이 유실되지 않도록도하구간에 凹형의 종단물매를 설치하여 그 구간내에서 유수단면적이 확보 되도록 한다. +##### 다) 세부작업방법 및 조정 +- (4) -(라)-3)-마)의 제1단계 작업과 제2단계 작업을 참고한다. +#### 4) 임도망계획서 작성 + +임도망이 편성되면 임도망계획서를 작성하여야 한다. 이 계획 안에는 임도계획시에 조사 분석한 내용과 임도망 편성시에 작성한 다음과 같은 사항을 포함하여야 한다. 또한 사항에 따라서 관계기관과 협의하여야 할 것이 있을 경우에는 사전에 협의하여 작성한다. + +- ① 사회적 요인 +- ② 경제적 요인 +- ③ 기술적 요인 +- ④ 작업적 요인 +- ⑤ 기본임도밀도 및 적정임도밀도의 산정 +- ⑥ 노선별 내역서 +- ⑦ 임도망의 평가내역 +- ⑧ 임도망 계획도 +- ⑨ 기타 관계되는 자료 +### 마. 임도망 평가 +#### 1) 연산작업 기초 +- ① 먼저 적당한 격자(Mesh)크기(100m×100m, 50m×50m 등)의 수치지형도(Digital TerrainModel)를 작성한다. +- ② 수치지형도의 인자는 표고, ha당 축적, 임상, 영급 등을 관련자료(산림조사부, 영림계획서 +##### 등) 에 의하여 격자내에서 평균값을 산출하여 작성한다. +##### 가) 생산예정재적의 산출 + +$$BV=\frac{V\cdot BR\cdot CR\cdot B}{10,000}$$ + +- $BV$: 생산예정재적(㎥/ha) +- $V$: 축적(㎥/ha) +- $BR$: 조재율 +- $CR$: 벌채율 +- $B$: 단위면적(㎡) + +(예제) 축적 498㎥/ha, 벌채율 100%, 조재율 90%, 단위면적 10,000㎡이면 $BV=498\times0.9\times1.0\times10,000/10,000=448.2$㎥/ha이다. +##### 나) 집재거리의 산출 + +집재거리는 임목이 서 있는 지점에서 임도변 집재장까지의 최단 직선거리로 한다. + +$$X_{ab}=B\sqrt{(I-M)^2+(J-N)^2}$$ + +- $X_{ab}$: a, b 간 집재거리(m) +- $I,J$: 임목이 서 있는 지점의 행·열 +- $M,N$: 임도변 집재장의 행·열 +- $B$: 격자간격(m) + +그림 5-2-22. 격자 설치 모형 + +(예제) 격자간격($B$)이 100m인 정방형 격자지에서 점 $a=(10,5)$의 임목을 점 $b=(6,7)$의 임도변까지 집재할 때 $X_{ab}=100\sqrt{(10-6)^2+(5-7)^2}=447.2$m이다. + +##### 다) 종단물매의 산출 + +$$G=\frac{E_{IJ}-E_{MN}}{L}\times100$$ + +(예제) 점 $c=(6,3)$의 표고가 227m, 점 $d=(5,6)$의 표고가 200m이고 격자간격이 100m이면 $L=100\sqrt{(6-5)^2+(3-6)^2}\fallingdotseq316.2$m이다. +- ② 종단물매(G) = (227-200)×100/316.2 ≒ 8.54% +##### 라) 집재작업량의 산출 + +$$W=BV\cdot CX\cdot G\cdot\eta'$$ + +여기서 $W$는 작업량(㎥·m), $BV$는 생산예정재적(㎥), $CX$는 집재거리(m), $G$는 지형조건에 따른 작업가산율(1.0∼1.2), $\eta'$는 집재우회율(1.0∼1.5)이다. + +(예제) $W=448.2\times447.2\times1.1\times1.2=264,574.3$㎥·m이다. +##### 마) 집재비의 산출 + +$$SC=a\sum W+b\sum V$$ + +여기서 $a$는 집재거리에 비례하는 유동비(원/m/㎥), $b$는 고정비(원/㎥), $W$는 작업량(㎥·m), $V$는 생산예정재적(㎥)이다. + +(예제) $SC=10\times264,574.3+3,500\times448.2=4,214,443$원이다. +##### 바) 임도비의 산출 + +$$RC=C\sum R\cdot\eta$$ + +여기서 $C$는 임도단가(원/m), $R$은 임도연장(m), $\eta$는 임도우회율(1.0∼2.0)이다. + +(예제) 계획거리 408km, 임도단가 52,400천원/km, 임도우회율 1.25이면 $RC=52,400\times408\times1.25=26,724,000$천원이다. +##### 사) 총비용의 산출 + +$$TC=\sum SC+\sum RC$$ +##### 아) 가중평균 집재거리의 산출 + +$$ASD=\frac{\sum(CX\cdot V)}{\sum V}$$ +##### 자) 산술평균 집재거리의 산출 + +$$ASD=\frac{\sum CX}{N}$$ +##### 차) 집재거리 표준편차의 산출 + +$$SD=\sqrt{\frac{\sum(CX-ASD)^2}{N-1}}$$ + +집재거리의 표준편차가 작을수록 임도가 계획구역 내에 균일하게 배치되어 임도망의 효율성이 좋아진다. + +| 행 | 열 | 집재예정재적(㎥) | 집재거리(m) | CX·V | (X - ASD)2 | +|---|---|---|---|---|---| +| 257 | 216 | 127 | 100 | 12,700 | 5,055.2 | +| 258 | 217 | 122 | 125 | 15,250 | 2,125.2 | +| 259 | 218 | 87 | 276 | 24,012 | 11,004.0 | +| 260 | 219 | 87 | 255 | 22,185 | 7,039.2 | +| 261 | 220 | 150 | 105 | 15,750 | 4,369.2 | +| 262 | 221 | 150 | 182 | 27,300 | 118.8 | +| 263 | 222 | 65 | 202 | 13,130 | 954.8 | +| 264 | 223 | 92 | 170 | 15,640 | 1.2 | +| 265 | 224 | 55 | 125 | 6,875 | 2,125.2 | +| 계 | | 935 | 1,540 | 152,842 | 32,792.8 | +| 평 균 | | 103.9 | 171.1 | | | + +(풀이) ① 가중평균집재거리: $ASD=152,842/935=163.5$m + +- ② 집재거리 표준편차: $SD=\sqrt{32,792.8/(9-1)}=64.0$m +#### 2) 개발지수 + +개발지수는 임도의 질적 기준과 배치효율을 나타내는 지표이다. + +$$I=\frac{ASD\times FRD}{2,500}$$ + +여기서 $I$는 개발지수, $ASD$는 평균집재거리(m), $FRD$는 임도밀도(m/ha)이다. 임도가 이론적으로 균일하게 배치되면 $ASD\times FRD=2,500$이므로 개발지수는 1.0이다. 그림 5-2-23의 ①·②처럼 균일하면 이용효율성이 높고, ④·⑧처럼 노선이 중첩될수록 이용효율은 각각 31%, 50% 정도 저하한다. 따라서 임도간격과 밀도가 같더라도 노망의 배치상태에 따라 이용효율은 크게 달라진다. + +![임도계획_그림5-2-23_노망배치형태별개발지수](<../pic/임도계획_그림5-2-23_노망배치형태별개발지수.png>) + +그림 5-2-23. 노망배치 형태별 개발지수 + +#### 3) 경제성 분석 + +공공투자사업의 경제성평가는 계획 또는 검토되고 있는 대안들의 비용과 편익을 분석하여 경제적 효율성과 공공투자의 당위성을 검토하는 것이다. 임도교통에 소요되는 비용은 임도비와 임도사용자비용으로 구별된다. 임도사용자비용은 임도 관리청이 임도구조·규격을 향상시키기 위하여 임도비를 많이 투자하면 할수록 임도사용자가 차량을 운행하는데 지출되는 연료비, 오일비, 타이어비, 수선비 등의 임도사용비용이 그만큼 절감될 것이다. 이때 그 절감액을 편익(Benefit)이라 한다. ※ ㉠ 비용항목 : 임도비로서 조사·계획비, 설계비, 보상비, 유지관리비 및 임도운영비로구성되며, 이들 항목은 과거의 경험치나 개략설계 결과로부터 산출한다. ㉡ 편익항목 : 임도사용자비용은 이를 다시 차량운행비(Vehicle Operating Costs)와 시간비(Time Cost) 및 작업방법개선비로 구분할 수 있다. RTC = RC + RUC 여기서, RTC : 임도운송비(Road Transportation Costs)RC : 임도비(Road Costs)RUC : 임도사용자비용(Road User Costs)경제성 분석의 궁극적인 목적은 임도운송비를 최소한으로 줄일 수 있는 대안을 설정하는 것이라고 할 수 있다. 차량 1대당의 임도비와 임도사용자비용을 (그림 5-2-24)에서 보면 임도비는 초기투자비(건설 + +##### 비) 가 대부분이기 때문에 시간의 경과에 따라 변동이 거의 없으므로 이를 고정비(Fixed Cost)로 + +볼 수 있으므로 운반량이 많을수록 ha당 임도비는 감소한다. 반면에 임도사용자비용은 시간이 경과함에 따라 점점 누증(累增)되는 변동비(Variable Cost)이기 때문에 ha당 임도사용자비용이 증가하게 된다. 따라서 임도운반비는 ha당 임도비와 생산량에 따라서 변화되며 어느 적정한계를 넘거나 모자라면 불리해진다. ha당 운반량이 많은 임도일수록 임도비보다 임도사용자비용이 임도운반비 중에 차지하는 비중이 높으므로 ha당 운반량이 많은 임도일수록 설계수준을 더 높게 책정할 수 있는 이론적 근거를 제시하여 준다. + +![임도계획_그림5-2-24_임도운반비의추정도](<../pic/임도계획_그림5-2-24_임도운반비의추정도.png>) + +그림 5-2-24. 임도운반비의 추정도 + +##### 가) 기본 자금 공식 + +임도운반비 중에서 임도비는 사업시행초기의 단기간 동안에 소요되는 것이지만, 유지관리비나 임도사용자비용은 개통후 장기간에 걸쳐 소요되므로 총소요비용을 기준연도의 금액으로 환산하거나 임도비를 내구연수 또는 건설기간 동안의 연간비용으로 환산할 필요가 있다. 이때 사용하는 환산법은 은행의 금전계산법과 같으며 일반적으로 다음과 같은 3가지 방법이 있다. + +- ○ 단순 지불(Single Payment)n 원리금 S로서 원금 P를 원금 P를 은행에 저금하여 이자율이 i 일 때 원리금 S = P·(1+i) + +구한다면 P = S / (1+i)n 이때 (1+i)n은 원금 P를 원리금 S로 환산하는 계수로서 원리금환산계수(CAF ; CompoundAmount Factor)라 하고, 1/(1+i)n은 원리금 S를 원금 P로 환산하는 계수로서 현재가격환산계수(PWF ; Present Worth Factor)라 한다. 즉, S = P × CAFsp,n,i P = S × PWFsp,n,i 여기서, sp : 단순지불 n : 기간 i : 이자율 + +- ○ 정기 불입 또는 적금(Sinking Fund)매 연말마다 정기적으로 일정금액 R을 적금형식으로 불입한다면 n-1 / i} +- ① 원리금의 합계 S = R × {(1+i)※ { }내는 원리금환산계수(CAF) +- ② 적금불입액 R = S × {i / (1+i)n-1}※ { }내는 적금액환산계수(SFF ; Sinking Fund Factor)따라서 S = R × CAFrp,n,i R = S × SFFn,i여기서, rp : 반복지불 n : 기간 i : 이자율 +- ○ 자본 회수(Capital Recovery) 또는 연금(Annuity)자본금 P를 불입한 후 매년마다 정기적으로 일정금액 R을 연금 형식으로 인출하여 n년 후에 + +잔고가 0이 되게 하는 경우 n-1 / {i·(1+i) + +- ① 자본금: $P=R\left\{\dfrac{(1+i)^n-1}{i(1+i)^n}\right\}=R\times PWF_{rd,n,i}$ +- ② 연금: $R=P\left\{\dfrac{i(1+i)^n}{(1+i)^n-1}\right\}=P\times CRF_{n,i}$ + +여기서 $rd$는 반복인출, $n$은 기간, $i$는 이자율이며 중괄호 안은 각각 현재가격환산계수(PWF)와 자본회수환산계수(CRF)이다. 3가지 은행거래방식에 따른 6가지 환산계수는 표 5-2-12와 같다. + +표 5-2-12. 복리환산계수표 + +| 이자율 $i$(%) | 기간 $n$ | CAFsp | PWFsp | CAFrp | SFF | PWFrd | CRF | +|---:|---:|---:|---:|---:|---:|---:|---:| +| 8 | 10 | 2.1589 | 0.4632 | 14.4866 | 0.0690 | 6.7101 | 0.1490 | +| 8 | 20 | 4.6600 | 0.2145 | 45.7620 | 0.0219 | 9.8181 | 0.1019 | +| 8 | 30 | 10.0627 | 0.0994 | 113.2832 | 0.0088 | 11.2578 | 0.0888 | +| 10 | 10 | 2.5937 | 0.3855 | 15.0374 | 0.0627 | 6.1446 | 0.1627 | +| 10 | 20 | 6.7275 | 0.1486 | 57.2750 | 0.0175 | 8.5136 | 0.1175 | +| 10 | 30 | 17.4494 | 0.0573 | 164.4940 | 0.0061 | 9.4265 | 0.1061 | +| 12 | 10 | 3.1058 | 0.3220 | 17.5487 | 0.0570 | 5.6502 | 0.1770 | +| 12 | 20 | 9.6463 | 0.1037 | 72.0524 | 0.0139 | 7.4694 | 0.1339 | +| 12 | 30 | 29.9599 | 0.0334 | 241.3327 | 0.0041 | 8.0552 | 0.1241 | +| 15 | 10 | 4.0456 | 0.2472 | 20.3037 | 0.0493 | 5.0188 | 0.1993 | +| 15 | 20 | 16.3665 | 0.0611 | 102.4436 | 0.0098 | 6.2594 | 0.1598 | +| 15 | 30 | 66.2118 | 0.0151 | 434.7452 | 0.0023 | 6.5660 | 0.1523 | +| 17 | 10 | 4.8068 | 0.2080 | 29.3931 | 0.0447 | 4.6586 | 0.2147 | +| 17 | 20 | 23.1056 | 0.0433 | 130.0329 | 0.0077 | 5.6278 | 0.1777 | +| 17 | 30 | 111.0647 | 0.0090 | 647.4391 | 0.0015 | 5.8994 | 0.1715 | +| 20 | 10 | 6.1917 | 0.1615 | 25.9587 | 0.0385 | 4.1925 | 0.2385 | +| 20 | 20 | 38.3376 | 0.0261 | 186.6880 | 0.0054 | 4.8696 | 0.2054 | +| 20 | 30 | 237.3703 | 0.0042 | 1,181.8816 | 0.0008 | 4.9789 | 0.2208 | + +(예제 1) 연간 유지관리비가 3백만원 절감되고 내구연수 10년, 이자율 10%일 때 공사비 한도는 다음과 같다. + +$$P=R\times PWF_{rd,10,10}=3,000,000\times6.1446=18,433,800\text{원}$$ + +(예제 2) 포장비가 350백만원이고 내구연수 10년, 이자율 15%일 때 필요한 연간 임도사용자비용 절감액과 최소 교통량은 다음과 같다. + +$$R=P\times CRF_{10,15}=350,000,000\times0.1993=69,755,000\text{원}$$ + +$$\text{교통량}=69,755,000\div1,000\div365\fallingdotseq191\text{대/일}$$ + +(예제 3) 2km 구간의 선형 개량으로 차량당 200원이 절감되고 교통량이 5,000대/일, 이자율이 15%, 내구연수가 무한대일 때: + +$$R=200\times5,000\times365=365,000,000\text{원/년}$$ + +$$PWF_{pp,\infty,15}=\frac{1}{i}=\frac{1}{0.15}=6.667$$ + +$$P=365,000,000\times6.667\fallingdotseq2,433\text{백만원}$$ + +(예제 4) 10년 거치 일시상환 임도공채 100억원, 공채이자율 10%, 은행이자율 8%일 때: + +$$S=P\times CAF_{sp,10,10}=10,000\times2.5937=25,937\text{백만원}$$ + +$$R=S\times SFF_{10,8}=25,937\times0.069=1,789.653\text{백만원}$$ + +##### 나) 경제성 분석방법 + +경제성분석방법으로 대표적인 것은 연간비용방법(Annual Cost Method), 현재가격방법(PresentWorth Method), 편익비용비방법(Benefit-Cost Ratio Method), 내부수익율방법(Internal Rate ofReturn Method)의 4가지를 들 수 있다. 이 때 경제성을 분석할 경우에는 임도투자를 전혀 하지 않고 현재의 상태를 그대로 유지하는 방안(Do-Nothing Alternative)도 하나의 대안으로 선정하여 다른 대안과 경제적 타당성을 비교하여야 한다. + +- ① 연간비용 방법 AC = (RC + RUC) × CRFn,i + M&O +- ② 현재가격 방법 PW = (RC + RUC) + M&O × PWFrd,n,i +- ③ 편익비용비 방법: $B/C=\dfrac{\Delta RUC\times CRF_{n,i}}{\Delta RC\times CRF_{n,i}+\Delta(M\&O)}$ +- ④ 내부수익률 방법: $\Delta RC\times CRF_{n,i}=\Delta RUC\times CRF_{n,i}+\Delta(M\&O)$ + +여기서 $RC$는 자본투자비인 임도비, $RUC$는 임도사용자비용, $M\&O$는 유지관리비이다. 연간비용방법과 현재가격방법은 각 대안의 비용을 각각 연간비용과 현재가치로 환산하여 비교한다. 편익비용비방법은 대안 간 사용자비용 절감액을 추가투자비의 연간비용으로 나눈다. 내부수익률방법은 비용 절감액과 추가투자비의 연간비용이 같아지는 이자율을 구하여 기준수익률과 비교한다. + +(예제) 경북 봉화 춘양 우구치 산림의 임도개설 전과 개설 후 대안 1·2의 자료는 표 5-2-13과 같다. + +표 5-2-13. 경제성분석 기초자료(단위: 천원) + +| 구 분 | 임도개설전 | 임도개설후 | | 비 고 | +|---|---|---|---|---| +| | | 대안노선 1 | 대안노선 2 | | +| 공사비(RC) | - | 311,660 | 623,311 | 57,080천원/km | +| 집재비(EC) | 635,400 | 114,220 | 34,970 | | +| 운재비(TC) | - | 2,940 | 2,750 | | +| 유지관리비(MC) | - | 18,700 | 37,400 | 연간 공사비의 6% | + +임도개설전에는 임도시설분이 없으므로 집재비만을 계상하고, 임도개설후에는 공사비, 집재비, 운재비, 유지관리비를 계상한다. 여기서 임도개설전에는 임도시점부근으로, 개설후에는 가장 가까운 임도변으로 집재되는 것을 기준으로 하고 유지관리비는 매년 시설비의 6%, 임도상각기간(n)은 20년, 이자율(i)는 12%라고 할 때 임도개설의 경제성을 분석하여라. (풀이) + +- ① 연간비용 방법에 의한 경제성분석 AC=(RC+RUC)×CRFn,i+M&O이고, CRF20,12는 0.1339(표 5-2-12 참조)이므로 +- - 개설전 : 635,400×0.1339=85,080천원/년 +- - 대안 1 : (311,660+114,220+2,940)×0.1339+18,700=76,119천원/년 +- - 대안 2 : (623,311+ 34,970+2,750)×0.1339+37,400=125,912천원/년 +- ② 현재가격 방법에 의한 경제성분석 PW=(RC+RUC)+M&O×PWFpp,n,i이고, PWFpp,20,12는 7.4694(표 5-2-12 참조)이므로 +- - 개설전 : 635,400천원 +- - 대안 1 : 311,660+114,220+2,940+18,700×7.4694=568,498천원 +- - 대안 2 : 623,311+ 34,970+2,750+37,400×7.4694=940,386천원 +- ③ 편익비용비 방법에 의한 경제성분석($CRF_{20,12}=0.1339$) + - 개설 전과 대안 1: $B/C=\dfrac{\{635,400-(114,220+2,940)\}\times0.1339}{311,660\times0.1339+18,700}=1.148$ + - 개설 전과 대안 2: $B/C=\dfrac{\{635,400-(34,970+2,750)\}\times0.1339}{623,311\times0.1339+37,400}=0.662$ + +이상의 결과를 종합하면 대안노선 1은 연간비용과 현재가격이 개설 전에 비하여 약 11% 절감되고 편익비용비도 1.148이므로 임도개설이 타당하다. 대안노선 2는 연간비용과 현재가격이 개설 전보다 약 48% 증가하고 편익비용비도 0.662이므로 타당하지 않은 것으로 판단할 수 있다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 19~47쪽 (인쇄면 389~417쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/4. 노선측량.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/4. 노선측량.md new file mode 100644 index 00000000..1814fa56 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/4. 노선측량.md @@ -0,0 +1,796 @@ +# 4. 노선측량(Route Surveying) + +### 가. 기초조사 +#### 1) 현지조사 +##### 가) 지형 + +공사의 난이도를 판정하기 위하여 일반적인 지형상태를 조사한다 +- ① 토질, 지질의 상태 : 절토면, 채석장, 토취장, 산허리의 붕괴면 +- ② 지하수의 상황 : 우물, 용출수(湧出水), 습지대 +- ③ 특수지대 : 애추(崖錐), 선상지(扇狀地), 지붕(地崩), 단층(斷層) 및 파쇄대(破碎帶), 사구(砂丘), 천정천(天井川), 지질구조. +- ④ 기존시설의 상황 : 사면의 침투수상태, 침하상태, 배수공, 낙석방지공, 방설책 등의 형식과 효과 등 +##### 나) 성토부 +- ① 재료선정 : 보링(Boring)작업에 의하여 토취장이나 절취되는 흙이 성토의 재료로 적합한지를 조사하여 성토시공의 지침을 마련한다. +- ② 기초지반의 안정과 침하 : 보링(Boring)과 사운딩(Sounding)시험에 의하여 성토의 기초지반의 안정성과 침하에 대비한다. 느슨한 모래, 연약한 세립토에는 주의한다. +- ③ 비탈면 안정 : 공사의 완성 후 성토자체의 안정성을 검토하기 위하여 현장시험으로 흐트러지지 않는 시료를 채취하여 검토한다. +##### 다) 절토부 +- ① 절취비탈면에 대한 표토의 두께, 흙부분의 안정성, 암반의 층리(層理), 균열의 방향 및 비탈면 방향과 관련성을 검토한다. +- ② 애추·단층·파쇄대 등의 유무, 산사태·붕괴의 가능성, 지반내의 침투수와 그 처리 방법을 검토한다. +##### 라) 토공계획 +- ① 토공량의 추정 +- ② 시공기계, 시공방법의 선정, 다짐효과의 추정 등 +#### 2) 토질시험 +##### 가) 현장토질시험(원위치시험) +- ① 현장에서 간단하게 토질을 판정하기 위하여 자연상태의 흙으로 시험 +- ② 시험의 종류 ㉠ 탄성파 검사 : 지하의 지질상태를 시험 ㉡ 전기 탐사 : 지하수 조사 ㉢ 관입시험 : 현장에 있는 흙의 단위체적중량시험과 흙의 강도를 판정 ㉣ 베인(vane)시험 : 연한 점토 또는 실트의 전단강도 측정 ㉤ 평판재하시험 : 노상, 보조기층의 지반계수(지지력계수)의 측정과 시공관리 ㉥ 현장 투수시험 : 관정 등을 이용하여 투수계수 측정 등 +##### 나) 토질시험 +- ○ 흙의 판별 및 분류를 위한 시험 +- ① 흙의 물리적 성질을 구하여 그 흙이 지니고 있는 성상을 파악하기 위한 시험 - 흙의 함수량 시험, 흙입자의 비중시험, 입도시험, 컨시스턴시(consistency)시험(액성한계시험, 소성한계시험) 등 +- ② 흙의 분류방법 ㉮ 입경(粒徑)에 의한 토립자 구분 표 5-2-14. 입경에 의한 토립자의 구분(단위:mm) + +| 미국재료시험협회 및일본공업규격 | colloid | | | | clay | | | | | | | | silt | | | | | | 세사(細砂) | | | | | | 조사(組砂) | | | | | | | | | 력(礫) | | | | | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +| | | | 0.001 | | | | | | | | | 0.005 | | | | | | 0.05 | | | | | | 0.25 | | | | | | | 2.0 | | | | | | | | +| 미국도로관리국 | colloid | | | | clay | | | | | | | | silt | | | | | | fine sand | | | | coarse sand | | | | | | | gravel | | | | | | boullder | | | +| | 0.001 | | | | | | | | | 0.005 | | | | | | | 0.074 | | | | | 0.42 | | | | | | | 2.0 | | | | 2 | | | 0 | | | +| 미국토성국 | colloid | | | clay | | | | | silt | | | | | sand | | | | | | | | | | | | | | | | | fine gravel | | | | | gravel | | | +| | | | | | | | | | | | | | | very fine | | | | | fine | | | medium | | | | | coarse | | | | | | | | | | | | +| | | 0.001 | | | | 0.005 | | | | | | | 0.05 | | | | | 0.1 | | | 0.25 | | | | | 0.5 | | | 1.0 | | | | | | 2.0 | | | | +| 일본철도성 토질조사위원회 | colloid | | | | clay | | | | | | silt | | | | | 砂 | | | | | | | | | | | | | | | | | 礫 | | | | | | +| | | | | | | | | | | | | | | | | 微粒砂 | | | | 細粒砂 | | | 中粒砂 | | | | | 組粒砂 | | | | | 細礫 | | | 礫 | | | +| | | | 0.001 | | | | | 0.005 | | | | | 0.05 | | | | | | 0.1 | | | 0.25 | | | | 0.5 | | | | | | 1.0 | | 2.0 | | | | | + +㉯ 삼각좌표에 의한 구분 : 3성분의 함유율 합계가 반드시 100%가 되어야 한다(그림 5-2-25 참조). ㉰ 통일 분류법 •통일분류법(Unified Dlassification)은 카스그란드(Casagrande)에 의하여 개발된 것으로서 콘시스턴시 시험(액성한계시험, 소성한계시험)에 의한 공학적 분류방법이다. •흙의 조합을 3개 문자로 쓸 경우가 있지만 거의 대부분 2개 문자조합으로 표시한다. (즉, 1개 문자는 흙의 형, 다른 문자는 흙의 속성)•흙의 종류는 15종(조립토 8, 세립토 6, 유기질토 1종)으로 구분하여 SM, SC, ML,OL, MH, OH 등으로 표시한다(그림 5-2-26 참조). 표 5-2-15. 통일 분류법에 사용되는 기호와 그 의미 + +| 토질의형 | | 제1문자 | 토질의속성 | 제2문자 | +|---|---|---|---|---| +| 조 립 토 | 자 갈 (gravel) | G | (Well-Graded)입도 분포 양호 세 립 분 거의 없음 (0.075mm 이하5% 이하함유) | W | +| | 모 래 (sand) | S | (Poor-Graded)입도 분포 불량 세 립 분 거의 없음 | P | +| 세 립 토 | 실 트 (mo) | M | (Mo)세립분12% 이상함유A선아래, 소성지수4 이하 | M | +| | 점 토 (clay) | C | (Dlay-Binder)세립분12% 이상함유A선위, 소성지수7 이상 | C | +| | 유기질의실트및점토 (organic clay) | O | (Low Compressibility)압축성낮음WL 50 | L | +| 유기 질토 | 이 탄 (peat) | P1 | (High Compressibility)압축성높음WL 50 | H | +| 토 질 | | | 토질의속성 | 제3문자 | +| 조 립 토 | | | (Drained)액성한계WL≦28, 소성지수IP≦6 | D | +| | | | (Undrained)액성한계WL≦28 | U | +| 주) 제3문자는 도로 및 비행장에 사용되는 기호 | | | | | + +![노선측량_그림5-2-26_통일분류법을위한소성도](<../pic/노선측량_그림5-2-26_통일분류법을위한소성도.png>) + +![노선측량_그림5-2-25_삼각좌표에따른흙의분류도](<../pic/노선측량_그림5-2-25_삼각좌표에따른흙의분류도.png>) + +그림5-2-25. 삼각좌표에 따른 흙의 분류도 + +그림5-2-26. 통일분류법을 위한 소성도표 5-2-16. 토공시험관리 기준 + +| 종 별 | 시 험 종 목 | 시 험 법 | 시 방 서 규 격 | 빈 도 | +|---|---|---|---|---| +| 노 체 부 | 흙의 함수량 시험 | KS F 2306 | 최적함수비의 90% 밀도 에해당하는 습윤측 함수비 | •200m마다 1회 •1,500㎡마다 1회 | +| | 다짐시험 | KS F 2312 | A-1 다짐 또는 D-1 다짐 | •15,000㎡마다 1회 •토질이 변할 때마다 •필요시 마다 | +| | 현장밀도시험 | KS F 2311 | 실내최대건조밀도의 90% 이상 | •200m마다 1회 •1,500㎡마다 1회 | +| | 흙의 분류 시험 | KS F 2324 또는 PRA | 소성한계 25 이상 액성한계 50 이상 | •10,000㎡마다 1회 •토취장 변경시마다 | +| | CBR 시험 | KS F 2320 | 2.5 이상 | •필요하다고 인정할 때 | +| | 평판재하시험 | KS F 2310 | | •2,000㎡마다 1회(다짐도 를측정할수없을때) | +| 노 상 부 | 흙의 함수량 시험 | KS F 2306 | 최적함수비의 ±2% 이내의 함수비 | •200m마다 1회 •1,000㎡마다 1회 •강우 후 1회 | +| | 흙의 분류 | KS F 2324 또는 PRA | PI<10 | •10,000㎡마다 1회 •토질이 변할 때마다 •필요시 마다 | +| | 다짐시험 | KS F 2312 | B-2 다짐 또는 D-2 다짐 | •5,000㎡마다 1회 •토질이 변할 때마다 •필요시 마다 | +| | 현장밀도시험 | KS F 2311 | 실내최대건조밀도의 95% 이상 | •200m마다 1회 •500㎡마다 1회 | +| | 프로후로링 | 승인된 타이어로 러(복륜하중 5톤 이상) 타이어 접지 압 5.6㎏/㎠이상 | 침하가 5㎜이면 재시공 | •노상 완성 후 전 구간 에 걸쳐 3회 이상 | +| | CBR 시험 | KS F 2320 | 10 이상 | •필요하다고 인정할 때 | +| | 평판재하시험 | KS F 2310 | | •100㎡마다 1회(다짐도 를 측정할 수 없을 때) | +| 구 조 물 접 속 부 | 흙의 함수량시험 | KS F 2306 | 1. B-2, D-2다짐 최적함수 비와 95%밀도에 대응하는 습윤측 함수비 사이(되메 우기의 경우) 2. 최적함수비의 ±2% 이 내(토취장인 경우) | •50㎡마다 1회 | +| | 흙의 분류시험 | KS F 2324 또는 PRA | | •500㎡마다 1회 •토취장 마다 1회 | +| | 현장밀도 | KS F 2311 | 실내최대건조밀도의 95% 이상 | •50㎡마다 1회 | +| | 다짐시험 | KS F 2312 | B-2다짐 또는 D-2다짐 | •흙분류 결과가 다를 때 마다 1회 •필요하다고 인정할 때 | + +- ○ 흙의 역학적 성질을 구하는 시험 +- ① 다짐특성, 특수성, 강도 및 압밀성상 등 토공설계에 필요한 흙의 정수를 측정 +- ② 다짐시험, CBR시험, 실내특수시험, 압밀시험, 전단시험(일축압축시험, 직접전단시험, 삼축 압축시험), 콘지지력시험, 표준관입시험 등 +### 나. 답사 +#### 1) 실행방법 +- ① 당해 노선을 임도망계획서를 참고하여 건설비, 유지비가 최소화될 수 있도록 그 지역에서 가장 적정한 지형도에 노선을 도시하여 답사도를 작성한다. +- ② 이 답사도를 이용하여 현장을 답사하고 현장여건과 도상의 추정상태가 동일한가? 또는 더 유리한 노선의 대안이 없는지를 조사 비교한다. +- ③ 두 노선의 우열을 검토하여 유리한 노선을 선정하되 우열이 곤란한 지역은 두 노선을 모두 선정하여 도시한다. +- ④ 측정방법 ㉮ 거리측정 : 목측, 보측 또는 테이프 등으로 약측 ㉯ 방향측정 : 핸드컴퍼스 ㉰ 고저차 : 핸드레벨, 경사측정기, 기압계 등 ㉱ 기타자재 : 쌍안경, 포올(pole) 등, 특히 목측으로 측정할 경우에는 시환(視幻)에 주의하여야 한다. ※ 시환이란? • 눈 앞의 직선은 길게 보이고, 먼거리에 있는 것은 짧게 보임. • 비탈진 지반에 서서 높은 곳을 보면 45°는 75°로, 약 60°는 거의 수직처럼, 1할 5부는 1할의 기울기로 보임. 특히 높은 곳에서 비탈진 아래로 보면 더 심함 • 덤불이 무성한 지역은 공사하기가 곤란하게, 반대로 고저기복이 심하지 않는 곳이나 기울기가 완만한 곳은 공사하기가 쉽게 보임 +- ⑤ 산정, 계곡, 지질, 가옥, 토취장, 토사장, 인부의 공급, 기타 경제적인 문제 등을 조사한다. +#### 2) 주요지점의 결정 +##### 가) 시·종점의 결정 +- ① 기설도로에서 진출입이 편리하고 교통에 안정성이 있는 곳이어야 한다. +- ② 공사비, 운반비 등에 현저한 영향을 미치므로 임도의 종류, 노면의 상태, 물매(勾配), 곡선 설치, 임도너비, 장래의 저목장(貯木場)의 역활 등을 참작하여야 한다. +- ③ 임도를 막장에서 끝내어야 할 경우에는 가능한한 완경사지를 선택하여 차돌림과 주차장, 산원 집재장, 산림작업시의 가설사무소와 숙소 등의 시설이 편리한 곳이어야 한다. +- ④ 장래 노선연장시설의 필요가 있을 경우에 연장선의 물매(勾配)와 곡선 설치에 지장을 주지 않는 곳이어야 한다. +##### 나) 주요 통과지의 결정 +- ① 교량, 석축, 옹벽 등의 구조물 시설이 적은 곳이어야 한다. +- ② 건조하고 양지바른 곳이어야 한다. +- ③ 암석지, 연약지반, 붕괴지역은 가능한한 피한다. +- ④ 너무 많은 흙깎기와 흙쌓기, 높고 긴 교량을 필요로 하는 곳은 되도록 우회한다. +- ⑤ 가교지점은 양안(兩岸)에 침식된 부분이 없는 곳을 선정하고 강중심(江心)에 대하여 되도록이면 직각으로 건너도록 한다. +- ⑥ 임도개설에 유리한 지점은 통과한다. 이와 같은 지점으로는 안부(鞍部 : Saddle), 여울목(Ford), 급경사지내의 완경사지(Hair Pin Curve, 집재장 시설지), 공사용 자재(골재, 석재 +##### 등) 의 매장지와 산재지 등이 있다. +- ⑦ 임도개설에 불리한 지점은 피한다. 이와 같은 지점으로는 늪(Swamp)과 같은 습지, 붕괴지·산사태지(山沙汰地)와 같은 지반이 불안정한 산지사면, 암석지, 홍수범람지역, 소유경계 등이 있다. +### 다. 예측 +- ① 답사에서 결정된 노선(1∼2개)을 따라 트래버어스 측량을 실행하여 노선의 상태를 시점, 종점, 교량의 가설지점, 임도의 분지점, 주요한 통과지점, 구간마다의 고저차와 개략적인 거리에 의한 종단물매를 산출하고 개략적인 공사비를 산출할 수 있는 자료를 조사한다. +- ② 노선을 횡단하는 도로, 하천, 부락, 토지의 경계 등을 기록하고, 지질, 경작상황, 절토의 난이, 기타 임도시설에 관계되는 사항을 조사한다. +- ③ 이와같은 조사사항을 정리하여 예측도를 작성한 후 개개 노선별로 대안비교법에 의하여 가장 타당한 노선을 결정한다. +- ④ 측정방법 ㉮ 거리 : 대자(竹尺), 테이프 또는 스타디아측량으로 측정(정도는 1/3,000)㉯ 각 : 트랜싯 또는 컴퍼스로서 편각이나 교각 또는 방위각을 측정 ㉰ 고저차 : 레벨, 핸드레벨 또는 경사측정기로서 측정 ㉱ 노선 양쪽 주위의 지형 : 스타디아측량, 핸드레벨, 경사측정기와 테이프, 포올의 횡단, 평판, 지거법에 의하여 측정 +### 라. 실측 + +예측의 결과에 의하여 노선을 현지지상에 측설하는 방법은 노선의 중심선(中心線 : CenterLine)을 기준으로 측량하는 경우와 영선(零線 : Zero Line)을 기준으로 측량하는 경우의 2가지 방법이 있다. 전자를 중심선측량법(中心線測量法 : Center Line Method)이라 하고 주로 평탄지와 완경사지에서 많이 이용되며, 후자를 영선측량법(零線測量法 : Zero Line Method)이라 하고 주로 산악지에서 많이 이용되고 있다. + +#### 1) 중심선법과 영선법의 차이점 +- ① (그림 5-2-27)과 같이 노폭의 1/2이 되는 지점을 중심점(中心點 : Center Point)이라하고 이 점을 연결한 노선의 종축을 중심선(中心線 : Center Line)이라 한다. 경사지에 설치하는 측점별로 임도에서 노면의 시공면(Road Plane)과 산지의 경사면이 만나는 점을 영점(零點 :Zero Point)이라하고 이 점을 연결한 노선의 종축을 영선(零線 : Zero Line)이라 한다. + +![노선측량_그림5-2-27_중심선과영선의위치비교](<../pic/노선측량_그림5-2-27_중심선과영선의위치비교.png>) + +그림 5-2-27. 중심선과 영선의 위치 비교 + +- ② 영선은 (그림 5-2-28)에서 보는 바와 같이 절토작업과 성토작업의 경계선이 되기도 한다. + +![노선측량_그림5-2-28_경사지임도의영선과기면](<../pic/노선측량_그림5-2-28_경사지임도의영선과기면.png>) + + +- ③ 중심선측량은 중심점을 기준으로 중심선을 따라 측정하고, 영선측량은 영점을 기준으로 영선을 따라 측정한다. +- ④ 중심선측량은 지반고(地盤高 : Ground Height)상태에서 측량하며 종단면도상에서 계획선을 설정하여 계획고(計劃高 : Formation Height)를 산출한 후 종단과 횡단의 형상이 결정되지만, +- ⑤ 영선측량은 시공기면(Zero Plane)의 시공선(Formation Line)을 따라 측량하므로 굴곡부를 제외하고는 계획고의 상태로 측량하며, 필요시 지반고를 유추 산정하여 종단과 횡단의 형상이 결정되고 노선은 영점과 중심점의 차이에 따라 조정된다. +- ⑥ 균일한 사면일 경우에는 중심선과 영선은 일치되는 경우도 있지만 대개 완전히 일치되지 않고 지반기울기가 급할수록 영선보다 중심선이 경사지의 안쪽에 위치하고, 약 45∼55%지형에서는 중심선과 영선이 거의 일치되다가 지반기울기가 완만할수록 중심선이 영선보다 바깥쪽에 위치한다. +- ⑦ 지형의 상태에 따라 중심선측량은 파상지형의 소능선과 소계곡을 관통하며 진행되고, 영선측량은 사형(蛇形)으로 우회하여 진행되기도 한다. +- ⑧ 중심선측량은 평면측량에서 중심선을 설정한 후 종단·횡단측량을 실행하지만, 영선측량은 종단측량에서 영선을 먼저 설정한 후 평면·횡단측량을 실행한다. +#### 2) 중심선 측량법 +##### 가) 평면선형측량 +- ① 노선의 방향이 바뀌는 점{交點 : Intersection Point(IP)}에는 교점말뚝을 박고 시점말뚝을 0으로 하여 교점의 일련번호를 기입한다. +- ② 교점말뚝 1의 중심점에 측각기구(트랫싯,컴퍼스 등)를 설치하여 시점(BP)를 시준한 후 교 점 2를 반복 시준하여 교각(IA)를 구한다. 교점은 중심선측량에서 매우 중요한 측점이며 시공측량이나 공사 완성 후 노선의 유지관리 및 개량시에도 필요하므로 교점말뚝은 잘 보존하여야 한다. +- ③ 노선의 시점을 기준으로 20m마다 측점말뚝(Station Peg)을 박은 후 시점말뚝으로부터 측 점번호를 기입한다. 지형상 종·횡단의 변화가 심한 지점, 구조물설치 지점, 곡선부의 주요점 등에는 보조말뚝(Reference Peg)을 설치하여 측점번호를 부여한다. 이때 측점간의 번호는 20m이내에서 조정된다. +- ④ 교점간의 내각이 155°이내일 경우에는 평면곡선을 삽입하여야 하며 곡선부에서도 연속적으로 곡선을 따라 20m 간격으로 측점말뚝을 박고, 곡선의 시곡점(BC), 중곡점(MC), 종곡점(EC)에도 말뚝을 박아 보조측점을 부여한다. +- ⑤ 때로는 주요말뚝, 교점말뚝의 좌우에 필요할 경우 보호말뚝을 설치하기도 한다. +- ⑥ 측량기구 및 방법은 제 4장 2 -(3), (5) 참조. +##### 나) 종단측량 +- ① 중심선측량이 완료되면 함척, 레벨, 경사측정기, 핸드레벨 등을 이용하여 종단측량을 실시하며, 기준지반고는 가장 가까운 삼각점이나 보조삼각점으로부터 측정하여 기점부근의 교량이나 암반 등 변용되지 않은 지점에 수준점{Bench Mark(B. M)}을 설치한다. +- ② 각 측점마다 종단측량을 실행하여 지반고를 산출하고, 종단면도(縱斷面圖 : Profile)를 작성한다. +- ③ 측량기구 및 방법은 제 4장 2-(4) 참조. +##### 다) 횡단측량 +- ① 종단측량이 완료되면 함척, 테이프, 경사측정기, 핸드레벨 등을 이용하여 각 측점마다 중심선의 직각 방향이 되도록 중심선 좌·우의 지형에 대한 변화 상태를 측정하고 특히, 지형이 급변하는 지점과 구조물 설치지점에는 현지지형을 충분히 측정하여 설계도 작성과 공사수량 산출에 지장이 없도록 한다. +- ② 노폭, 중심선, 종단면도의 지반고, 계획고 및 토성에 따른 안식각에 따라 각 측점별로 횡 단면도(橫斷面圖 : Cross Section)을 작성한다. +- ③ 측량방법은 제 4장 2-(4) 참조. +#### 3) 영선측량법 +##### 가) 영선설정의 원칙 +- ① 영선은 당해노선의 구조·규격에 따라 설치하고자 하는 적정 종단물매를 정확히 알고 있어야 설정이 가능하다. +- ② 두 측점사이의 종단물매는 일정하게 유지해야 하며 물매를 변환하여야 할 경우의 허용편차는 2∼3%를 넘지 않도록 한다. +- ③ 영선 설정시에는 평면측량시 설치될 중심선의 위치를 감안하여야 하며, 만약 능선, 소계곡, 배향곡선 등과 같이 영선과 중심선의 편차가 심하게 발생할 우려가 있는 곳에서는 시공후 노선의 선형을 감안하여 적정물매 이상이 되지 않도록 평균물매를 조정한다. +- ④ 항상 고정된 지점(기지점)에서 가변지점(미지점)으로 측정하여 진행하되, 측량작업은 측량자(기계수)가 다른 작업원보다 앞선 상태에서 즉, 보조자를 기지점에 표적판을 세우게하고 측량자는 적정한 물매에 맞는 미지점을 찾아 이동하면서 측점을 확정한다. +- ⑤ 동일지점에서 기지점과 미지점으로 한 측점씩 건너서 측량하는 단도선시준방법은 측정오차가 발생하기 쉬우므로 가급적 하지 않도록 한다. +- ⑥ 시준거리의 변화가 크면 내부오차 조정에 영향을 미치므로 너무 긴 시준거리의 측량은 하지 않도록 한다. 적정시준거리(측점거리)는 20∼30m가 좋으며 임목이 조밀하여 시야가 좋지 못한 유령임분에서는 10m 정도로 하는 것이 시야가 좋다. +- ⑦ 영선의 설정과 측량작업에 소요되는 품은 외업과 내업을 포함하여 km당 측량자 1∼1.5인(8∼12 hr/km/1인), 보조원 2.5∼4인(20∼30 hr/km/1인)이다. +##### 나) 사용기구 +- ① 측량자 : 경사측정기(Clinometer), 지지봉(Clinometer rod), 컴퍼스 또는 핸드컴퍼스, 고도계 +- ② 보조자 : 30m 줄자(Tape), 10m 토우로프(Tow Rope), 표지테이프(Marking Tape), 표적판(Clinometer Target), 유성펜 + +![노선측량_그림5-2-29_표적판과지지봉](<../pic/노선측량_그림5-2-29_표적판과지지봉.png>) + +##### 다) 기구제작방법 +- ① 표적판 : (그림 5-2-29)의 1과 같이 크기는 50∼70cm×20∼30cm의 판을 3cm×3cm×120∼150cm의 각재에 부착하고, 조도가 낮은 임내에서도 시준이 가능하도록 야광 또는 발광 페인트로서 표면에는 백색바탕에 적색띠를 세로로 3∼4선을 그리고, 뒷면은 동계 적설시에도 사용할 수 있도록 황색바탕으로 한다. +- ② 지지봉: 그림 5-2-29의 2와 같이 3cm×3cm×120∼150cm의 각재 또는 원형봉으로 한다. 경사측정기를 설치했을 때 시준선이 표적판 상단과 일치하도록 하며, 지지봉 길이와 경사측정기 시준선 높이(약 27mm)의 합이 표적판 상단 높이가 되게 한다. + +![노선측량_그림5-2-30_토우로프](<../pic/노선측량_그림5-2-30_토우로프.png>) + +- ③ 토우로프: 그림 5-2-30과 같이 총 길이 10m의 가벼운 로프 양쪽 끝에 고리를 만든다. 한쪽 고리는 말뚝에 걸고 다른 고리를 잡아 10m 길이를 측정한다. +##### 라) 측량방법 +- ○ 측점부설과 종단물매의 측정 +- ① 보조자 1은 시점에 표적판을 수직으로 세우고 줄자의 0점을 잡는다. +- ② 측량자는 지지봉을 수직으로 세우고 경사측정기를 지지봉의 상단에 얹은 후 표적판의 상단을 시준하여 계획하고자 하는 물매로 시준하기 좋은 지점을 찾아 이동하면서 계획된 물매가 확정되는 지점에 말뚝을 박고, 오차의 유무를 확인한 후 야장에 기재한다. +- ③ 보조자 2는 줄자를 끌어 측점거리를 m 단위로 소수점 1자리까지 반복 측정하여 측량자에게 읽어주면 측량자는 복창하고 야장에 기재한다. +- ④ 만약 2회 측정한 물매와 거리에 대한 측정값이 차이가 근소하면 그 평균치를 구하여 기재하고 차이가 크면 다시 반복 측정한다. +- ○ 방위각의 측정 +- ① 측량자는 종단물매를 측정한 후 지지봉위에 컴퍼스를 설치하고, 보조자 1인이 세우고 있는 표적판의 수직선을 시준하여 방위각을 측정한다. 이때의 방위각은 측량야장 정리시에 역방위각으로 환산하여야 한다. +- ② 항상 동일한 방향으로 측정하고 매 측정시마다 전시와 후시를 통하여 반복측정하며 단도 선시준방법은 피한다. +- ③ 가능한한 동일한 장비를 사용하고 장비를 바꿀 때나 너무 오래 사용한 것은 사전에 점검하여 오차가 있을 경우에는 조정한다. +- ④ 측량자는 국지인력(Local Attraction)에 영향을 미치는 방해 요인(스틸테이프, 기구, 포켓 칼, 철테안경, 우산 등)을 휴대하고 작업하지 말고 필요시에는 먼 곳에 두거나 보조자에게 맡긴다. +- ⑤ 측량방법은 제 4장 2-(3) 참조 +- ○ 횡단기울기의 측정 +- ① 측량자는 지형변동이 심한 경우에는 좌우 양쪽의 기울기를 측정하여 평균하고, 심하지 않을 경우에는 한 쪽만 측정하여 사용하여도 측량의 정도(精度)에는 거의 영향을 미치지 않는다. +- ② 보조자 3은 10m 토우로프로서 한쪽 끝은 측점 말뚝에 걸고 임도노선에 대하여 직각방향으로 다른 한 쪽 고리를 팽팽하게 잡아당겨 표적판을 수직으로 세우면, 측량자는 방위각을 측정한 후 지지봉 위에 경사측정기를 설치하고 횡단기울기를 측정한다. +##### 마) 세부측량 방법 및 조정 + +노선설치는 경사측정기와 컴퍼스에 의하여 측정한다. 측량자는 지형 조건, 조정하여야 할 지점, 각 구간의 종단물매에 대한 자료를 파악하고 있어야 한다. 작업방법은 다음과 같이 4단계 작업으로 구분하여 소요 시간과 노력을 최대한 절약하며 가장 적정한 노선이 될 수 있도록 한다. 여기서 제 1단계와 제 2단계 작업을 예측단계, 제 3단계와 제 4단계 작업을 실측단계라고도 할 수 있다. + +- ○ 제 1단계 작업 +- ① 보조자는 표지테이프를 갖고 시점에 똑바로 서고, 측량자는 경사측정기를 이용하여 계획한 종단물매로 보조자의 눈 높이를 시준(측량자의 눈높이와 같게 하기 위하여 보조자가 측량자보다 키가 크면 코 높이로, 보조자의 키가 작으면 이마 높이로 시준)하며 가능한한 영선의 시준거리가 긴 곳으로 가서 측점 1을 부설하여 표시한다. +- ② 보조자는 측점 1에 이동하여 측점 주위의 임목에 표지테이프를 돌려매어 표지한 후 측점 위에 똑바로 서고, 측량자는 다음 측점으로 이동하여 ①과 같은 방법으로 계획한 종단물 매에 맞는 영선을 설정하고 측점 2를 부설하여 표시한다. +- ③ 측점간의 거리는 줄자나 토우로프로서 개략적으로 측정한다. +- ④ 이와 같이 하여 이론적인 계획선이 현지조건에 잘 부합되고 노선선형이 적정하게 되면 제1단계 작업으로서 영선설정을 위한 예측작업이 완료된 것이므로 제 2단계 작업은 생략하고 바로 제 3단계 작업을 실행할 수 있으나, 그렇지 않을 경우에는 제 2단계 작업을 계속한다. +- ○ 제 2단계 작업 +- ① 제 1단계 작업에서 현지조건에 잘 부합되지 않거나 이론적인 계획선에 편차가 너무 클 경우에는 불부합구간 끝지점에서 되돌아 오거나 또는 조정하여야 할 구간을 (그림 5-2-31)과 같이 제 1단계의 작업과 같은 방법으로 되풀이 한다. + +![노선측량_그림5-2-31_개산물매와수정](<../pic/노선측량_그림5-2-31_개산물매와수정.png>) + + +- ② 이때 보조자는 제 1단계 작업의 계획선과 혼동을 피하기 위하여 다른 색의 표지테이프를 사용한다(수정하는 첫 측점과 끝 측점은 2색을 같이 묶어 수정되는 구간이 본 노선과 연속되게 한다). +- ③ 이와 같이 이론적인 계획선이 현지조건에 잘 부합되고 노선선형이 적정하게 되면 제 2단계 작업으로서 예측작업이 완료된 것이므로 제 3단계 작업을 실행하고, 그렇지 않을 경우에는 다시 되풀이한다. (예제) (그림 5-2-31)과 같이 제 1단계 작업시에 개략거리와 종단물매가 측정되었으나 이론적인 계획선에 미흡하였다. 적정하게 조정하여라. (풀이) No. 20에서 No. 50까지의 고저차 : 200×0.04+220×0.09-130×0.04 = 22.6m 평균종단물매 : 22.6 ÷ (200+220+130) = 4.1%따라서 No. 50에서 4∼5%의 종단물매로서 되돌아오면 부득이한 경우를 제외하고는 조정된다. ○제 3단계 작업 +- ① 보조자 1은 표적판을 시점에 수직으로 세우고, 측량자는 측점에 지지봉을 수직으로 세우고 그 위에 경사측정기를 올려 적정한 종단물매로 전방의 표적판을 반복 시준하여 오차가 없으면 (표 5-2-17)의 야장에 기재한다. +- ② 이때 구간마다 물매가 변하면 노선선형이 순조롭지 못하므로 물매변환구간까지는 동일한 물매로 작업하는 것이 좋다. +- ③ 보조자 2는 각 측점에 말뚝을 박고 일련번호를 기재한 후 제 1단계와 제 2단계 작업시 사용한 표지테이프와 색깔이 다른 테이프로서 측점주위의 임목에 묶어 표지하여 측점말뚝의 위치를 쉽게 알 수 있게 한다. +- ○ 제 4단계 작업 +- ① 측량자는 각 측점에 보조자 1이 세운 표적판의 중심선을 컴퍼스로 전시와 후시하여 방위각을 반복 측정하고 오차가 없으면 (표 5-2-17)의 야장에 기재한다. 표 5-2-17. 영선측량 야장 + +| 임도노선선정야장 | | | | | | | | | +|---|---|---|---|---|---|---|---|---| +| 위치 : 임도번호 : 측량자 : | | | | | | | | | +| 측 점 | | 물매 | 거리 | 방위각 | 지 반 | 암 석 | 표고 | 비고 및 견취도 | +| | | | | | 기울기 | 구성비 | | | +| 부터 | 까지 | (%) | (m) | (˚) | (%) | (%) | (m) | | + +- ② 보조자 2와 3은 줄자나 측승으로 측점간의 구간거리를 m 단위로 소수점 1자리 까지 반복 측정하여 측량자에게 읽어주면 측량자는 복창을 한 후 야장에 기재한다. +- ③ 측량자는 보조자 4가 각 측점의 횡단상에 세운 표적판을 시준하여 횡단기울기를 반복 측정하고 오차가 없으면 야장에 기재한다. +- ④ 측점, 거리, 종단물매, 지반기울기, 암석구성비율, 지형의 특수성, 암거 등 배수시설, 공사자재 분포유무 등의 주요사항을 야장에 기재하고 노선의 견취도를 그린다. +- ⑤ 측량자의 작업이 숙련되면 제 3단계와 제 4단계의 작업을 동시에 실행하여도 될 것이며 보조자도 연속된 작업과정은 동시 작업으로 실행할 수 있으므로 작업인원을 줄일 수 있을 것이다. +##### 바) 굴곡부 등의 측량 +- ① 영선이 계곡부나 능선부를 횡단할 경우와 지형조건이 불규칙하거나 불량할 경우에는 중심선측량법에 의하여 중심선을 표지한다. 이때 영선과 중심선 사이의 간격이 너무 떨어져 있을 경우에는 중심선물매까지 위치와 계획된 종단물매의 차이를 구하여 차이가 클 경우에는 (그림 5-2-32)와 같이 영선을 조정한다. + +![노선측량_그림5-2-32_굴곡부의영선과중심선](<../pic/노선측량_그림5-2-32_굴곡부의영선과중심선.png>) + + +- ② 일반적으로 능선부나 계곡부를 횡단할 경우에는 (그림 5-2-33)과 같이 종단물매를 낮추거나 높혔다가 정점(頂點)이나 곡점(曲點)이 지나면 반대로 높히거나 낮춘다. 이때 물매의 편차폭도 2∼3%이다. + +![노선측량_그림5-2-33_능선부와계곡부의종단물매](<../pic/노선측량_그림5-2-33_능선부와계곡부의종단물매.png>) + +그림 5-2-33. 능선부와 계곡부에서 종단물매 설치방법 + +#### 4) 트래버어스측량 + +트래버어스측량(折線測量 : Traverse Survey)은 다각측량(多角測量 : Polygonal Survey)이라고도 하며, 연속된 측선의 거리와 방향을 차례로 측정하는 측량으로서 각(角)의 측정은 트랜싯 또는 컴퍼스 등으로 하는 것이 보통이다. 측정결과에 대해서는 경위거(經緯距 : Departure and Latitude)를 계산하고, 각 측점의 좌표를결정하여 트래버어스(折線 : Traverse)를 그리고 면적을 계산한다. + +##### 가) 트래버어스측량의 측각법 +- ① 방위각법(方位角法 : Azimuth Angle Method) +- ② 편각법(偏角法 : Deflection Angle Method) +- ③ 내각법(內角法 : Interior Angle Method) +- ○ 방위각법에 의한 트래버어스측량의 측각방위각(方位角 : Azimuth)이란 N, S를 기준으로 N에서 시계방향으로 측각하는 것으로서 측 + +각방법은 다음과 같다. + +- ① (그림 5-2-34)의 점 A에 트랜싯을 설치하여 분도원의 0°와 버어니어의 0을 일치시켜 상부고정나사를 잠그고, 자침을 늦추어 콤파스의 0°를 자침끝에 맞추어 정지시키고 하부고정나사를 잠근다. + +![노선측량_그림5-2-34_방위각법트래버어스측량](<../pic/노선측량_그림5-2-34_방위각법트래버어스측량.png>) + +그림 5-2-34. 방위각법에 의한 트래버어스 측량 + +- ② 상부고정나사를 풀어 기계를 시계방향으로 수평회전시켜 점 B를 시준하고 상부고정나사를 잠그고, 미동나사로 정준하여 AB의 방위각(67°)을 읽는다. +- ③ ②에서 측정한 방위각(67°)을 그대로 둔 채로 하부고정나사를 풀고, 망원경을 반위하여 점 B에 옮겨 설치한다. +- ④ 점 A를 시준하여 하부고정나사를 잠그고 망원경을 정위하여 점 B'방향으로 향하게 한 후 상부고정나사를 풀고, 기계를 시계방향으로 회전하여 점 C를 시준한 후 상부고정나사를 잠그고 BC의 방위각(90°)을 읽는다. +- ⑤ 이와 같이 계속하여 측정하고 출발점 A에 돌아와 AB의 방위각을 재측정하여 최초의 측정치와 동일하면 정상이다. +- ⑥ 만일 일치하지 않으면 오차가 발생한 것이므로 조정하거나 재측하여야 한다. 방위각법에의한 트래버어스측량의 야장은 (표 5-2-18)과 같다. 표 5-2-18. 방위각법 트래버어스측량의 야장기입법(예) + +| 측 선 | 거 리 | 방 위 각 | 방 위 | 비 고 | +|---|---|---|---|---| +| A B | 51.80m | 60°00' | | | +| B C | 41.55m | 90°00' | | | +| C D | 40.80m | 130°00' | | | + +- ○ 편각법에 의한 트래버어스측량의 측각편각(偏角 : Deflection Angle)이란 그 선의 연장선과 인접되는 선이 이루는 각을 말하며, 시 + +계방향으로 측각한 것을 (+), 시계반대방향으로 측각한 것을 (-)로 표시한다. 이 방법은 주로 도로, 철도, 수도 등의 노선측량에 많이 사용된다. 편각법에 의한 트래버어스측량의 야장(표5-2-19) 및 측각방법은 다음과 같다. 표 5-2-19. 편각법 트래버어스측량의 야장기입법(예) + +| 측 선 | 거 리 | 편 각 | | 비 고 | +|---|---|---|---|---| +| | | + | - | | +| A B B C C D | 54.35m 52.12m 48.40m | 90°17' 60°10' | 35°10' | | + +![노선측량_그림5-2-35_편각법트래버어스측량](<../pic/노선측량_그림5-2-35_편각법트래버어스측량.png>) + +그림 5-2-35. 편각법에 의한 트래버어스 측량 + +- ① (그림 5-2-35)에서 점 A에 트랜싯을 설치하고, 분도원 0°와 버어니어 0을 일치시켜 상부 고정나사를 잠근 후 망원경을 반위하여 점 F를 후시하고 하부고정나사를 잠근다. +- ② 망원경을 정위로 하고, 상부고정나사를 푼 후 기계를 수평으로 회전시켜 점 B를 전시하여 상부고정나사를 잠그고 각을 읽는다. +- ③ 이렇게 계속하며, 폐합트래버어스에서는 그 대수합이 360°가 되어야 한다. 편각법에 의한트래버어스측량에 있어서 첫 측점의 방위각은 실측하여 두는 것이 좋다(야장정리시에 방위각법으로 환산가능하기 때문임). +- ○ 내각법에 의한 트래버어스측량의 측각 서로 접하는 두 측선이 이루는 사이각인 내각(內角 : Interior Angle)을 측정하는 방법으로 측 + +각방법은 다음과 같다. + +- ① (그림 5-2-36)에서 점 A에 트랜싯을 설치하고 분도원의 0°와 버어니어의 0을 일치시켜 상부고정나사를 잠그고, 점 D를 후시하여 하부고정나사를 잠근다. +- ② 상부고정나사를 풀어 점 B를 전시하여 AB의 방위각 θ와 점 A의 내각(∠BAD)을 측정한다. +- ③ 점 B에 기계를 이동 설치하고 ①과 같은 방법으로 한다. 점 A를 후시하여 하부고정나사를 잠근 후, 상부고정나사를 풀고 점 C를 전시하고 점 B의 내각을 측정한다. +- ④ 이와 같이 계속 진행하며 n각형의 내각의 합은 180°×(n-2)를 만족시켜야 한다. + +![노선측량_그림5-2-36_내각법트래버어스측량](<../pic/노선측량_그림5-2-36_내각법트래버어스측량.png>) + + +##### 나) 트래버어스측량 측각치의 조정 +- ○ 트래버어스측량 측각오차의 처리트래버어스의 측각이 전부 끝나면 관측치가 기하학적으로 만족하여야 한다. 이때 각 조건과 + +비교해서 오차가 있는 경우에는 다음과 같이 처리한다. + +- ① 오차가 허용범위 내에 있는지를 조사해서 허용범위보다 클 경우에는 재측하여야 한다. +- ② 허용범위 내에 있을 경우에는 합리적으로 조정하여 기하학상의 조건을 만족시킨다. +- ③ n을 트래버어스의 변수(邊數)라 할 때, 트래버어스 측각오차의 허용범위는 다음과 같다. √㉮ 산림지, 복잡한 경사지 : 1.5 n (분)√√㉯ 평지, 보통지 : 1.0 n ∼ 0.5 n (분)√√㉰ 시가지, 중요한 곳 : 0.3 n ∼ 0.2 n (분) +- ④ 특별한 경우를 제외하고는 측정오차가 각 점의 각에서 평균되게 발생한다고 가정하여 각 점의 각에 가감한다. +- ○ 트래버어스 측정치의 충족조건 +- - 폐합트래버어스 측정치의 충족조건 변수(邊數)를 n, 측정각을 a1, a2, a3, …, 〔a〕= a1+a2+a3+ … 라 하면, 측정오차 Δa 는 다음식에 의하여 산출한다. +- ① 내각 측정인 경우 : Δa = 180°(n-2) -〔a〕 +- ② 외각 측정인 경우 : Δa = 180°(n+2) -〔a〕 +- ③ 편각 측정인 경우 : Δa = 360°- 〔a〕 +- - 결합트래버어스 측정치의 충족조건 +- ① (그림 5-2-37)의 (a) 인 경우: Δa = (Wa-Wb) +〔a〕- 180°(n+1) +- ② (그림 5-2-37)의 (b), (c) 인 경우: Δa = (Wa-Wb) +〔a〕- 180°(n-1) +- ③ (그림 5-2-37)의 (d) 인 경우: Δa = (Wa-Wb) +〔a〕- 180°(n-3)여기서, a1, a2, a3,…, an : 교각의 측정치, Wa, Wb : AL, BM의 방위각 + +![노선측량_그림5-2-37_트래버어스측정치조건](<../pic/노선측량_그림5-2-37_트래버어스측정치조건.png>) + +그림 5-2-37. 트래버어스 측정치의 조건 + +##### 다) 측정각들의 상호 환산법 +- ○ 교각에서 방위각을 구하는 계산 교각의 측정은 진행방향의 좌측각을 측각하는 경우와 우측각을 측각하는 경우의 두 가지가 + +있다. 좌측각의 경우{그림 5-2-38의(a)참조)는 (+)}로, 우측각의 경우{그림 5-2-38의 (b) 참조는(-)}로 나타내며, 교각에서 방위각은 다음식에 의하여 산출할 수 있다. 측선의 방위각 = 앞 측선의 방위각 + 180°± 교각(여기서, 구해진 각이 360°보다 크면 그 각에서 360°를 빼고, 구해진 각이 0°보다 작으면 360° + +를 더한다.) + +![노선측량_그림5-2-38_트래버어스방위각산출_01](<../pic/노선측량_그림5-2-38_트래버어스방위각산출_01.png>) + +![노선측량_그림5-2-38_트래버어스방위각산출_02](<../pic/노선측량_그림5-2-38_트래버어스방위각산출_02.png>) + + +- ○ 방위각, 편각, 내각에서 방위를 구하는 계산 +- - 방위각에서 방위를 구하는 계산(그림 5-2-39)과 같이 방위각을 측정하여 방위를 산출하는 방법은 (표 5-2-20)과 같다. + +![노선측량_그림5-2-39_방위각과방위의관계](<../pic/노선측량_그림5-2-39_방위각과방위의관계.png>) + +표 5-2-20. 방위각에서 방위를 산출하는 방법 + +| 방 위 각 | 방 위 | +|---|---| +| 0∼ 90° | N (방위각) E | +| 90∼180° | S (180°-방위각) E | +| 180∼270° | S (방위각-180°)W | +| 270∼360° | N (360°-방위각) W | + +- - 편각에서 방위를 구하는 계산(그림 5-2-40)과 같이 편각에서 방위를 구할 때에는 먼저 방위각을 구한 후, 방위각에서 방위를 구한다. +- ① 최초선의 방위각은 그선의 방위각이 된다. +- ② 임의의 측선의 방위각 = 앞 측선의 방위각 + 앞 측선과 이루는 편각(방위각을 구하려는 점의 편각)즉, β2 = β1 + α2 +- ③ 그러나, 측점이 최초의 점에 있지 않고, 그 측선이 반향(反向)하여 (-)인 음각(負角)이 생기는 경우(그림 5-2-40의 점 C)에는 측선의 방위각 = 앞 측선의 방위각 - 그 측선과 이루는 편각 즉 β3 = β2 -α3 + +![노선측량_그림5-2-40_편각과방위의관계](<../pic/노선측량_그림5-2-40_편각과방위의관계.png>) + +그림 5-2-40. 편각과 방위의 관계 + +- - 내각에서 방위를 구하는 계산(그림 5-2-41)과 같이 편각에서 방위를 구할 때에도 먼저 방위각을 구한 후, 방위각에서 방위를 구한다. +- ① 최초선의 방위각은 그대로 그선의 방위각이 된다. +- ② 임의의 측선의 방위각 = 앞 측선의 방위각 + 180°- 그 측선과 이루는 내각 단, 반대방향으로 계산할 경우에는 (+), (-)를 바꾸어 계산한다. +- ③ ②의 식에서 계산한 각이 360°이상일때는 그 각에서 360°를 뺀다. + +![노선측량_그림5-2-41_내각과방위의관계](<../pic/노선측량_그림5-2-41_내각과방위의관계.png>) + +그림 5-2-41. 내각과 방위의 관계 + +이상에서 설명한 방법에 의해 방위각, 편각, 내각에서 방위를 구하는 계산의 예를 살펴보면 표 5-2-21과 같다. + +표 5-2-21. 방위각, 편각, 내각에서 방위를 구하는 계산의 예 + +| 측점 | 내 각 | 편 각 | 방위각 | 방 위 | 비 고 | +|---|---|---|---|---|---| +| 1 | 95°58′ | 84°02′ | 29°12′ | N 29°12′ E | 최초 방위각 | +| 2 | 134°55′ | 45°05′ | 74°17′ | N 74°17′ E | | +| 3 | 93°46′ | 86°14′ | 160°31′ | S 19°29′ E | | +| 4 | 148°38′ | 31°22′ | 191°53′ | S 11°53′ W | | +| 5 | 111°31′ | 68°29′ | 260°22′ | S 80°22′ W | | +| 6 | 135°12′ | 44°48′ | 305°10′ | N 54°50′ W | | +| 계 | 720°00′ | 360°00′ | | | 내각은 우측정 | + +(계산 예) 각 측점의 편각은 $180°-$내각으로 구한다. 이후 방위각은 앞 측선의 방위각에 편각을 더하여 구하며, 180°를 넘는 방위각은 해당 사분면의 방위로 환산한다. 예를 들어 측점 3은 $74°17′+86°14′=160°31′$이므로 방위는 S 19°29′ E이다. + +##### 라) 위거 및 경거의 계산 + +- ○ 트래버어스측량에서 위거 및 경거의 이용 + +![노선측량_그림5-2-42_위거와경거의관계](<../pic/노선측량_그림5-2-42_위거와경거의관계.png>) + +그림 5-2-42에서 XY를 직교축이라고 할 때 종축 NS는 자오선, 횡축 EW는 위선이며 $\theta$는 방위각이다. 측선 AB가 NS축에 비치는 정사영거리 Ab를 위거(Latitude), EW축에 비치는 정사영거리 Aa를 경거(Departure), 측선 중점에서 NS선에 직각으로 그은 CC′를 자오선거(Meridian Distance)라 한다. + +- ① 오차의 합리적인 배분 +- ② 측정치의 제도 +- ③ 폐합트래버어스인 경우의 면적 계산 +- ④ 결측(缺測) 또는 오측(誤測)의 보정위거와 경거의 방향을 알기 위해 다음과 같이 (+), (-)의 부호를 붙인다. 표 5-2-22. 방위에 따른 경거 및 위거의 부호 + +| 방위각(θ) | 방 위 | 위 거 | 경 거 | 비 고 | +|---|---|---|---|---| +| 0°~ 90° | N θE | + | + | | +| 90°~180° | S θE | - | + | | +| 180°~270° | S θW | - | - | | +| 270°~360° | N θW | + | - | | + +○삼각함수에 의한 경위거의 계산 위거 및 경거는 삼각함수의 진수를 사용하여 다음식에 의하여 계산할 수 있다. + +- ① 측선 AB의 위거 = LAB = AB·cosθ +- ② 측선 AB의 경거 = DAB = AB·sinθ +- ③ 측선 AB의 자오선거 = CC′이다. 표 5-2-23. 삼각함수에 의한 경위거의 계산 (예) + +| 측 선 | 거 리 (m) | 방 위 각 | cosθ | sinθ | 위 거 | | | 경 거 | | +|---|---|---|---|---|---|---|---|---|---| +| | | | | | N(+) | S(-) | | E(+) | W(-) | +| AB | 67.30 | 23°55′40″ | 0.91406 | 0.40558 | 61.52 | | | 27.30 | | +| BC | 79.90 | 313°10′30″ | 0.68423 | 0.72927 | 54.67 | | | | 58.28 | +| CD | 63.37 | 16°39′10″ | 0.95806 | 0.28647 | 60.71 | | | 18.15 | | +| DE | 93.60 | 115°35′50″ | 0.43204 | 0.90185 | | 40.44 | | 84.41 | | + +(예제) AB=67.30m, $\theta=23°55′40″$일 때 위거는 $67.30\times0.91406=61.52$m, 경거는 $67.30\times0.40558=27.30$m이다. + +- - 대수에 의한 경위거의 계산 측선의 길이를 S, 방위각을 θ라 하면, 위거는 S·cosθ, 경거는 S·sinθ이므로 양변에 대수(對數 : log)를 취하면 다음과 같은 식이 성립한다. +- ① 위거의 대수 =log S + log cosθ +- ② 경거의 대수 =log S + log sinθ표 5-2-24. 대수에 의한 경위거의 계산 (예) + +| 측선 | 방위각 | 거리 (m) | 대 수 | | | | | 위 거 | | 경 거 | | +|---|---|---|---|---|---|---|---|---|---|---|---| +| | | | 측 선 | cos θ | sin θ | 위 거 | 경 거 | N(+) | S(-) | (+) | (-) | +| AB | 23°55′40″ | 67.30 | 1.828015 | 9.960974 | 9.608082 | 1.788989 | 1.436097 | 61.52 | | 27.30 | | +| BC | 313°10′30″ | 79.90 | 1.902547 | 9.835201 | 9.862886 | 1.739748 | 1.765334 | 54.67 | | | 58.28 | +| CD | 16°39′10″ | 63.37 | 1.801884 | 9.981399 | 9.457232 | 1.783283 | 1.259116 | 60.71 | | 18.15 | | +| DE | 115°35′50″ | 93.60 | 1.971276 | 9.635526 | 9.955136 | 1.606802 | 1.926112 | | 40.44 | 84.41 | | +주) $\sin$과 $\cos$ 값은 1보다 작으므로 그 대수는 음수이다. 계산 편의를 위해 대수표에는 10을 더한 값을 쓰고 최종 계산에서 10을 뺀다. 예를 들어 $\cos23°55′40″=0.91406$이고 $\log0.91406=-0.039026$이므로 대수표에는 $10-0.039026=9.960974$를 기재한다. + +(예제) AB=67.30m, $\theta=23°55′40″$일 때 $\log 67.30=1.828015$, $10+\log\cos\theta=9.960974$, $10+\log\sin\theta=9.608082$이다. 따라서 위거의 대수는 1.788989, 경거의 대수는 1.436097이며, 위거는 61.52m, 경거는 27.30m이다. + +- ○ 경위거표에 의한 경위거의 계산(표 5-2-25)와 같은 경위거표(經緯距表 : Traverse Table)란 측선 및 방위각의 여러 가지 값에 대하 + +여 경거 및 위거를 계산하는 것으로 곱셈의 필요없이 덧셈으로써만 계산하도록 되어 있는 표이다. (예제) 측선 AB의 거리 25.10m, 방위각 = 30°5′일 때 다음의 경위거표를 이용하여 위거 및경거를 구하여라. 표 5-2-25. 경위거표(예)a) 30°위거 + +| 분 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | +|---|---|---|---|---|---|---|---|---|---|---| +| 0 | 0.8660 | 1.7320 | 2.5980 | 3.4641 | 4.3301 | 5.1961 | 6.0622 | 6.9282 | 7.7942 | 60 | +| 1 | 0.8659 | 1.7318 | 2.5976 | 3.4635 | 4.3294 | 5.1953 | 6.0612 | 6.9270 | 7.7929 | 59 | +| 2 | 0.8637 | 1.7315 | 2.5972 | 3.4629 | 4.3286 | 5.1944 | 6.0601 | 6.9258 | 7.7916 | 58 | +| 3 | 0.8656 | 1.7312 | 2.5968 | 3.4624 | 4.3279 | 5.1935 | 6.0591 | 6.9247 | 7.7903 | 57 | +| 4 | 0.8654 | 1.7309 | 2.5963 | 3.4618 | 4.3272 | 5.1926 | 6.0581 | 6.9235 | 7.7890 | 56 | +| 5 | 0.8653 | 1.7306 | 2.5959 | 3.4612 | 4.3265 | 5.1918 | 6.0571 | 6.9224 | 7.7877 | 55 | + +b) 30°경거 + +| 분 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | +|---|---|---|---|---|---|---|---|---|---|---| +| 0 | 0.5000 | 1.0000 | 1.5000 | 2.0000 | 2.5000 | 3.0000 | 3.5000 | 4.0000 | 4.5000 | 60 | +| 1 | 0.5002 | 1.0005 | 1.5007 | 2.0010 | 2.5012 | 3.0015 | 3.5017 | 4.0020 | 4.5022 | 59 | +| 2 | 0.5005 | 1.0010 | 1.5015 | 2.0020 | 2.5025 | 3.0030 | 3.5035 | 4.0040 | 4.5045 | 58 | +| 3 | 0.5008 | 1.0015 | 1.5023 | 2.0030 | 2.5038 | 3.0046 | 3.5053 | 4.0061 | 4.5068 | 57 | +| 4 | 0.5010 | 1.0020 | 1.5030 | 2.0040 | 2.5050 | 3.0061 | 3.5071 | 4.0081 | 4.5091 | 56 | +| 5 | 0.5013 | 1.0025 | 1.5038 | 2.0050 | 2.5063 | 3.0076 | 3.5088 | 4.0101 | 4.5113 | 55 | + +(풀이) (표 5-2-25)와 같은 경위거표에서 위거 30°의 위거란에서 5′(분)의 줄을 보면1은 0.8653, 2는 1.7306, 5는 4.3265, … , 9는 7.7877이다. 여기서, 25.10m = 2×10 + 5 + 1 ÷ 10 으로 풀이할 수 있으므로 측선 AB의 위거 = (1.7306×10)+4.3265+(0.8653÷10) = 21.71903 또한, 경거 30°의 경거란에서 5′(분)의 줄을 보면,1은 0.5013, 2는 1.0025, 5는 2.5063, … , 9는 4.5113 이므로 측선 AB의 경거 = (1.0025×10)+2.5063+(0.5013÷10) = 12.58143 따라서, 위거 = 21.72m, 경거 = 12.58m + +### 마. 평면곡선(horizontal curve)의 설치 +#### 1) 곡선의 종류 +- ① 단(원)곡선(Simple Curve) : 평형하지 않은 2개의 직선을 1개의 원곡선으로 연결하는 곡선{그림 5-2-43의 (a)} +- ② 반향곡선(Reversed Curve) : 방향이 다른 두 개의 원곡선이 직접 접속하는 곡선으로서 곡선의 중심이 서로 반대쪽에 위치한 곡선{그림 5-2-43의 (b)} +- ③ 복심곡선(Compound Curve) : 동일한 방향으로 굽고 곡률이 다른 2개 이상의 원곡선이 직접 접속되는 곡선{그림 5-2-43의 (c)} +- ④ 배향곡선(Hair Pin Curve) : 단곡선, 복심곡선, 반향곡선이 혼합되어 머리핀(Hair Pin)모양으로 된 곡선으로서 산복부에서 노선길이를 연장하여 종단물매를 완화하게 하거나 동일 사면에서 우회할 목적으로 설치되며 교각이 180°에 가깝게 됨{그림 5-2-43의 (d)} +- ⑤ 완화곡선(Transition Curve) {그림 5-2-43의 (e)}㉮ 3차포물선(Parabolic) : 접선장에 비례하여 Cant의 증가 또는 곡율반경이 감소하는 곡선 - 주로 철도에 이용 ㉯ 쌍곡선(Clothoid) : 완화곡선장에 비례하여 Cant의 증가 또는 곡율반경이 감소하는 곡선 - 주로 도로에 이용 ㉰ 연주곡선(Lemniscate) : 현장에 비례하여 Cant의 증가 또는 곡률반경이 감소하는 곡선 +- - 주로 입체교차로에 이용 + +![노선측량_그림5-2-43_곡선의종류_01](<../pic/노선측량_그림5-2-43_곡선의종류_01.png>) + +![노선측량_그림5-2-43_곡선의종류_02](<../pic/노선측량_그림5-2-43_곡선의종류_02.png>) + +그림 5-2-43. 곡선의 종류 + +#### 2) 곡선부의 명칭과 산출식 +- ① 곡선시점(Beginning of Curve : BC) = A +- ② 곡선종점(End of Curve : EC) = B +- ③ 교점(Intersection Point : IP) = V +- ④ 곡선반지름(Radius : R) = OA=OB +- ⑤ 곡선장(Curve Length : CL) = AHB = 0.017453 R·I°= 2π·R·I°/360° +- ⑥ 장현(Long Chord : C) = AB = 2 R·sin (I/2) +- ⑦ 절선장(Tangent Length : TL 혹은 T) = VA = VB = R·tan(I/2) +- ⑧ 외거(외할)(External Distanse : E) = VH = R{sec(I/2) - 1)} +- ⑨ 중앙종거(Middle Ordinate : M) = HF = R {1- cos(I/2)}= C2 / 8R +- ⑩ 교각(편각) = (Intersection Angle : IA 또는 I) = I + +![노선측량_그림5-2-44_곡선부의구조](<../pic/노선측량_그림5-2-44_곡선부의구조.png>) + +V + +| | I | +|---|---| +| H | | + + +#### 3) 교점의 설치와 교각의 측정 +- ① 시공측량이나 공사 완성후 장애물이 없는 지역에서는 두 절선의 교차에 의하여 교점과 교각을 쉽게 측정할 수 있지만 장애물이 있을 경우와 기설노선에서 교점을 구할 경우에는(그림 5-2-45)와 같이 한다. +- ② 이미 설치된 2∼3개 점의 지물로부터 그 위치를 측정하여 직선부의 방향을 정한 후 말뚝을 박고 두 직선의 교각(交角)을 측정한다. +- ③ 이때 장애물이나 지형 관계상 교점이 두 직선상에서 보이지 않거나 접근할 수 없는 경우에는 두 절선상(TL)에 임의의 두 점을 선택하여 ∠α와 ∠β를 측정하면 IA = ∠α+ ∠β에 의하여 구할 수 있다. + +![노선측량_그림5-2-45_두절선상교점설치법](<../pic/노선측량_그림5-2-45_두절선상교점설치법.png>) + + +#### 4) 편각에 의한 곡선의 설치 +- ① (그림 5-2-46)과 같이 교점(점 V)에 트랜싯을 세우고 교각(I)을 측정하여 절선장(VA 또는 VB = R·tan (I/2))만큼 떨어진 지점에 각각 곡선의 시점(BC)과 종점(EC)을 설정한다. + +![노선측량_그림5-2-46_편각에의한곡선설치법](<../pic/노선측량_그림5-2-46_편각에의한곡선설치법.png>) + +그림 5-2-46. 편각에 의한 곡선설치법 + +- ② BC점에 트랜싯을 옮겨 설치하고 ∠VAB = (I/2) 되는지를 검사한 다음 버어니어의 0을수평분도원의 0°에맞추고, 상부고정나사를 잠근다. +- ③ AV선에 망원경을 향하게 하여 하부고정나사를 잠그고, 상부고정나사를 푼 다음 다음 편각만큼 회전한다. + +$$\delta=\frac{\ell}{2R}\;(\mathrm{radian})=\frac{1,718.87'\times\ell}{R}$$ + +시준선상에 BC점에서 거리 $\ell$인 점 $P_1$을 정해 중심선을 확정한다. 일반도로에서는 보통 $\ell\le R/10$이고 대개 20m로 하지만, 임도에서는 지형에 따라 조정한다. 마지막 직선부 말뚝 D가 BC점과 일치하지 않을 때 $AP_1=\ell_1=\ell-DA$를 시단현이라 하며 $\delta_1=1,718.87'\ell_1/R$이다. +- ④ 상부고정나사가 풀어진 상태에서 수평각이 2δ(또는 δ1+δ)가 될 때까지 상부를 회전하고, 이 시준선상에 점 P1에서 거리 ℓ이 되는 곳에 점 P2를 설정하여 측점말뚝을 박고 못을 박아 중심선을 확정한다. ※ APn의 편각 = δ1+(n-1)×δ +- ⑤ 이와 같은 방법을 계속하여 측점말뚝을 설치한다. +- ⑥ 마지막 말뚝 $P_n$과 EC가 일치하지 않을 경우 $P_nB=\ell_2=AB-AP_n$를 종단현이라 하며, $BP_n$에 대한 편각은 $\delta_2=1,718.87'\ell_2/R$이다. + +(예제1) 광능시험림 임도내 I. P 16에 대한 곡선 제원이 I = 32°15', R = 200m이고, 노선기점에서 I. P 16까지의 거리는 1,200.50m이다. 기점부터 20m 간격으로 측점말뚝을 설치할 때 각 측점의 거리와 제원을 구하라. (풀이) 절선장(T. L) = 200×tan(32°15'/2) = 57.82m 외거(E) = 200×{sec(32°15'/2)-1} = 8.19m 곡선장(C. L) = 0.017453×200×32°15'= 112.57m 곡선시점(B. C) = 1200.50-57.82 = 1,142.68m 곡선종점(E. C) = 1200.50-57.82+112.57 = 1,255.25m 시단현(l1) = 20-2.68 = 17.32m 종단현(l2) = 1,255.25-(62×20) = 15.25m δ= (ℓ/R)×1,1718.87'= (20.00/200)×1,1718.87'= 2°51'53 δ1 = (ℓ1/R)×1,1718.87'= (17.32/200)×1,1718.87'= 2°28'51 δ2 = (ℓ2/R)×1,1718.87'= (15.25/200)×1,1718.87'= 2°11'04 따라서, B. C점에서 각 측점말뚝의 편각은 (표 5-2-26)과 같다. 표 5-2-26. B. C점에서 각 측점의 편각 + +| 기점에서부터의 거리(m) | | 편각 | 비고 | +|---|---|---|---| +| 1,142 | .68 | | B.C | +| 1,160 | | 2°28′51″ | | +| 1,180 | | 5°20′44″ | | +| 1,200 | | 8°12′37″ | | +| 1,220 | | 11°4′30″ | | +| 1,240 | | 13°56′23″ | | +| 1,255 | .25 | 16°7′27″ | E.C | + +(예제2) 곡선함수표를 이용하여 I=37°30′, R=300m, IP까지거리=1,150.70m일때 20m 간격으로 단곡선의 중심말뚝을 설치하여라. (풀이) 곡선 함수표에서 I=37°30′에 대한 곡선 제원은 T. L=33.945, C. L=65.450, E= 5.604 이 고 이는 R=100m일 경우이므로 이를 R=300m로 조정하면 + +- ○ T. L = 33.945×300/100 = 101.835m +- ○ C. L = 65.450×300/100 = 196.350m +- ○ E = 5.604×300/100 = 16.812m +- ○ BC = IP-T. L = 1,150.70-101.835 = 1,048.865m +- ○ EC = IP-T. L+C. L = 1,150.70-101.835+196.350 = 1,245.215m 또한, R = 300m일 때 ℓ= 20m에 대한 편각 δ는 곡선설치표에서 1°54′35"이다. 따라서 (BC 1,048.865m에서 가장 가까운 20배수는 1,060.0m이고, EC 1,245.215m에서 가장 가까운 20의 배수는 1240.0m이므로 +- ○ 시단현 ℓ1 = 60-48.865 = 11.135m +- ○ 종단현 ℓ2 = 45.215-40 = 5.215m 이에 대한 편각 δ1과 δ2는 곡선 설치표에서 R = 300m 란에서 ℓ을 보면, +- ○ 시단현 10m … 0°57′18" +- ○ 종단현 5m … 0°28′39"1m … 0°5′44"0.2m … 0°1′09"0.1m … 0°0′34"+ 0.01m … 0°0′03"+ 0.03m … 0°0′10"δ2 =0°29′51"δ1 =1°3′46"각도를 초(")까지 측정하였으면 비례보간법에 의하여 계산한다. 따라서 BC에서 각 측점말뚝의 편각은 (표 5-2-27)과 같다. 표 5-2-27. BC에서 각 측점의 편각 + +| 측점말뚝(m) | 편각 | 비고 | +|---:|---:|---| +| 1,048.865 | | BC | +| 1,060 | 1°3′46″ | | +| 1,080 | 2°58′21″ | | +| 1,100 | 4°52′56″ | | +| 1,120 | 6°47′31″ | | +| 1,140 | 8°42′06″ | | +| 1,160 | 10°36′41″ | | +| 1,180 | 12°31′16″ | | +| 1,200 | 14°25′51″ | | +| 1,220 | 16°20′26″ | | +| 1,240 | 18°15′01″ | | +| 1,245.215 | 18°44′52″ | EC | + +#### 5) 장애물이 있을 경우의 편각에 의한 곡선설치 +##### 가) 시준선상에 장애물이 있는 경우 + +(그림 5-2-47)의 점 A에서 4)항의 방법으로 점3까지 설치하고 점4의 위치를 설치하고자 할 때 장애물이 있어서 방향선을 정하지 못할 경우에는 다음의 방법으로 정한다. + +- ① (그림 5-2-47) 같이 점 EC에 트랜싯을 설치하고 점 5, 4, 3을 4)항의 방법으로 설치한다. (방법 1) +- ② 점 3에 트랜싯을 세우고, 수평분도원 0°와 버어니어 0을 일치시켜 점 A(BC)를 시준하고 상·하고정나사를 고정시킨 후 망원경을 반전한다. +- ③ 상부고정나사를 풀고 상부를 d3만큼 회전시키면 점 3의 접선이 되므로 4)항의 방법에 의하여 점 4, 5를 측정한다(방법 2). + +![노선측량_그림5-2-47_시준선장애물곡선설치법](<../pic/노선측량_그림5-2-47_시준선장애물곡선설치법.png>) + + +##### 나) 교점(I.P)에 접근하지 못하는 경우 +- ① (그림 5-2-48)과 같이 점 P가 장애물 중에 있어 접근하지 못할 때에는 EP선 과는 DP선의 선상에 각각 임의의 점 a와 b를 정한다. + +![노선측량_그림5-2-48_교점접근불가곡선설치법](<../pic/노선측량_그림5-2-48_교점접근불가곡선설치법.png>) + + +- ② 점 a와 b에 트랜싯을 설치하여 각 θ1, θ2 및 ab의 거리를 측정하여 Aa와 Bb의 거리를 구한다. β1 = 180°- θ1, β2 = 180°- θ2, β3 = 180°- (β1+β +#### 2) + +I = 180°- β₃에서 Pa = (ab·sinβ2) / sinβ3Pb = (ab·sinβ1) / sinβ3Aa = T. L - Pa, Bb = T. L - Pb +- ③ BC와 EC가 결정되면 4)항의 방법에 의하여 곡선을 설치한다. +##### 다) BC와 EC가 모두 장애물 중에 있을 경우 +- ① (그림 5-2-49)와 같이 EP와 DP의 거리를 측정하여 곡선제원을 계산하고 트랜싯을 점 P에 설치하여 θ/2 를 측정하여 PG의 방향을 설정한다. +- ② PG선에 E = PG = R{(sec(I/2) - 1)}이 되도록 점 G를 설정한다. +- ③ 점 G에 트랜싯을 설치하여 PG에 대하여 직각방향 PGD′를 설정하면 GD′는 호의 접선이 되므로 BC와 EC방향의 곡선을 4)항의 방법으로 설정한다. 이때 BC = EP - TL이고,EC = BC + CL 이며, 점 G까지의 거리는 BC + (CL/2)이 된다. 그러므로 전후의 단현을 계산하고 양측의 곡선을 설정한다. + +![노선측량_그림5-2-49_BC와EC장애물곡선설치법](<../pic/노선측량_그림5-2-49_BC와EC장애물곡선설치법.png>) + +그림 5-2-49. BC와 EC에 장애물이 있을 경우의 곡선설치법 + +#### 6) 중앙종거에 의한 곡선설치 + +이 방법은 줄자만으로도 충분히 곡선설치가 가능한 방법으로서 정확을 요하지 않을 경우에 적용된다. + +- ① (그림 5-2-50)에서 교각 I를 측정하고 R을 가정하여 T = R·tan(I/2)로 계산한다. +- ② 점 P에서 TL을 측정하여 BC와 EC점을 결정하고, AB의 거리를 측정하거나 C = 2R·sin(I/2)에 의하여 계산한다. +- ③ M = C2/B을 계산하여 AB의 중점 E를 구하고 PE선에서 M을 측정하여 점 D를 정한다. +- ④ AD의 길이를 측정하여 그 중점 E1에서 직각선을 테이프로 측정하여 M′= M/4 만큼 되는 점 D1을 산정한다. +- ⑤ 다음에 AD1을 연결하여 그 중점에서 M"= M′/4 만큼 되는 점 D2를 측정하여 곡선을 설정한다. 이와 같은 방법으로 EC까지 계속한다. + +![노선측량_그림5-2-50_중앙종거곡선설치법](<../pic/노선측량_그림5-2-50_중앙종거곡선설치법.png>) + + +#### 7) 반향곡선(反向曲線 : Reversed Curve)의 설치 +##### 가) 평행한 2직선 구간을 반향곡선으로 연결할 경우 +- ① (그림 5-2-51)에서 AD//EB라고 하면 점D, E(두곡선의 IP)를 선정하고 DE상의 1점 C(반향점)를 설치하여 CD, CE를 측정한다. +- ② 이때는 이미 접선장(T. L)과 교각(I)를 알고 있으므로 곡선반지름 r과 R을 산출하여 단곡선 설치의 방법 중 한가지를 선택하여 곡선 AC와 곡선 BC를 설정한다. + +![노선측량_그림5-2-51_평행한두직선반향곡선](<../pic/노선측량_그림5-2-51_평행한두직선반향곡선.png>) + + +##### 나) 평행하지 않은 2직선구간을 반향곡선으로 연결할 경우 +- ① (그림 5-2-52)의 점 A에서 HA에 수선을 긋고 AE = R 되는 점 E를 구하고 점 E에서 BK의 연장선상에 그은 수선과 AC호의 연장과 만나는 교점을 점 D라고 하면 +- ② DACB 곡선은 DN선과 MK선이 평행하므로 √DB = a = 2 R·b 가 되고 +- ③ DB의 방향은 sin∠BDN = b / a 이므로 점 B와 점 C를 산출한다. +- ④ BD간을 연결하는 곡선을 단곡선 설치의 방법에 의하여 설치하면 점 A를 통과하는 소요 곡선이 된다. +- ⑤ ∠HAD = 1/2·K, AD = 2 R·sin(1/2·K)이므로 점 D를 설정하고, ∠ADN = 1/2·K이므로 DN의 방향선을 구한다. + +![노선측량_그림5-2-52_평행하지않은두직선반향곡선](<../pic/노선측량_그림5-2-52_평행하지않은두직선반향곡선.png>) + +그림 5-2-52. 평행하지 않은 2직선 구간의 반향곡선 설치법 + +#### 8) 복심곡선(複心曲線 : Compound Curve)의 설치 +- ① (그림 5-2-53)의 점 C를 통과하고 주위의 지형에 적합한 임의의 직선 DCE를 설치하고, ∠PDE(θ)와 ∠PED(θ +#### 1) 의 각을 측정한다. +- ② AC구간 사이에 설치할 곡선의 절선 즉 접선 = DC = TL이라 하면 TL =DC와 θ는 실측에 의하여 값을 정하는 것이므로 R의 값은 R = AO = DO / tan(θ/ 2) = TL /tan(θ/ 2) = TL cot (θ/ 2) +- ③ TL과 R이 결정되면 AC구간은 단곡선으로서 설치될 수 있고, 다음에 TL =EC와 θ1을 실측하여 구하면, R′= BO′= EC / tan(θ1/2) = TL / tan(θ1/2) = TL cot(θ1/2) +- ④ R′를 계산하여 CB구간도 단곡선으로 설치할 수 있다. + +![노선측량_그림5-2-53_복심곡선설치법](<../pic/노선측량_그림5-2-53_복심곡선설치법.png>) + + +#### 9) 배향곡선의 설치 +- ① 배향곡선(背向曲線 : Hair Pin Curve)은 부임도나 작업도를 연결하기에 편리한 곳이지만, 토사유출과 임지내 생산면적의 감소 등으로 인하여 불합리하기 때문에 사면기울기가 40%이하이고 지반이 안정된 곳에 설치하고 동일사면에 1개 이상은 설치하지 않아야 한다. +- ② 곡선내부의 외쪽물매는 5%, 노폭은 6m 정도가 좋으며, 부득이 동일사면에 (그림 5-2-54)와 같이 1개 이상을 설치할 경우에는 다음식에 의하여 적정간격을 구한다. ※ 배향곡선의 적정간격(d) = 0.5·RS·gs / gr 여기서, RS : 적정임도간격(m)gs : 산지사면 기울기(%)gr : 종단물매(%) + +![노선측량_그림5-2-54_배향곡선의간격](<../pic/노선측량_그림5-2-54_배향곡선의간격.png>) + + +- ③ 배향곡선 역시 (그림 5-2-55)와 같이 단곡선의 연속이므로 각각의 접선과 반지름을 결정하여 단곡선의 설정법과 같이 곡선을 설치한다. ㉮ (그림 5-2-55)에서 배향곡선의 반경을 r로 하고, 지형조건에 맞게 점O에서 약 2r~2.5r 떨어진 곳(ℓm)에 점 P, S를 절선상에 설정한다. ㉯ 점 P에서 배향곡선을 둘러싸는 새로운 절선다각형 P, Q, R, S를 설치하면 + +![노선측량_그림5-2-55_배향곡선설치법](<../pic/노선측량_그림5-2-55_배향곡선설치법.png>) + +$$\beta=\cos^{-1}\left(\frac{r}{\ell}\right)$$ + +$$\gamma=\cos^{-1}\left(\frac{r}{\ell}\right)$$ + +$$d=\sqrt{\ell^2-r^2}+r\cot\left(\frac{\alpha+\beta}{2}\right)$$ + +$\ell=2r$로 하면 다음과 같다. + +$$\gamma=30^\circ,\qquad d=r\left\{\sqrt{3}+\cot\left(\frac{\alpha+\beta}{2}\right)\right\}$$ + +㉢ 배향곡선을 현지에 설치할 때에는 먼저 점 P와 S에서 $\gamma$°만큼 곡선 외측으로 비스듬하게 통과하는 선상에서 $d$m 떨어진 점을 구한다. + +㉣ 다음에 이 점들을 교점으로 한 반경 $r$의 원을 절선다각형에 내접시키는 동시에 교점 P와 S에도 약 $1.5r$의 원을 외접시키면 배향곡선이 된다. + +(예제) 광릉시험림 내 임도시설 예정지에서 동일 사면에 배향곡선 2개를 설치해야 한다. 임도간격 300m, 산지사면기울기 40%, 종단물매 9%일 때 적정간격은 $d=0.5\times300\times40/9=666\fallingdotseq700$m이다. + +### 바. 종단곡선의 설치 + +종단물매가 m, n인 두 기울기선이 교차하는 점에서는 물매가 급하게 변화되어 자동차의 안전 운행에 지장을 주게 되므로 그 수직면내에 적당한 곡선을 삽입하여 물매의 변화를 완만하게 하여야 한다. 이때 사용되는 곡선을 종단곡선(縱斷曲線 : Vertical Curve)이라 하며, 보통 포물선(抛物線 : Parabola)이나 반지름이 큰 원곡선(圓曲線)이 사용된다. + +#### 1) 물매의 변화량 산출 + +두 기울기선의 종단물매 대수차는 $|m-n|/100$이다. +#### 2) 종단곡선의 길이 산출 +##### 가) 종단면도에 의한 산출 +- ① 교점이 20m 종선에 있으면, 양 물매차를 5/100로 나눈 값에 가장 가까운 짝수에 20을 곱한다. 3/100과 17/100의 경우 $2.8$에 가장 가까운 짝수 2를 적용하여 $L=2\times20=40$m이다. +- ② 교점이 10m 종선에 있으면, 같은 값에 가장 가까운 홀수에 20을 곱한다. 위 조건이면 홀수 3을 적용하여 $L=3\times20=60$m이다. +- ③ 교점이 20m 종선 사이에 있으면 다음 순서로 정한다. + - 종곡점 위치: 교점에 $\{\text{양 물매차}/(5/100)\}\times10$을 더한 값에 가장 가까운 20m 배수 + - 종단곡선 길이: 종곡점과 교점 거리의 2배에 가장 가까운 20m 배수 + - 시곡점 위치: 종곡점 위치에서 종단곡선 길이를 뺀 값 + +(예제) 교점이 927m이고 물매가 3/100과 17/100이면 보정거리는 28m이다. 종곡점은 $(927+28)$에 가장 가까운 20m 배수인 960m, 곡선길이는 $(960-927)\times2$에 가장 가까운 20m 배수인 60m, 시곡점은 $960-60=900$m이다. +##### 나) 종단곡선의 길이를 주행속도로서 산출 + +$$L=|i_1-i_2|\frac{V^2}{360}$$ + +계산값에 가장 가까운 10m 배수를 취한다. 여기서 $V$는 주행속도(km/hr), $|i_1-i_2|$는 종단물매 대수차의 절대값(%), 360은 불쾌감을 주지 않는 충격변화율을 결정하는 계수이다. + +표 5-2-28. 설계속도별 최소종단곡선의 길이 + +| 설 계 속 도(km/hr) | 20 | 30 | 40 | 50 | +|---|---|---|---|---| +| 곡 선 길 이(m) | 20 | 25 | 35 | 40 | + +(예제) 안부의 물매가 +10%와 -10%, 설계속도가 30km/hr이고 산복구간의 물매가 5%와 9%, 설계속도가 40km/hr일 때: + +- ① 안부구간: $L=|10-(-10)|\times30^2/360=50$m +- ② 산복구간: $L=|5-9|\times40^2/360=17.8\fallingdotseq20$m + +※ 안부: 말안장을 의미한다. +##### 다) 가시거리로서 종단곡선의 길이 산출 +- ① 가시거리 $S>L$인 경우: $L=2S-\dfrac{2(\sqrt{h_1}+\sqrt{h_2})^2}{G}$ (그림 5-2-56 ⓐ) +- ② 가시거리 $S) + + +#### 3) 종단곡선의 반지름 산출 + +$$R\fallingdotseq\frac{100L}{|i_1-i_2|}$$ + +(예제) 앞 예제에서 $R=(100\times40)/|17-3|=285.7\fallingdotseq280$m이다. + +![노선측량_그림5-2-57_종단곡선길이별가시거리](<../pic/노선측량_그림5-2-57_종단곡선길이별가시거리.png>) + +그림 5-2-57. 종단곡선길이(L)와 가시거리(S)의 관계(h1=1.4m, h2=0.5m인 경우) + +#### 4) 종거의 산출 + +$$Y_n=\frac{1}{2L}\cdot\frac{d}{100}\chi^2=\frac{|i_1-i_2|}{200L}\chi^2$$ + +- $Y_n$: 횡거 $\chi$에 대한 종거(m) +- $L$: 종단곡선의 길이(m) +- $d$: 인접한 두 기울기선의 물매차 절대값(%)인 $|i_1-i_2|$ +- $\chi$: 종단곡선의 시점 또는 종점에서 종거를 구하는 점까지의 횡거(m) + +![노선측량_그림5-2-58_종단곡선측점종횡거](<../pic/노선측량_그림5-2-58_종단곡선측점종횡거.png>) + +그림 5-2-58. 종단곡선상 각 측점의 종횡거 산출 + +(예제) 앞의 예제에서 종단곡선의 시곡점과 종곡점 사이에 위치한 각 측점의 종거를 구하여라. 두 기울기선의 물매차는 14%, 종단곡선의 길이는 60m이다. + +- ① 시곡점 : 810-(60/2) = 780m +- ② 종곡점 : 810+(60/2) = 840m +- ③ 그림 5-2-58을 참고하면 800m와 820m에 위치한 측점은 종단곡선의 시·종곡점으로부터의 횡거가 각각 20m이므로 종거가 동일하다. $Y_1=Y_3=(14\times20^2)/(200\times60)=0.47\,\mathrm{m}$ +- ④ 810m에 위치한 측점은 종단곡선 시곡점으로부터의 횡거가 30m이므로 $Y_2=(14\times30^2)/(200\times60)=1.05\,\mathrm{m}$ +#### 5) 종단곡선상의 표고 산출 + +$$H_n'=H_n\pm\frac{i}{100}\chi,\qquad H_n=H_n'\pm Y_n$$ + +- $H_n'$: B.C 또는 E.C에서 $\chi$만큼 떨어진 점의 표고(m) +- $H_n$: B.C 또는 E.C의 표고 또는 종단곡선상의 표고(m) +- $Y_n$: B.C 또는 E.C에서 $\chi$만큼 떨어진 점과 곡선과의 종거(m) + +(예제) 앞의 예제에서 각 점의 표고를 구하여라. 단, B.C의 표고는 100.57m이다. + +- ① 780m 지점: $H_0=100.57\,\mathrm{m}$ +- ② 800m 지점: $H_1'=100.57+(3/100)\times20=101.17\,\mathrm{m}$, $Y_1=0.47\,\mathrm{m}$, $H_1=101.64\,\mathrm{m}$ +- ③ 810m 지점(V): $H_2'=100.57+(3/100)\times30=101.47\,\mathrm{m}$, $Y_2=1.05\,\mathrm{m}$, $H_2=102.52\,\mathrm{m}$ +- ④ 820m 지점: $H_3'=101.47+(17/100)\times10=103.17\,\mathrm{m}$, $Y_3=0.47\,\mathrm{m}$, $H_3=103.64\,\mathrm{m}$ +- ⑤ 840m 지점(V+30m): $H_4'=101.47+(17/100)\times30=106.57\,\mathrm{m}$, $H_4=106.57\,\mathrm{m}$ +### 사. 구조물 및 지질조사 + +구조물(교량, 배수구, 석축 등)을 설치할 필요가 있는 개소의 위치, 지형, 자재 채취의 양부 등을 상세하게 조사하거나 측량을 실시하여 필요한 자료를 구한다. + +#### 1) 구조물 조사 +##### 가) 교량류 : 교량, 암거(BOX) 등 +- ① 중심선과 유수의 각도 및 방향 +- ② 유수량과 H. W. L, L. W. L +- ③ 교대 교각예정 위치 부근의 토질 +- ④ 유수의 유무 +- ⑤ 하천의 관리상태 +- ⑥ 교량의 형식 +- ⑦ 기타 필요사항 +##### 나) 구거류 : 배수관, 개거 등 +- ① 설치해야 할 위치 및 중심선과의 방향각도 +- ② 집수면적, 유수량 +- ③ 지반토질 +- ④ 기타 필요사항 +##### 다) 옹벽류 : 옹벽, 석축(찰쌓기,메쌓기) 등 +- ① 설치위치, 연장, 높이 +- ② 지반상황, 토압관계 +- ③ 유수, 수심 +- ④ 기타 필요사항 +#### 2) 공사재료조사 +- ① 공사재료로 채취할 경우에는 채취위치, 품질형상, 양, 운반거리 및 운반로상황, 소유자, 채취료 등 +- ② 또한 필요가 있을 때에는 공사재료로서의 적합성을 평가하기 위한 품질시험을 한다. +#### 3) 토취장, 토사장조사 +- ① 공사실행에 있어서 토취장, 토사장이 필요할 경우에는 위치, 운반거리, 운반로상황, 채취(또는 버릴)가능량, 소유자 등 +- ② 이 경우 토사장의 토사유출 방지시설을 필요로 할 때는 시설에 관한 충분한 조사를 한다. +#### 4) 장해물 조사 + +공사에 지장이 되는 가옥, 전주 등 구조물과 전답, 묘지, 구거, 용수로 등에 관해서는 명칭, 위치, 수량, 소유자 등에 대해서도 조사한다. + +### 아. 용지측량 +#### 1) 용지측량방법 +- ① 임도용지는 측점마다 횡단면의 중심선에서 경사면의 길이, 즉 절토사면의 머리위에서 성토사면의 끝아래까지 거리를 측정하고 측점마다 이 보다 약간의 여유(보통 1m 정도)를 더하여 측정한다. +- ② 현지에서 그 점에 말뚝을 박아 용지경계를 명시하고 지적도, 토지대장 등을 참조하여 임도부지에 대해 소유자별 지번별, 지목별 면적을 측정한다. +- ③ 사용기종 : 트란싯트 또는 평판 +#### 2) 용지측량시 조사사항 +- ① 해당용지의 소유자명, 지번, 지목 +- ② 해당용지의 지상권, 지역권(地域權), 저당권, 임대차에 따른 권리, 기타 제권리 등의 유무 +- ③ 해당용지의 경계에 관한 기록 및 도면 유무와 그 내용 +- ④ 해당용지 내의 도로, 하천, 용수로, 관거류 등의 부지형상, 노폭 등 +- ⑤ 용지도 작성의 기본이 되는 삼각점 기준점의 종류, 내용 +- ⑥ 행정구역계 및 인접지의 상태 +- ⑦ 지형지물 기타 필요한 사항 +- ⑧ 편입지의 범위 : 구조물 주위 1m 내외 + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 48~86쪽 (인쇄면 418~456쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/5. 설계.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/5. 설계.md new file mode 100644 index 00000000..b4173e6b --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/5. 설계.md @@ -0,0 +1,652 @@ +# 5. 설계 + +### 가. 설계서 + +광의의 설계서는 종합보고서, 설계서, 예산내역서, 단가산출서, 수량산출서 및 설계도면을 포함한다. + +#### 1) 종합보고서 +- ① 과업에 대한 개요 : 과업의 목적, 과업의 범위와 내용, 기타 지시사항 등 +- ② 기본계획에 대한 개요 +- ③ 환경에 미치는 영향과 대책 : 자연환경, 생활환경, 사회경제적 환경 +- ④ 기본조사와 측량내역 : 지역현황, 측량, 수문, 토질, 재료원, 구조물, 용지 및 지장물 +- ⑤ 실시설계 : 설계기준, 설계선형, 토공, 배수공, 포장, 부대시설 등 +- ⑥ 공사개요 : 주요자재, 주요공사수량, 공사비 산출 +- ⑦ 부록 : 측량기준점 조서, 수리계산서, 토질보고서 등 부속자료 +#### 2) 설계서 +- ① 설계설명서 : 공사목적, 공사내용(공사명, 위치, 연장), 공사개요, 소요자재, 골재원, 사용중기, 공사기간, 설계변경조건, 보안대책, 설계적용기준 등 +- ② 특별시방서 +- ③ 일반시방서 +- ④ 예정공정표 +- ⑤ 동원인원계획표 +### 나. 설계도면 +#### 1) 평면도 +##### 가) 축척과 위치 +- ① 축척 : 1/1,000 또는 1/1,200 +- ② 작성위치 : 종단면도의 상단여백에 도표 +##### 나) 중심선 제도법 +- ○ 합위거 및 합경거에 의한 트래버어스의 제도법 트래버어스 측량에서 임의의 한 측점을 원점(0, 0)으로 하고, 이 점을 지나는 자오선(NS선)과 + +동서선(EW선)을 직각좌표축(直角座標軸)으로 하여 이 좌표축에 대한 다른 측점의 좌표를 그측점의 위거 및 경거로 표시한 것을 합위거(合緯距 : Total Latitude) 및 합경거(合經距 : TotalDeparture)라 한다. 합위거 및 합경거에 의한 트래버어스의 제도법은 다음과 같은 장점이 있다. + +- ① 제도하기 전에 측량의 오차를 찾아서 이를 배분할 수 있다. +- ② 각 점의 위치가 합위거 및 합경거에 의하여 결정되어 있으므로 도면의 크기와 배치를 쉽게 할 수 있다. +- ③ 제도상의 오차가 누적하지 않고 정확하게 측점위치가 정해진다. + +합위거 및 합경거에 의한 트래버어스제도의 방법은 다음과 같다. + +- ㉮ 다음 식에 의해 각 측점의 합위거 및 합경거를 구한다. + - 각 측점의 합위거(합경거) = 원점부터 그 측점까지의 위거(경거)의 합 +- ㉯ 각 측점의 위거와 경거 중에서 최대 (+), (-)값을 찾아서 이를 기준으로 적당한 지점에 원점의 위치를 정한다. +- ④ 원점을 교점으로 하는 직각좌표축을 그린 후, 각 측점의 합위거 및 합경거를 도면에 전개시킨다. + +(예제) 트래버어스측량 결과를 표 5-2-29와 같이 얻었다. 이에 대한 폐합오차를 조정하고 그 결과를 이용하여 측점 A를 원점으로 하여 각 측점의 합위거와 합경거에 의해 제도하여라. + +표 5-2-29. 트래버어스측량 결과 및 조정 + +| 측선 | 거리 (m) | 위거 (+) | 위거 (-) | 위거 조정량 (m) | 경거 (+) | 경거 (-) | 경거 조정량 (m) | 조정위거 (+) | 조정위거 (-) | 조정경거 (+) | 조정경거 (-) | +|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| AB | 10.60 | 6.54 | | +0.03 | 8.38 | | -0.05 | 6.57 | | 8.33 | | +| BC | 4.10 | | 3.56 | -0.02 | 2.03 | | -0.01 | | 3.54 | 2.02 | | +| CD | 7.69 | | 6.54 | -0.03 | | 4.05 | +0.02 | | 6.51 | | 4.07 | +| DA | 7.13 | 3.46 | | +0.02 | | 6.24 | +0.04 | 3.48 | | | 6.28 | +| 합계 | 29.52 | 10.00 | 10.10 | +0.10 | 10.41 | 10.29 | -0.12 | 10.05 | 10.05 | 10.35 | 10.35 | +| 폐합차 | | | -0.10 | | +0.12 | | | | | | | + +#### 풀이 + +폐합오차와 폐합비는 다음과 같다. + +$$ +\text{폐합오차}=\sqrt{0.10^2+0.12^2}=0.16 +$$ + +$$ +\text{폐합비}=\frac{0.16}{29.52}=\frac{1}{185} +$$ + +- 위거 절대값의 총계: $6.54+3.56+6.54+3.46=20.10$ +- 경거 절대값의 총계: $8.38+2.03+4.05+6.24=20.70$ + +| 측선 | 위거의 조정량 | 경거의 조정량 | +|---|---:|---:| +| AB | $0.10\times6.54/20.10=0.03$ | $0.12\times8.38/20.70=0.05$ | +| BC | $0.10\times3.56/20.10=0.02$ | $0.12\times2.03/20.70=0.01$ | +| CD | $0.10\times6.54/20.10=0.03$ | $0.12\times4.05/20.70=0.02$ | +| DA | $0.10\times3.46/20.10=0.02$ | $0.12\times6.24/20.70=0.04$ | +| 합계 | 0.10 | 0.12 | + +※ 트렌싯법칙에 의한 트래버어스 폐합오차의 조정 + +트렌싯법칙(transit rule)은 각도는 트렌싯, 거리는 테이프를 써서 측정하는 경우로서 거리측정의 정도(精度)가 각 측정의 정도에 비하여 불완전할 때에 사용되는 방법으로서 폐합오차를 위거와 경거의 길이에 비례해서 배분하는 것이다. + +$$ +\text{임의 측선의 위거 조정량} +=\varepsilon_{\ell}\times +\frac{\text{해당 측선의 위거(측선의 길이)}}{\text{위거 절대값의 총계(측선 길이의 총계)}} +$$ + +$$ +\text{임의 측선의 경거 조정량} +=\varepsilon_d\times +\frac{\text{해당 측선의 경거(측선의 길이)}}{\text{경거 절대값의 총계(측선 길이의 총계)}} +$$ + +※ 괄호 안은 컴퍼스법칙을 사용할 경우이다. + +표 5-2-30. 트래버어스 폐합오차 조정결과 + +![설계_그림5-2-59_합경거와합위거](<../pic/설계_그림5-2-59_합경거와합위거.png>) + +| 측선 | 조정위거 (+) | 조정위거 (-) | 조정경거 (+) | 조정경거 (-) | 합위거 | 합경거 | +|---|---:|---:|---:|---:|---:|---:| +| AB | 6.57 | | 8.33 | | +6.57 | +8.33 | +| BC | | 3.54 | 2.02 | | +3.03 | +10.35 | +| CD | | 6.51 | | 4.07 | -3.48 | +6.28 | +| DA | 3.48 | | | 6.28 | 0.00 | 0.00 | + +그림 5-2-59. 합경거, 합위거에 의한 트래버어스제도(예) + +- ○ 분도기에 의한 트래버어스의 제도법 + +트래버어스의 제도법 중 가장 간단한 방법이지만, 아무리 주의하여도 최후에 폐합오차가 생기 + +므로 정밀을 요하지 않을 경우나 좌표계산을 할 시간이 없을 경우를 제외하고는 사용하지 않는 것이 좋다. + +- ① 원점 A에서 분도기로 방향을 결정하여 임의의 선 AB′를 긋고, 적정한 축척으로 거리를 재어 점 B를 도시한다. +- ② 점 B에서 다시 분도기로 방향을 결정하여 임의의 선 BC′를 긋고, 적정한 축척으로 거리를 재어 점 C를 도시하는 방법으로, 점 D, E, … 를 결정하여 제도해 나간다. +- ○ 탄젠트의 값에 의한 트래버어스의 제도법 + +분도기를 사용하지 않고 탄젠트의 값에 의해 제도할 수 있다. 예를 들어 AB선과 자오선(NS선)의 편각이 28°30′이고, BC선과 AB선의 편각이 35°23′이라면 제도방법은 다음과 같다. +- ① 그림 5-2-60과 같이 기준선 NS선상의 임의의 점 A에서 $Aa'=10\,\mathrm{cm}$가 되도록 점 $a'$를 정하고 수직선 $aa'$를 긋는다. +- ② AB선과 NS선의 편각에 대한 탄젠트 값을 구하고 이를 이용하여 점 $a$를 결정한다. 즉, $\tan 28^\circ30'=0.543=5.43/10$이므로 $aa'$의 길이는 5.43cm이다. + +![설계_그림5-2-60_탄젠트값트래버어스제도](<../pic/설계_그림5-2-60_탄젠트값트래버어스제도.png>) + +그림 5-2-60. 탄젠트값에 의한 트래버어스제도(예) + +- ③ 점 A와 $a$를 연결하면 NS선에 대하여 $28^\circ30'$인 직선을 구할 수 있으므로, $Aa$ 선상이나 연장선상에 적당한 축척의 AB 길이를 취하여 점 B를 정한다. +- ④ AB선을 연장하여 $Bb=10\,\mathrm{cm}$가 되도록 점 $b$를 정하고 수직선 $bb'$를 긋는다. BC선과 NS선의 편각에 대한 탄젠트 값($\tan 35^\circ23'=0.710$)의 10배인 7.10cm를 취하여 점 $b'$를 정한다. 점 B와 $b'$를 연결하면 AB에 대하여 $35^\circ23'$인 직선이 되므로, $Bb'$ 선상이나 연장선상에 적당한 축척의 BC 길이를 취하여 점 C를 정한다. +- ⑤ 이와 같은 방법을 반복한다. + +※ 방위각에서 편각을 구할 때는 다음 식을 이용한다. + +- ㉮ 편각 = 측선의 방위각 - 전 측선의 방위각 +- ㉯ 시계방향(+)이고 절대값이 180° 이상인 경우: 조정편각 = 360° - 편각 +- ㉰ 시계반대방향(-)이고 절대값이 180° 이상인 경우: 조정편각 = 360° + 편각 + +(예제) 측선 AB의 방위각이 26°16′30″이고 측선 BC의 방위각이 236°27′00″일 때 편각과 조정편각을 구하여라. + +- 편각 = 26°16′30″ - 236°27′00″ = -210°10′30″ +- 180° < 210°10′30″이고 부호가 (-)이므로 조정편각 = 360° - 210°10′30″ = 149°49′30″ + +- ○ 사인 및 코사인의 값에 의한 트래버어스의 제도법 + +사인 또는 코사인의 값으로 트래버어스를 제도할 수 있다. 예를 들어 기준선 PQ에서 35°20′의 각을 이루는 직선 AB를 그을 때 제도방법은 다음과 같다. + +- ① 그림 5-2-61과 같이 임의의 선 PQ상에 점 A를 설정한 후, PQ와 AB선이 이루는 각(35°20′)의 사인 및 코사인 값을 구한다. $\sin 35^\circ20'=0.578$, $\cos 35^\circ20'=0.816$ +- ② 점 A에서 코싸인 값의 10배, 즉 8.16 cm 와 같게 점 a′를 PQ선상에서 취한다. +- ③ 점 a'에서 PQ선에 수직선을 그어 그 길이를 싸인의 10배, 즉 5.78cm와 같게 점 a를 정한다. +- ④ 점 A와 $a$를 연결하면 $\angle aAa'=35^\circ20'$이므로, 그 연장선상에서 적당한 축척의 AB 길이를 취하여 점 B를 정한다. +- ⑤ 이와 같은 방법을 반복한다. + +![설계_그림5-2-61_삼각함수값트래버어스제도](<../pic/설계_그림5-2-61_삼각함수값트래버어스제도.png>) + +그림 5-2-61. sin, cos 값에 의한 트래버어스제도(예) + +##### 다) 측점과 곡선제도법 +- ① 트레버어스제도법으로 중심선의 골격이 제도되고 나면 (표 5-2-31)과 같이 각 교점(IP)마다 곡선제원을 계산하고 시점(BP)에서부터 측점말뚝은 일련번호(예 No.11)로 하고 보조 말뚝은 그 측점에서 떨어진 거리(예 No.11+13)로 표기하는 보조측점을 부여한다. + +| 표5-2-31. 교점제원과선형계산(예) | | | | | | | | | | | | | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| ○교점번호: BP | | | | | | | | | | | | | +| 좌 표 | | X | | 470740.500 | | 방위각 | | | | | 188°39′19.41″ | | +| | | Y | | 142679.000 | | | | | | | | | +| ○교점번호: IP1 (좌향) | | | | | | | | | | | | | +| 곡선종류 | | 원곡선 | | | IP좌표 | | | X | | 470697.8000 | | | +| | | | | | | | | Y | | 142672.5000 | | | +| 방위각 | 1 | 188°39′19.41″ | | | 원중심좌표 | | | X | | 470720.5531 | | | +| | 2 | 111°55′46.52″ | | | | | | Y | | 142712.3783 | | | +| IA | 76°43′32.90″ | | | | R | | 36.0000 | | | 거리 | | 43.1919 | +| TL | 28.4953 | | | | SL | | 9.9128 | | | CL | | 48.2083 | +| ○측점별위치및제원표 | | | | | | | | | | | | | +| 구분 | 누가거리 | | 측점(No) | | X좌표 | | | | Y좌표 | | | 방위각 | +| BP | 0.0000 | | 0+00.0000 | | 470740.50 | | | | 142679.00 | | | | +| BC | 14.6966 | | 0+14.6966 | | 470725.97 | | | | 142676.79 | | | 188°39′19.41″ | +| | 20.0000 | | 1+00.0000 | | 470720.69 | | | | 142676.38 | | | 180°12′53.06″ | +| | 40.0000 | | 2+00.0000 | | 470701.68 | | | | 142681.72 | | | 148°23′ 1.50″ | +| | 60.0000 | | 3+00.0000 | | 470688.35 | | | | 142696.29 | | | 116°33′ 9.94″ | +| EC | 62.9049 | | 3+02.9049 | | 470687.16 | | | | 142698.93 | | | 111°55′46.52″ | + +- ② 교점에서 절선장(TL)을 끊어 시곡점{(BC), IP간의 거리(43.1919m) - TL(28.4953m) =BC(14.6966m)} 종곡점{(EC), BC(14.6966m) + CL(48.2083m) = EC(62.9049m)}의 측점을 부여하고 교점 내각의 2등분선 방향으로 외할장(E, SL)만큼 중곡점(MC)을 부여한다. +- ③ 시곡점과 종곡점에서 각 절선에 대한 수직선을 내려 만나는 점이 곡선의 중심(0)이 되며 그 길이를 곡선 반지름으로 하여 단곡선을 그리면 중심선의 곡선부가 된다. +- ④ 이를 계속하여 다음 교점까지 가서 ②와 ③의 작업을 반복하면 직선과 곡선이 어울려 조화를 이루는 하나의 평면 선형이 완성된다. +##### 라) 노폭, 용지폭, 현황 등 제도법 +- ① 평면선형이 완성되면 각 측점마다 노폭, 측구폭, 절토사면폭, 성토사면폭, 사면구조물폭 등의 시공폭 및 용지폭을 횡단면도를 참고하여 도시하고 연결하되 노폭을 진하게 하고 그 외의 선은 조금 가늘게 도시한다. +- ② 종단면도에서 계산된 지반고를 각 측점마다 부여한 후 평판과 트랜싯의 스타디아 측량에 의하여 현황측량을 실시하여 지형의 상태와 교량, 배수구, 옹벽, 석축, 경작지의 경계선, 가옥, 기설도로 등의 지물에 대한 위치와 크기, 등고선을 측정 도시한다. +- ③ 노선이 연속되어 도면이 나누어 질 경우에는 절취선이 겹쳐지게 하여 선형의 방향이 흐트러지지 않도록 하고, 시설 계획된 구조물을 시설위치마다 명칭, 치수 및 수량을 기재한다. +- ④ 각 교점에 대한 곡선제원표를 도면의 상단 또는 하단의 빈 공간에 기록한다. + +![설계_그림5-2-62_평면도작성예](<../pic/설계_그림5-2-62_평면도작성예.png>) + +그림 5-2-62. 평면도 작성(예) + +#### 2) 종단면도 +##### 가) 축척 : 수평 1/1,000 또는 1/1,200(평면도의 축적과 같게 한다), 수직 1/200 +##### 나) 제도방법 +- ① 1m/m 눈금의 방안지에 아래서부터 평면선형, 측점, 거리, 누가거리, 지반고, 계획고, 절토고, 성토고, 종단선형의 란으로 구분하고, 횡(수평)축을 거리(m)로 표시하고 종(수직)축은 높이(표고 : m)로 표시한다. +- ② 평면선형란에는 평면도에서 작성된 곡선방향을 진행방향으로 오른쪽으로 회전하면 위쪽이 볼록(凸)하게 왼쪽으로 회전하면 아래쪽이 볼록하게 도시하고, 앞과 뒤의 곡부는 BC,EC의 측점에 맞게 도시하여 교점번호(IP)를 기재하며 그외 곡선제원을 곡선형의 여백에 기재한다. +- ③ 측점은 평면도에서 작성된 측점번호와 같아야 하며, 거리는 측점간의 거리이고, 누가거리는 시점에서부터 누진되는 거리를 기록한다. +- ④ 지반고는 종단측량에서 측정계산된 현지의 지반고를 기재하고, 각 측점별로 종축의 높이에 맞게 막대그래프를 그려 중심선의 지반 선형을 나타낼 수 있도록 연결한다. +- ⑤ 계획고는 측점별 임도노면의 시공 높이가되며 이를 연결한 선형이 종단계획선이다. + +![설계_그림5-2-63_종단면도작성예](<../pic/설계_그림5-2-63_종단면도작성예.png>) + +그림 5-2-63. 종단면도 작성(예) + +계획선은 임도의 구조와 공사비에 직접적인 영향을 미치게 되므로 성토량과 절토량의 균형이 맞고 계획구배의 선형이 임도 내부에서 유로(流路) 방향이 된다는 것을 명심하여 알맞게 설정하여야 한다. 영선측량법에서는 측량자가 종단물매, 지형조건, 공사의 난이성, 경제성 등을 참고하여 종단계획선 위주로 측량하기 때문에 설계 시에 문제를 발생시키는 일이 거의 없다. 그러나 중심선측량법에서는 평면측량→평면도, 종단측량→종단면도, 횡단측량→횡단면도의 과정을 모두 마친 후 입체적으로 검토하여야 하므로 현지 지형조건과 각 선형조건에 부합되게 설정하기가 어렵다. + +평면선형과 종단선형으로 예를 들면 그림 5-2-64(a)와 같은 선형은 양호하나 (b)와 같은 선형은 불량한 선형계획이 될 것이다. 따라서 종단계획선의 설정 시에는 물매, 지형조건, 공사의 난이도, 경제성에 알맞도록 신중을 기하여야 한다. + +![설계_그림5-2-64_평면선형과종단선형](<../pic/설계_그림5-2-64_평면선형과종단선형.png>) + +그림 5-2-64. 평면선형과 종단선형의 결정 + +- ⑥ 성토고와 절토고란은 지반고>계획고일때 절토고에 그 차를 기재하고, 지반고<계획고이면성토고에 그 차를 기재한다. +- ⑦ 종단선형란은 계획선이 같은 물매로 되는 No. a와 No. b 구간에 대한 물매(%)를 말하며, 측점표고가 a>b일 경우에는 하향선(\), a 0 이므로 절토고 +#### 3) 횡단면도 +##### 가) 축척 : 1/100 +##### 나) 제도방법 +- ① 1mm 눈금크기의 방안지에 임도시점부터 진행방향으로 좌측 아래부터 적정한 간격을 유지하며 각 측점별로 횡단측량한 결과를 중심점을 기준으로 좌우의 지반선을 도시한다. +- ② 각 측점마다 종단면도에서 결정된 계획고에 따른 성토고, 절토고만큼 성토할 경우에는 중심점의 상단에, 절토를 할 경우에는 중심점의 하단에, 노면과 측구의 시공기면을 계획된 구조와 치수에 따라 도시한다. +- ③ 길끝(路端) 양편에서 토질과 공종에 따라 절취, 성토, 석축, 옹벽, 등의 사면 기울기에 따라 지반선과 만날때까지 선을 긋고 구조형태에 따라 축조모형을 도시한다. 만약 동일측점에서 보통토사, 견질토사, 보통암, 풍화암, 경암 등 토질이 다를 경우에는 토질구분선을 도시한다. +- ④ 도면작성이 완성되면 토질별 절취·성토단면적은 삼각형법 또는 구적기를 이용하여 단면적을 산출하고 석축, 옹벽, 떼 등은 공종별 길이를 측정한다. +- ⑤ 각 측점별로 횡단면도의 하단부에 측점(No), 지반고{Ground Height(GH)}, 계획고{Formation Height(FH)}, 절취고{Cutting Height(CH)}, 성토고{Banking Height(BH)}를 기재하고, 절토단면적, 절토사면장은 토성별로 기재하며 성토단면적, 성토사면장, 옹벽, 석축, 줄떼, 평떼, 종자뿌리기 등은 공종별로 수량을 기재한다. + +| STA NO. 3 | | | | | | | | | +|---|---|---|---|---|---|---|---|---| +| 지 반 고 | | 719.46 | 측구 터파기 | 토 사 | 0.5 | 노상 준비 | 기존도로 | | +| 계 획 고 | | 720.38 | | 리핑암 | | | 절토면 | | +| 성 토 고 | | 0.92 | | 발파암 | | 되메우기 | | | +| 절 토 고 | | | 측구흙쌓기 | | | 줄 떼 | | 4.9 | +| 흙 깍 기 | 토 사 | 4.2 | 답 표토 제거 | 절토부 | | 평 떼 | | 5.1 | +| | 리 핑 암 | | | 노 상 | | 벌개제근 | | 16.6 | +| | 리퍼 병행암 | | | 노 체 | | | | | +| | 편절 형암 | | 답외 표토 제거 | 절토부 | | | | | +| 흙 쌓 기 | 노 상 | 3.9 | | 노 상 | | 층 따 기 | 노 상 | 0.9 | +| | 노 체 | 3.1 | | 노 체 | | | 노 체 | | + +| STA NO. 11 | | | | | | | | | +|---|---|---|---|---|---|---|---|---| +| 지 반 고 | | 726.26 | 측 구 터 파 기 | 토 사 | 1.6 | 노 상 준 비 | 기존 도로 | | +| 계 획 고 | | 726.70 | | 리 핑 암 | | | 절 토 면 | 0.5 | +| 성 토 고 | | 0.44 | | 발 파 암 | | 되 메 우 기 | | | +| 절 토 고 | | | 측 구 흙 쌓 기 | | | 줄 떼 | | 3.8 | +| 흙 깍 기 | 토 사 | 0.9 | 답 표 토 제 거 | 절 토 부 | | 평 떼 | | | +| | 리 핑 암 | | | 노 상 | | 벌 개 제 근 | | 12.1 | +| | 리퍼 병행암 | | | 노 체 | | | | | +| | 편 절 형 암 | | 답 외 표 토 제 거 | 절 토 부 | | | | | +| 흙 쌓 기 | 노 상 | 3.0 | | 노 상 | | 층 따 기 | 노 상 | | +| | 노 체 | 0.9 | | 노 체 | | | 노 체 | | + +그림 5-2-65. 횡단면도 작성(예) + +#### 4) 구조물도 +- ① 임도의 시공기면은 노폭, 절취 및 성토상태에 따라 교량, 배수구, 석축, 옹벽 등의 보호시설이 필요할 경우가 있다. 이들 구조물은 정확하고 견고한 시공을 도모하기 위하여 공종별로 각각 그 내용을 명시한 정면도, 평면도, 측면도 등의 단면도를 임의의 축적으로 작성한다. +- ② 국부적으로 필요한 경우에는 그 부분을 확대한 상세도를 그리고 공종별로 재료별 수량과 규격을 도시한다. +- ③ 구조가 간단한 경우에는 규정도나 종·횡단면도에 명시한 것으로서 구조물도를 대체할 수 있으나 주요구조물에 대하여는 다음 사항을 도시 또는 기재한다. ㉠ 설계조건 ㉡ 소요재료표 및 수량조서 ㉢ 중심선 및 측점과의 관계 ㉣ 시공기면과의 관계 ㉤ L. W. L 및 H. W. L의 관계 - 수위와 관계가 있을 경우 ㉥ 각 부분의 형상, 방법, 물매 등 ㉦ 기타 필요한 사항 + +![설계_그림5-2-66_구조물도](<../pic/설계_그림5-2-66_구조물도.png>) + +그림 5-2-66. 구조물도 작성(예) + +#### 5) 표준도 +- ① 공사시공 기면에 대한 치수, 재료 및 형상 등을 명시한 것을 공사규정이라고 하고, 이를(그림 5-2-67)과 같이 일정하고 공통적인 사항에 대하여 도면으로 그 기준을 표시한 것을 표준도라고 한다. +- ② 다음 사항에 관하여 일정한 규정을 정한 경우에는 표준도를 작성한다. ㉠ 절취, 성토, 측구 등 시공기면의 조성폭과 기울기 ㉡ 암벽의 최소 덮은 두께 및 기초구조 등 ㉢ 석축공의 기울기, 공장도, 뒷채움 두께, 콘크리트 두께 등 ㉣ 콘크리트 옹벽공의 상부 두께 ㉤ 돌망태의 사면기울기, 뒷채움 두께 ㉥ 기타 필요한 사항 + +![설계_그림5-2-67_표준도작성예](<../pic/설계_그림5-2-67_표준도작성예.png>) + +그림 5-2-67. 표준도 작성(예) + +#### 6) 용지도 및 용지조서 +- ① 계획노선의 중심선, 시공부지의 경계선(일반적으로 절토사면 머리부터 성토사면 끝까지)을 지적도와 임야도를 기준으로 실시한 용지측량의 결과를 1/600 또는 법정도면의 축척으로 그림 5-2-68과 같이 용지도를 작성한다. + +![설계_그림5-2-68_용지도작성예](<../pic/설계_그림5-2-68_용지도작성예.png>) + +그림 5-2-68. 용지도 작성(예) +- ② 임야대장, 토지대장을 기준으로 택지, 농경지, 임야 등을 행정구역별, 소유별, 지목별, 소유자별로 면적을 산출하고 표 5-2-32와 같은 용지조서를 작성한다. + +표 5-2-32. 용지조서(예) (단위: m²) + +| 일 련 번 호 | 소 재 지 | | | | 공 부 상 | | 실 편 입 | | 소 유 자 | | | +|---|---|---|---|---|---|---|---|---|---|---|---| +| | | | | | | | | | | | 비고 | +| | 군 | 면 | 리 | 지 번 | 지 목 | 지 적 | 지 목 | 지 적 | 주 소 | 성 명 | | +| 1 | 홍천 | 내 | 자운 | 산50-1 | 임 | 4,064,436 | 임 | 61,299 | 국(산림청) | | | +| 2 | 〃 | 〃 | 〃 | 1177 | 임 | 1,491 | 임 | 974 | 홍천, 내, 자운, 126 | 박종식 | | +| 3 | 〃 | 〃 | 〃 | 1198-1 | 도 | 5,92 | 도 | 172 | 국 | | | +| 4 | 〃 | 〃 | 〃 | 1481 | 구 | 21,462 | 구 | 110 | 국(건설부) | | | + +#### 7) 위치도 +- ① 위치도에는 기설도로, 기설임도 등의 주요지형지물, 시설예정 임도의 위치, 이용구역, 토취 장, 토사장, 골재 및 자재채취장, 자재운반관계를 명시하여 1/25,000 또는 1/50,000 지형도에 작성한다. +- ② 계획노선은 기점과 종점, 시설예정길이, 공구가 구분될 경우에는 공구계, 계속공사일 경우에는 시설(예정)년도를 기재한다. +### 다. 공종과 수량산출 +#### 1) 공종구분 + +공사원가계산의 기본이 되는 공종은 공사의 종류에 따라 다르지만 일반적으로 공사발주기관에서 따로 정하지 아니하면 건설표준품셈표에 의하여 구분한다. + +#### 2) 공사수량의 산출 +##### 가) 체적과 면적의 산출 +- ① 공종별 공사수량은 구조가 간단한 것은 표준도나 종·횡단면도에 의하여 단면적(또는 높이)과 길이가 산출되지만 주요구조물은 구조물도의 재료표에 의하여 직접 그 수량을 적용한다. +- ② 종·횡단면도에 의하여 공사수량의 체적과 면적을 산출할 경우에는 일반적으로 평균단면적법과 평균거리법을 적용하고 있다. 전자는 당해측점의 공종수가 적을 경우에 편리하고 후자는 공종수가 많을 경우에 편리하나 그 값은 동일하게 산출된다. +- ③ 토취장 또는 토사장이 넓을 경우에는 점고법에 의하여 절취량 또는 성토가능량을 산출한다. +- ○ 평균단면적법 +- ① (표 5-2-33)의 토적계산표(예)에 종단면도에서 측점과 거리를 이기하고, 횡단면도에서 공 종별 단면적과 높이를 이기한다. +- ② 각 공종별로 앞 측점과 현 측점의 단면적 평균에 두 단면 간 거리를 곱하여 체적을 구한다. + + - No.1의 평균 절토단면적: $(0.92+4.16)/2=2.54$㎡ + - No.1의 절토체적: $2.54\times20.0=50.80$㎥ +- ③ 거리 및 각공종별로 체적(면적)을 합계하면 해당노선의 공사수량이 된다. 표 5-2-33. 토적계산표(평균단면적법)(예) (단위:m, m2, m +- 3) + +| 측점 | 거 리 | 절 토 | | | 성 토 | | | 평 떼 | | | 석 축 | | | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +| | | 단면적 | 평균면적 | 체적 | 단면적 | 평균면적 | 체적 | 사면길이 | 평균길이 | 면적 | 높이 | 평균높이 | 면적 | +| BP | | 0.92 | | | | | | | | | | | | +| No.1 | 20.00 | 4.16 | 2.54 | 50.80 | | | | | | | | | | +| BC | 10.00 | 3.64 | 3.90 | 39.00 | 5.14 | 2.57 | 25.70 | 4.00 | 2.00 | 20.00 | | | | +| No.2 | 10.00 | 6.18 | 4.91 | 49.10 | 1.16 | 3.15 | 31.50 | 1.20 | 2.60 | 26.00 | | | | +| EC | 12.00 | 5.92 | 6.05 | 72.60 | 2.12 | 1.64 | 19.68 | 1.60 | 1.40 | 16.80 | | | | +| No.3 | 8.00 | | 2.96 | 23.68 | 7.64 | 4.88 | 39.04 | | 0.80 | 6.40 | 2.00 | 1.00 | 8.00 | +| No.4 | 20.00 | | | | 3.60 | 5.62 | 112.40 | | | | 1.40 | 1.70 | 34.00 | +| +10 | 10.00 | 3.62 | 1.81 | 18.10 | | 1.80 | 18.00 | | | | | 0.70 | 7.00 | +| No.5 | 10.00 | 2.26 | 2.94 | 29.40 | | | | | | | | | | +| 계 | 100.00 | | | 282.68 | | | 246.32 | | | 69.20 | | | 49.00 | + +- ○ 평균거리법 +- ① (표 5-2-34)의 토적계산표(예)에 종단면도에서 측점과 거리를, 횡단면도에서 공종별 단면적과 길이를 이기한다. +- ② 현재 측점거리와 다음 측점거리의 평균에 공종별 단면적(길이)을 곱하여 체적을 구한다. + + - BP의 평균거리: $(0.00+20.00)/2=10.00$m + - BP의 절토체적: $10.00\times0.92=9.20$㎥ +- ③ 거리 및 각 공종별로 체적(면적)을 합계하면 해당노선의 공사수량이 된다. 표 5-2-34. 토적계산표(평균거리법)(예) + +| 측 점 | 거리(m) | 평균 거리(m) | 절 토 | | 성 토 | | 평 떼 | | 석 축 | | +|---|---|---|---|---|---|---|---|---|---|---| +| | | | 단 면적(㎡) | 체적(㎥) | 단면적(㎡) | 체적(㎥) | 사면길이(m) | 면적(㎡) | 높이(m) | 면적(㎡) | +| BP | 0.00 | 10.00 | 0.92 | 9.20 | | | | | | | +| No.1 | 20.00 | 15.00 | 4.16 | 62.40 | | | | | | | +| BC | 10.00 | 10.00 | 3.64 | 36.40 | 5.14 | 51.40 | 4.00 | 40.00 | | | +| No.2 | 10.00 | 11.00 | 6.18 | 67.98 | 1.16 | 12.76 | 1.20 | 13.20 | | | +| EC | 12.00 | 10.00 | 5.92 | 59.20 | 2.12 | 21.20 | 1.60 | 16.00 | | | +| No.3 | 8.00 | 14.00 | | | 7.64 | 106.96 | | | 2.00 | 28.00 | +| No.4 | 20.00 | 15.00 | | | 3.60 | 54.00 | | | 1.40 | 21.00 | +| +10 | 10.00 | 10.00 | 3.62 | 36.20 | | | | | | | +| No.5 | 10.00 | 5.00 | 2.26 | 11.30 | | | | | | | +| 계 | 100.00 | | | 282.68 | | 246.32 | | 69.20 | | 49.00 | + +- ○ 점고법 +- ① 넓은 지역을 동일한 면적의 직(정)사각형 또는 직각삼각형(가급적 1변의 길이가 20m 이하)으로 구획하고 각 꼭지점의 높이(點高)를 측정한다. +- ② 각 구역을 사각(또는 직삼각)기둥으로 생각하여 각 구역의 면적과 평균높이를 구하는 방법으로 전체체적을 산출한다. +- ③ (그림 5-2-69)와 같이 각 꼭지점의 높이를 사용하는 회수에 따라 1번사용(H1), 2번사용(H2), 3번사용(H3), 4번사용(H4)으로 구분하여 다음식에 의하여 산출한다. + +![설계_그림5-2-69_사각주의점고](<../pic/설계_그림5-2-69_사각주의점고.png>) + +구역체적과 전체체적은 다음 식으로 산출한다. + +$$V_0=\frac{A(h_1+h_2+h_3+h_4)}{4}$$ + +$$V=\frac{A(\Sigma H_1+2\Sigma H_2+3\Sigma H_3+4\Sigma H_4)}{4}$$ + +- $A$: 한 구역의 수평 단면적(㎡) +- $\Sigma H_1$: 1회 사용된 지반고의 합 +- $\Sigma H_2$: 2회 사용된 지반고의 합 +- $\Sigma H_3$: 3회 사용된 지반고의 합 +- $\Sigma H_4$: 4회 사용된 지반고의 합 + +그림 5-2-69. 4각주의 점고 + +(예제) 다목적시범단지 내 어느 부지를 그림의 각 꼭지점에 나타낸 높이만큼 깎아 정지하고자 한다. 땅깎기할 토량과 시공면고를 구하여라. 단, 구역면적은 30㎡이다. + +$$ +V=\frac{30}{4}\{(0.2+0.4+0.4+0.2)+2(0.5+0.4+0.3+0.3+0.5+0.4+0.5+0.2+0.3+0.3)+3(0)+4(0.3+0.5+0.5+0.4+0.2+0.1)\} +$$ + +$$V=7.5\times(1.2+2\times3.7+0+4\times2.0)=124.5\,\mathrm{m^3}$$ + +$$H=\frac{\text{토적}}{\text{총면적}}=\frac{124.5}{12\times30}=0.346\,\mathrm{m}$$ + +※ 정지작업 시 시공면고(施工面高)와 성토고(盛土高) 및 절토고(切土高)의 관계 +- ① 시공면고보다 높은 곳은 그 차이만큼 흙깎기(切土)를 시행한다. +- ② 시공면고보다 낮은 곳은 그 차이만큼 흙쌓기(盛土)를 시행한다. +##### 나) 구조물도에 의한 수량산출(예) +- ① (그림 5-2-70)과 같이 Box 2련 2.0 × 1.5 × 6.03m 되는 구조물을 설치한다고 하자. +- ② 구체 콘크리트는 전체단면적{(0.3 + 2.0 + 0.3 + 2.0 + 0.3) × (0.25 + 1.5 + 0.25) = 9.80 ㎡}에서 유수구단면적{(2.0 × 1.5 × 2개) - (0.2 × 0.2 ÷ 2 × 8개) = 5.84㎡}을 뺀 값(3.96㎡)에 길이(6.03m)를 곱하면 23.88㎥가 된다. +- ③ 기초 콘크리트는 폭(5.1m) × 두께(0.10m) × 길이(6.03m)를 곱하면 3.08㎥가 된다. +- ④ 거푸집(합판 3회 사용)은 내벽, 외벽, 받침판으로 구분하여 좌우외벽(2.0m × 6.03m × 2장), 유수구 2개 단면{(1.5 - 0.2 × 2개) × 6.03m × 4장}, 받침판{(2.0 - 0.2 × 2개) × 6.03m × 2장} 및 유수구 귀면{$\sqrt{0.2^2+0.2^2}\times6.03m\times8장$}을 합하면 83.59㎡가 된다. + +![설계_그림5-2-70_Box단면도](<../pic/설계_그림5-2-70_Box단면도.png>) + +그림 5-2-70. Box(2.0×1.5×2련×6.03 m) 단면도 + +- ⑤ 동바리(강관)는 유수구 단면적(2.0 × 1.5m × 2개)에서 귀면(0.2 × 0.2 ÷ 2 × 8개)을 뺀 값(5.36㎡)에 길이(6.03m)를 곱하면 32.32㎡가 된다. +- ⑥ 철근은 구조물도의 철근상세도에서 각 철근의 길이와 개수를 산출하여 철근 규격별 m당 중량을 곱하면 총소요량이 된다. +- ⑦ 이와 같이 각 재료공종별(터파기, 구체콘크리트, 거푸집, 동바리, 되메우기 등) 재료별로 수량을 산출한다. +##### 다) 토량수급계획 +- ○ 해석법에 의한 방법 +- ① (표 5-2-33) 또는 (표 5-2-34)의 토적계산표에서 (표 5-2-35)와 같은 토량운반계획표의 측점, 거리, 총성토량 및 총절토량을 이기하고 성토량은 토량환산계수(다짐상태/자연상태)에 의한 보정토량을 산출 기재한다. 표 5-2-35. 토량운반 계획표 + +| 측점 | 거리 | 총절토량 | 총성토량 | | | 유용 토량 | 잔토량 | 부족 토량 | 도쟈운반성토 | | 덤프운반성토 | | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| | | | 자연 상태 | 토량환 산계수 | 보정 토량 | | | | 주는곳 | 토공량 | 주는곳 | 토공량 | +| BP | 0.00 | 9.20 | | | | | 9.20 | | | | | | +| No.1 | 20.00 | 62.40 | | | | 57.11 | 5.29 | | | | | | +| BC | 10.00 | 36.40 | 51.40 | 0.9 | 57.11 | | 36.40 | | | | | | +| No.2 | 10.00 | 67.98 | 12.76 | 0.9 | 14.17 | 14.17 | 53.81 | | No.2 | 41.31×20 = 826.2 | | | +| EC | 12.00 | 59.20 | 21.20 | 0.9 | 23.55 | 23.55 | 35.65 | | BC | 36.40×30 = 1,092.0 | | | +| No.3 | 8.00 | | 106.96 | 0.9 | 118.84 | | | 83.19 | No.1
BP | 5.29×40 = 211.6
0.19×60 = 11.4 | | | +| No.4 | 20.00 | | 54.00 | 0.9 | 60.00 | | | 23.80 | | | | | +| +10 | 10.00 | 36.20 | | | | 36.20 | | | No.5 | 11.30×20 = 226.0 | | | +| No.5 | 10.00 | 11.30 | | | | | 11.30 | | No.2 | 2.50×40 = 500.0 | | | +| 사토장 | 20.00 | | | | | | | | | | BP | 9.01×120 = 1,081.2 | +| 계 | 100.00 | 282.68 | 246.32 | | 273.67 | 166.68 | 116.00 | 106.99 | | 106.99 2,867.20 = 26.8 ≒27(m) | | 9.01 1,081.2 = 120(m) | +| 주) ㉠토량환산계수: 자연 상태의 토 량과 다짐 상태의 토 량의 비율 | | | | | | | | | | | | | +| ㉡보정토량: 자연상태토량/토량환산계수 | | | | | | | | | | | | | +| ㉢평균운반거리= 총작업량/총운반성토량 | | | | | | | | | | | | | +| ㉣도쟈운반성토= 60m이하의토량(건설표준품셈참조) | | | | | | | | | | | | | +| ㉤덤프운반성토= 60m초과의토량(건설표준품셈참조) | | | | | | | | | | | | | + +- ② 유용토는 20m 미만의 총성토량 및 총절토량 중 적은 수량을 기재하고 총절토량 - 총성토량 > 0 일 경우에는 잔토란에, 총절토량 - 총성토량 < 0 일 경우에는 부족토란에 그 수량을 기재한다. ※ ㉠ BP에서 총절토량은 9.20㎥이나 20m미만 거리에 총성토량이 없으므로 잔토란에 9.20㎥가 되고, No.1의 총절토량 62.40㎥는 BC의 총성토량 57.11㎥가 20m 미만거리이므로 유용토로 57.11㎥를 우선 감하고 나머지 5.29㎥는 잔토란에 기재한다. ㉡ BC의 총절토량 36.40㎥는 다음 측점 No.2에서 총절토량 67.98㎥, 총성토량 14.17㎥이므로 그대로 BC의 잔토란에 36.40㎥를 기재하고, No.2의 유용토란에 14.17㎥, 잔토란에(67.98 - 14.17) 53.81㎥를 기재한다. ㉢ EC에서 총성토량 23.55㎥, 총절토량 59.20㎥이므로 23.55㎥는 유용토로 처리하고 나머지(59.20 - 23.55) 35.65㎥는 잔토로 처리하여야 하지만 No.3에서 총성토량이 118.84㎥이므로 EC에서 No.3 까지의 거리는 8m < 20m이므로 EC의 잔토량 35.65㎥는 No.3에서 유용이 가능하기 때문에 부족토량은(118.84 - 35.65) 83.19㎥가 된다. ㉣ No.4에서 총성토량이 60.00㎥, No.4 +10에서 총절토량이 36.20㎥이므로 유용토로 36.20 ㎥를 제하면 부족토는 (60.00 - 36.20) 23.80㎥가 된다. +- ③ 이렇게 하여 유용토량(166.68㎥) + 잔토량(116.00㎥) = 총절토량(282.68㎥), 유용토량(166.68㎥) + 부족토량(106.99㎥) = 총성토량(273.67㎥)이면 계산이 맞지만 다를 경우에는 다시 검산하여 맞도록 한다. +- ④ 유용토량 166.68㎥는 불도저의 절취작업시 삽날에 의하여 횡방향으로 집성토되는 것을 의미하여 무대로 처리하고, 부족토는 불도저 또는 덤프트럭운반으로서 흙쌓기를 하여야만 노체 또는 노상의 형성이 가능한 것을 의미한다. 따라서 부족토가 있는 측점을 기준으로 가장 가까운 곳에 있는 잔토부터 운반하여 60m이내에 있는 토량은 불도저운반거리로 계산하고 그 이상은 덤프트럭운반거리로 계획하여 계산한다. ※ ㉠ 부족토의 공급을 위하여 전체적인 잔토량을 살펴보면, No.3과 No.4에서는 흙이 모자라고 BP부터 N0.2까지는 흙이 남으므로 운반의 효율성으로 볼 때 운반형태가 교차되지 않도록 하기 위하여 No.4 부터 흙을 수급함이 타당하므로 No.4에서 가장 가까운 거리에 있는 No.5에서 부터 수급하면 작업량은 11.30㎥ × 20m = 226㎥·m가 되고 나머지 부족토(23.80-11.30) 12.5㎥는 그 다음 가까운 거리에 있는 No.2에서 운반하면 작업량은 12.5㎥ × 40m = 500㎥·m가 된다. ㉡ 그 다음 No.3의 부족토를 보면 가장가까운 거리에 있는 No.2의 잔토량(53.81-12.50)41.31㎥를 우선 수급하면 작업량은 41.31㎥ × 20m = 826.20㎥·m이고 나머지 부족토량(83.19-41.31) 41.88㎥ 중 36.40㎥는 BC에서 수급하면 작업량은 36.40㎥ ×30m = 1092.00㎥·m가 되고, 나머지 부족토량(83.19-41.31-36.40) 5.48㎥는 No.1과 BP에서 수급한다. ㉢ 이에 대한 운반량을 합계하면 106.99㎥이고, 작업량을 합하면 2,867.2㎥·m가 되므로 불도저 운반성토량의 가중평균운반거리는 2,867.2㎥·m ≑ 106.99㎥ = 26.8 ≒ 27m가 된다. ㉣ 덤프트럭 운반은 60m초과되는 거리를 기준으로 한다. 본표에서는 작업이 곤란하지만 사토(흙버리기:116.0-106.99=9.01㎥) 처리의 예로서 설명하면 다음과 같다. 사토장을 No.6되는 곳에 설치한다고 가정하면, BP의 잔토량(9.20-0.19)9.01㎥에 대한 작업량은 9.01㎥ × 120m = 1,081.2㎥·m가 된다. 이외에도 잔토량이 더 있을 경우에는 이와같이 계산하고 합하여 불도저 성토량의 평균운반거리와 같이 산출한다. +- ⑤ 이와 같이 계산하여 불도저운반 성토량(106.99) + 덤프트럭운반 성토량(0) = 부족토량(106.99㎥)이 되어야 하고, 부족토량(106.99) + 사토운반량(9.01) = 잔토량(116.0㎥)이 되어야 계산이 맞고 그렇지 않을 경우에는 다시 검산한다. +- ○ 유토(토량)곡선에 의한 방법 +- - 작성방법 +- ① (표 5-2-36)과 같이 토적계산표에서 측점, 거리, 총절토량, 총성토량을 이기한다. +- ② 토량환산계수를 적용하여 성토량을 실다짐상태에 필요한 자연상태의 토량으로 보정한다. ※ BC에서 성토량 51.40㎥는 다짐상태의 요구토량이지만 절취량은 자연상태의 토량이기 때문에 1㎥를 다지면 0.9㎥가 되므로 1.0 / 0.9 = 1.11㎥ 즉, 11%가 더 많은 57.11㎥의 흙이 필요함을 의미한다. 표 5-2-36. 토량유용 계산표 + +| 측점 | 거리 (m) | 절취량 (㎥) | 성 토 량(㎥) | | | 횡방향토량 | 잔토량 | 부족토량 | 누가토량 (㎥) | +|---|---|---|---|---|---|---|---|---|---| +| | | | 토 량 | 토량환산 계 수 | 보정토량 | | | | | +| BP | 0.00 | 9.20 | | | | | 9.20 | | 9.20 | +| No.1 | 20.00 | 62.40 | | | | | 62.40 | | 71.60 | +| BC | 10.00 | 36.40 | 51.40 | 0.9 | 57.11 | 36.40 | | 20.71 | 50.89 | +| No.2 | 10.00 | 67.98 | 12.76 | 0.9 | 14.17 | 14.17 | 53.81 | | 104.70 | +| EC | 12.00 | 59.20 | 21.20 | 0.9 | 23.55 | 23.55 | 35.65 | | 140.35 | +| No.3 | 8.00 | | 106.96 | 0.9 | 118.84 | | | 118.84 | 21.51 | +| No.4 | 20.00 | | 54.00 | 0.9 | 60.00 | | | 60.00 | -38.49 | +| No.4+10 | 10.00 | 36.20 | | | | | 36.20 | | -2.29 | +| No.5 | 10.00 | 11.30 | | | | | 11.30 | | 9.01 | +| 계 | 100.00 | 282.68 | 246.32 | | 273.67 | 74.12 | 208.56 | 199.55 | | + +- ③ 보정된 성토량을 (-)로 하고 절취량을 (+)로 하여 각 측점마다 누적대수화하여 누가토 량을 구한 후 횡축은 종단면도의 축척과 같이 거리별로 측점의 위치를 나타내고 종축은 각 측점까지의 누가토량을 (그림 5-2-71)과 같이 그린다. 이 곡선을 유토곡선(MassCurve)또는 토량곡선이라고 한다. + +![설계_그림5-2-71_유토곡선](<../pic/설계_그림5-2-71_유토곡선.png>) + +그림 5-2-71. 유토곡선(예) + +- - 유토곡선의 성질과 적용 +- ① 유토곡선이 상향인 구간(AB, CD)은 절토구간이고 하향인 구간(BC, DE)은 성토구간이며, 곡선의 곡점(점 C, 점 F)은 성토에서 절토로 정점(점 B, 점 D)은 절토에서 성토로 바뀌는 점이다. +- ② 곡선과 평행선이 교차하는 점(점 E, 점 G)은 절토량과 성토량이 거의 같은 평행상태를 나타내고 A∼E구간과 E∼G구간의 절토량과 성토량은 균형을 이룬다. +- ③ 평행선에서 곡선의 곡점과 정점까지의 높이(A∼E구간은 DD′, E∼G구간은 FF′)는 절 토에서 성토로 운반되는 전체의 토량을 나타내고 A∼H구간에서 사토량(捨土量)은 HH′(9.01㎥)가 되며, 토량과 운반거리는 토량유용계산표에서 직접 인용하고 만약 평형점이 측점과 측점의 중간에 위치할 경우에는 비례보간법에 의하여 토량을 구한다. +- ④ 절토와 성토의 평균운반거리는 유토곡선 토량의 1/2점(FF′/2)을 통과하는 길이(ab)가 되고, 평균운반거리는 절토의 중심(重心)과 성토의 중심(重心)간의 거리를 의미한다. ※ ㉠ 총토공작업량은 총토량을 평균운반거리 만큼 운반하는 것을 의미하므로 평균운반거리(m) = 총토공작업량(㎥·m)/총토량(㎥)㉡ 총토공작업량은 유토곡선과 평형선으로 둘러싸인 부분의 면적(프라니미터 또는 삼각형법에 의하여 산출한다)에 해당하며, 총토량은 유토곡선의 최대종거(縱距)를 의미하므로 평균운반거리(m) = 유토곡선과 평형선으로 둘러 쌓인 면적(㎡)/최대종거(m) +- ⑤ 유토곡선이 평형선보다 위에 있을 경우에는 절토에서 성토로 운반되는 작업방향은 좌에서 우로 이루어지고 아래에 있을 경우에는 우에서 좌로 이루어진다. +- ⑥ 평형선은 반드시 1개의 연속된 직선으로 설정할 필요는 없지만 유토곡선과 교차하는 측점에서 다른 평형선을 설정하여야 한다. 이때 2개의 평형선간의 상하간격은 보급토량 또는 사토량을 나타낸다. ※ (그림 5-2-71)의 절토구간 1+15∼EC와 성토구간 EC∼2+15(ℓ1∼ℓ2 구간의 평행선)및 절토구간 BC∼1+15와 성토구간 2+15∼2+18 (c∼c″구간의 평행선) +- ⑦ 절토는 양방향으로 운반될 수 있게 하는 것이 능률적이고 종단구배가 급한 구간에는 배수나 운반을 고려하여 종단곡선을 따라 내리막 구배로 굴착될 수 있도록 평형선을 긋는다. +- ⑧ 성토구간에 교량 등의 구조물이 있고 그 구조물 너머로 흙을 운반할 경우는 구조물까지 토량을 평형시키든지 또는 우회하여 운반계획을 세운다. (예제) (표 5-2-36)과 같은 토량유용계산표로서 유토곡선을 그리고 운반성토량을 산출하여라. (풀이) : 유토곡선은 (그림 5-2-71)과 같고 토량의 배분은 (표 5-2-37)과 같다. +- ① 유용토량은 운반거리가 20m미만이므로 ㉠ ABC구간 : 점 CC'의 평형선을 그으면 절토구간은 No.0 +13.5 ∼ No.1, 성토구간은 No.1∼BC로서 거리는 (30.0-13.5) 16.5m (평균거리 8.25m)가 되고 토공량은 BB1(71.6-50.89)= 20.71㎥이므로 작업량은 20.71㎥ × 8.25m = 170.8㎥·m가 된다. ㉡ CDE구간 : 평형선 ℓ1 ℓ2, 절토구간 No.1+15 ∼ EC, 성토구간은 EC ∼ No.2 +15으로서 거리는 20m, 토량 DD1 = [140.35-{50.89+(104.70-50.89)÷10×5}]62.55㎥, 작업량 62.55㎥ × 10m = 625.5㎥·m. ㉢ EFG구간 : 평형선 ℓ3 ℓ4, 절토구간 No.4 ∼ No.4+9, 성토구간은 No.3+9 ∼ No.4로서 거리 20m(평균거리 10.0m), 토량 FF1 =[38.49-2.29-{(38.49-2.29)÷10×1}] 32.58㎥, 작업량 32.58㎥ × 10m = 325.8㎥·m. ㉣ 이를 정리하면 (표 5-2-37)과 같다. +- ② 불도저운반성토 토량은 운반거리가 60m이하이므로 ①과 같은 방법으로 산출하여 운반토 량 71.40㎥, 작업량 2,573.7㎥·m 로서 평균운반거리는 36m이다. +- ③ 덤프트럭운반 성토량은 운반거리가 60m이상이므로 ①과 같은 방법으로 산출하여 운반성토량 12.31㎥, 작업량 769.4㎥·m로서 평균운반거리는 63m이고, 사토량은 2.43㎥이다. +- ④ 유용토량(115.84㎥), 불도저운반성토량(71.40㎥), 덤프트럭운반성토량(12.31㎥)을 합하면(표 5-2-36)의 부족토량(199.55㎥)과 같아야 하고, 여기에 사토량(9.01㎥)을 합하면 (표 5-2-36)의 잔토량(208.56㎥)과 같아야 한다. 표 5-2-37. 토량배분 산출표 + +| 구 분 | 절토구간 | 성토구간 | 토 량 (A) | 평균거리 (B) | 작업량 (A×B) | 비 고 | +|---|---|---|---|---|---|---| +| 유용토 | 0+13.5∼1 | 1∼BC | 20.71 | 8.25 | 170.8 | 71.60-50.89 | +| | 1+15∼EC | EC∼2+15 | 62.55 | 10.0 | 625.5 | 140.35-50.89-26.91 | +| | 4∼4+9 | 3+9∼4 | 32.58 | 10.0 | 325.8 | 38.49-2.29-3.62 | +| | 계 | | 115.84 | | 1122.1 | 9.70 ≒ 10m | +| 불도저 운 반 성 토 | BC∼1+15.0 | 2+15∼2+18 | 26.91 | 24.00 | 645.8 | 140.35-50.89-62.55 | +| | 4+9∼4+17 | 3+5∼3+9 | 15.11 | 26.00 | 392.8 | 38.49+9.2-32.58 | +| | 0+1.5∼0+13.5 | 2+18∼3+1.5 | 29.38 | 52.25 | 1535.1 | 140.35-62.55-26.91-21.51 | +| | 계 | | 71.40 | | 2573.7 | 36.9 ≒ 37m | +| 덤프운 반성토 | 0∼1.5 | 3+1.5∼3+5 | 12.31 | 62.50 | 769.4 | 140.35-62.55-26.91-29.38-9.2 | +| | 계 | | 12.31 | | 769.4 | 62.5 ≒ 63 | +| 사토 | | | 9.01 | | | | + +### 라. 공사원가 산출 + +각 공종별 공사수량산출이 완료되면 공사원가를 계산하기 위하여 각 공종별 단가를 산출한다. + +공사원가를 산출할 경우에는 관계규정과 행정지침을 참고하여 지역별 공사여건(자재채취 및 구입, 인력수급, 자재운반, 시공방법 등)에 따라 공사의 진행과정이 가장 합리적이고 현실적으로 실행될 수 있도록 한다. + +#### 1) 중기 사용료 +- ① 작업종류에 따라 사용할 건설기계의 종류와 규격을 건설표준품셈을 참고하여 가장 적정한 기종을 먼저 선정한다. +- ② 공사현장 조건이 할증율을 가산하여야 할 조건인지 아닌지를 검토한다. +- ③ 건설표준품셈을 참고하여 시간당 손료를 계산하고 중기가격(한화 또는 미화)을 적용하여 시간당 사용료를 산출한다. + +(예제) 임도시설공사의 절토에 사용할 굴삭기(유압식 백호우 0.7㎥)의 사용료를 산출하여라. + +(풀이) 가격 60,600천원, 시간당 손료 $2,148\times10^{-7}$이므로 다음과 같다. + +- ① 경비: $60,600,000\times2,148\times10^{-7}=13,016$원 +- ② 노무비 17,249원 조 종 원 1.0인 × 52,927원 × 1/8 × 25/20 × 16/12 = 11,026원조 수 0.5인 × 39,004원 × 1/8 × 25/20 × 16/12 = 4,062원 중기조장 0.2인 × 51,867원 × 1/8 × 25/20 × 16/12 = 2,161원 +- ③ 재료비 2,862원 주 연 료 10.5ℓ × 218.18원 = 2,290원 잡 품 25% × 2,290.89원 = 572원 +- ④ 계 33,127원/시간/대. +#### 2) 공종별 단가 +- ① 작업조건 및 토양의 종류에 따라 사용할 건설기계의 종류와 규격을 건설표준품셈을 참고하여 선정한다. +- ② 토사절취와 같이 1공종 1건설기계로 이루어지는 작업도 있지만 성토작업과 같이 2가지 이상의 건설기계가 조합되어 실행할 경우도 있다. 이때에는 기계별로 합리성과 경제성을 검토하여 가장 타당한 조합방법으로 계획한다. (예, 로우더 + 덤프트럭, 굴삭기 + 덤프트럭) +- ③ 사면 안정처리공사와 같이 여러가지의 공종이 결합되어 실행하거나 또는 동일공종이 기계와 인력이 서로 혼합(또는 비율구분)하여 실행할 경우에는 단계별 순서대로 공종이 서로 연결되도록 계획한다. +- ④ 구조물 공사와 같이 터파기, 버림콘크리트, 철근조립, 거푸집설치, 기초콘크리트, 구체콘크리트, 되메우기 등 여러개의 공종이 결합되어 공사가 진행되거나 동일공종안에서도 여러 가지의 자재와 건설기계가 투입될 경우에는 단계별 진행과정별로 공종이 연결되도록 한다. +- ⑤ 위의 사항을 참고하여 작성한 단가산출서의 예는 (표 5-2-38)과 같다. 표 5-2-38. 단가산출서(예) + +| 공종 | 산 출 내 역 | 계 | 재료비 | 노무비 | 경 비 | +|---|---|---|---|---|---| +| D00201
사토운반
(토사) | L = 2㎞(임도)/㎥
1. 적사(백호우 0.7㎥)
$q_o=0.7$, $K=0.9$, $f=1/1.325=0.75$
$E_o=0.65$, $C_M=21\,sec(135°)$
보통·흐트러진 상태·자갈 섞인 흙·점성토 기준
$Q=3,600q_oKfE_o/C_M=52.65㎥/hr$
재료비: $2,862/Q=54$
노무비: $17,249/Q=327$
경비: $13,016/Q=247$
소계 | 54
327
247
628 | 54
54 | 327
327 | 247
247 | +| | 2. 운반(덤프 10.5 ton)
$L=2.0㎞$, $E=0.9$, $V_1=7$, $V_2=10$
$q=10.5/1.7\times1.325=8.18$
$N=q/(q_oK)=12.98회$
$T_1=C_MN/(60E_o)=6.99$
$T_2=(L/V_1+L/V_2)\times60=29.14$
$T_3=0.8$, $T_4=0.42$
$C_m=T_1+T_2+T_3+T_4=37.35$
$Q=60qfE/C_m=8.87㎥/hr$
재료비: $5,905/Q=665$
노무비: $8,961/Q=1,010$
경비: $6,853/Q=772$
소계 | 665
1,010
772
2,447 | 665
665 | 1,010
1,010 | 772
772 | +| | 3. 사토장 정리(도쟈 19 ton)
$L=2.0m$, $f=1/1.325=0.75$
$E=0.75$ (양호·흐트러진 상태·자갈 섞인 흙·점성토 기준)
$V_1=75$, $V_2=98$, $q=3.2\times0.96=3.07$
$C_m=L/V_1+L/V_2+0.25=0.72분$
$Q=60qfE/C_m=143.91㎥/hr$
$Q_1=Q\times3=431.73㎥/hr$
재료비: $6,593/Q_1=15$
노무비: $17,249/Q_1=39$
경비: $17,389/Q_1=40$
소계 | 15
39
40
94 | 15
15 | 39
39 | 40
40 | +| | 계 | 3,169 | 734 | 1,376 | 1,059 | + +#### 3) 공사비 및 공사원가 계산서 +- ① 공종별 물량과 단가산출이 완료되면 서로 곱하여 합계, 노무비, 재료비, 경비로 구분하는(표 5-2-39)와 같은 공사비 내역서를 산출한다. 이때 산출되는 공사비를 순공사비라고 한다. 표 5-2-39. 공사비 내역서(예) + +| 공사명: 다목적 산림 경영 시범 단지 내임도 실시 설계 | | | | | | | | | | | | | | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +| ITEM NO. | 명 칭 | 규 격 | 수 량 | 단위 | 총 액 | | 재 료 비 | | 노 무 비 | | 경 비 | | 비고 | +| | | | | | 단가 | 금 액 | 단가 | 금 액 | 단가 | 금 액 | 단가 | 금 액 | | +| 1. | 토 공 | | | | | 1,084,639,755 | | 215,571,814 | | 519,096,394 | | 349,934,047 | | +| 1) | 잡관목제거 | | 319,242 | ㎥ | 79 | 25,220,118 | | | 79 | 25,220,118 | | | D00024 | +| 2) | 흙깍기 | | | | | 266,974,149 | | 36,493,858 | | 129,334,586 | | 101,145,705 | | +| | 흙깍기(토사) | 도쟈 | 214,297 | ㎥ | 879 | 188,367,063 | 140 | 30,001,580 | 368 | 78,861,296 | 371 | 79,504,187 | D00020 | +| | 흙깍기(풍화암) | 발파 +브레카 | 10,629 | ㎥ | 7,234 | 76,890,186 | 594 | 6,313,626 | 4,638 | 49,297,302 | 2,002 | 21,279,258 | D00044 | +| | 흙깍기(발파암) | 발파+브레 카+크롤라 | 118 | ㎥ | 14,550 | 1,716,900 | 1,514 | 178,652 | 9,966 | 1,175,988 | 3070 | 362,260 | D00045 | +| 3) | 측구터파기 | | | | | 38,121,502 | | 735,722 | | 35,536,358 | | 1,849,422 | | +| | 측구터파기 | 토사 | 4,008 | ㎥ | 3,070 | 12,304,560 | 89 | 356,712 | 2,669 | 10,697,352 | 312 | 1,250,496 | D00165 | +| | 측구터파기 | 풍화암 | 746 | ㎥ | 33,635 | 25,091,710 | 493 | 367,778 | 32,359 | 24,139,814 | 783 | 584,118 | D00033 | +| | 측구터파기 | 발파암 | 12 | ㎥ | 60,436 | 725,232 | 936 | 11,232 | 58,266 | 699,192 | 1,234 | 14,808 | D00115 | +| 4) | 흙쌓기 | | | | | 24,894,518 | | 3,196,484 | | 12,080,704 | | 9,617,330 | | +| | 성토다짐 | 노상 | 36,082 | ㎥ | 360 | 12,989,520 | 47 | 1,695,854 | 174 | 6,278,268 | 139 | 5,015,398 | D00124 | +| | 성토다짐 | 노체 | 50,021 | ㎥ | 238 | 11,904,998 | 30 | 1,500,630 | 116 | 5,802,436 | 92 | 4,601,932 | D00099 | +| 5) | 흙운반 | | | | | 718,594,764 | | 174,672,998 | | 306,562,676 | | 237,359,090 | | +| | 유용토운반(도쟈) | 토사 | 11,184 | ㎥ | 827 | 9,249,168 | 132 | 1,476,288 | 346 | 3,869,664 | 349 | 3,903,216 | D00313 | +| | 유용토운반(도쟈) | 풍화암 | 748 | ㎥ | 1,391 | 1,040,468 | 222 | 166,056 | 582 | 435,336 | 587 | 439,076 | D00314 | +| | 유용토운반(덤프) | 토사 | 2,062 | ㎥ | 1,456 | 3,002,272 | 293 | 604,166 | 672 | 1,385,664 | 491 | 1,012,442 | D00315 | +| | 유용토운반(덤프) | 풍화암 | 132 | ㎥ | 1,792 | 236,544 | 192 | 25,344 | 911 | 120,252 | 689 | 90,948 | D00316 | +| | 사토운반(토사) | L=4KM (임도) | 128,896 | ㎥ | 5,082 | 655,049,472 | 1,254 | 161,635,584 | 2,165 | 279,059,840 | 1,663 | 214,354,048 | D00323 | +| | 사토운반(리핑암) | L=4KM (임도) | 8,040 | ㎥ | 6,221 | 50,016,840 | 1,339 | 10,765,560 | 2,698 | 21,691,920 | 2,184 | 17,559,360 | D00324 | +| 6) | 목책 | | 3,216 | m | 3,369 | 10,834,704 | 147 | 472,752 | 3,222 | 10,361,952 | | | D00304 | + +- ② 순공사비의 산출이 완료되면 관계규정 및 행정지침에 따라 간접노무비, 산재보험료, 고용 보험료, 기타경비, 안전관리비, 일반관리비, 수수료(이윤), 사급자재대, 부가가치세를 적용율에 따라 산출하고 관급자재대를 합하여 (표 5-2-40)과 같은 총공사원가를 산출한다. +- ③ 공사원가가 산출되면 당해기관의 재무관이 평정하는 평정가에 따라 공사가 발주된다. 표 5-2-40. 공사원가 계산서(예) + +| 공사명: 다목적 산림 경영 시범 단지 내임도 실시 설계 | | | | | | | +|---|---|---|---|---|---|---| +| 공종 | 명 칭 | 규격 | 계 | 재료비 | 노무비 | 경 비 | +| 1. | 토공 | | 1,467,028,107 | 226,174,708 | 890,844,352 | 350,009,047 | +| 2. | 배수공 | | 94,490,769 | 13,240,414 | 77,167,207 | 4,083,148 | +| 3. | 구조물공 | | 63,112,857 | 8,497,246 | 52,442,004 | 2,173,607 | +| 4. | 부대공 | | 7,311,490 | 4,505,075 | 1,806,425 | 999,990 | +| 가. | 순공사비계 | | 1,631,943,223 | 252,417,443 | 1,022,259,988 | 357,265,792 | +| | 1.간접노무비 | | 159,472,558 | 직접노무비×15.6% | | | +| | 2.산재보험료 | | 33,088,511 | (직접노무비+간접노무비)×2.8% | | | +| | 3.기타경비 | | 88,917,299 | (직접노무비+간접노무비+재료비)×6.2% | | | +| | 4.안전관리비 | | 33,993,906 | (직접노무비+재료비+관급자재대)×1.81%+3,294,000 | | | +| 나. | 소계 | | 1,947,415,497 | | | | +| | 5.일반관리비 | | 107,107,852 | 나. × 5.5% | | | +| 다. | 소계 | | 2,054,523,349 | | | | +| | 6.수수료 | | 270,241,337 | (다-재료비) × 15% = 270,315,885 | | | +| | 7.사급자재대 | | 6,035,314 | | | | +| 라. | 공급가액 | | 2,330,800,000 | | | | +| | 8.부가가치세 | | 233,080,000 | 라. 의10% | | | +| 마. | 도급공사비 | | 2,563,880,000 | | | | +| | 9.관급자재대 | | 421,450,000 | | | | + +### 마. 설계의 전산화 +#### 1) 임도계획(임도망 편성)의 전산화 + +합리적인 임도망 편성을 위해서는 대상지역의 산림과 주변지역에 대한 여러 가지 정보를 수집하여 다각적으로 분석하여야 하며, 이들 정보의 종류, 내용, 가중치(상대적인 중요도) 등은 계속 변화한다. 임도망 편성의 전산화는 주로 임도망 편성용 프로그램 개발·이용과 GIS 이용의 두가지 측면에서 진행되어 왔다. 현재까지 국내에서 개발된 임도망 편성용 프로그램은 산림청 행정전산망에 입력되어 있는"FRNET"를 비롯한 2종이다. 그러나 이러한 전용 프로그램을 이용하는 방법은 이미 프로그램 자체적으로 임도망 편성시에 고려하여야 할 정보의 종류, 내용, 가중치 등이 결정되어 있다. GIS를 이용하는 방법은 이용자가 상황에 따른 정보의 추가 및 가중치의 변화가 전용 프로그램을 이용하는 방법에 비하여 용이하다. 따라서 현재 GIS를 이용한 임도망 편성에 대하여 연구 검토가 진행되고 있으나 아직까지는 이용할 수 있는 정보가 충분하지 않다. 그러나 전분야에서 GIS 기초자료를 구축하고 있으므로 앞으로 임도망 편성 등 임도 계획에 있어서 활발히 이용될 것으로 전망된다. ※ FRNET를 이용한 임도망 편성 + +- ① 시스템 개요 ㉠ 전산기기 : PC 또는 단말기, 프린터 ㉡ 사용기종 : VAX System(산림청 행정전산망 운용기종)㉢ 운영방식 : 문답방식으로 담당자가 직접 제한조건의 값을 입력 ㉣ 특징 : +- - 제한조건의 변화에 따라 여러 형태의 임도망을 편성 +- - 선점(選點) 단계별로 분석결과를 제시 +- ② 기초자료 작성 및 입력 ㉠ 지형도 및 임상도에 격자망을 만들고 각 격자에 행열의 번호를 부여한다. ㉡ 각 격자의 행열번호, 표고(m), 산지경사(%), 임종(형태), 영급, ha당 임목축적(㎥/ha), 기설도로의 행열번호 조사 +- - 임종 : 인공침엽수림(1), 인공활엽수림(2), 인공혼효림(3), 천연침엽수림(4), 천연활엽수림(5), 천연혼효림(6) +- - 기설도로 : 1개 이상의 기설도로를 반드시 표시 ㉢ 입력내용 기설도로자료 : 통과 행열번호입지자료 : 표고, 경사도, 임종, 영급, ha당 축적기타 : 구역면적, 격자간격, 임도밀도, 한계물매, 임도 및 집재우회율, 집재단가, 임도단가 +- ③ 작업 흐름도 + +![설계_그림5-2-72_FRNET흐름도](<../pic/설계_그림5-2-72_FRNET흐름도.png>) + +- ④ 출력사항 ㉠ 초기화면 상에서 입력한 제한조건의 적용값과 기설도로의 행열번호 ㉡ 선점(選點) 단계별로 선점된 행열번호, 집재재적, 집재비용 및 임도시설비용, 임도연장, 종단물매, 평균집재거리, 선점순서, 가중평균집재거리, 집재거리 표준편차, 개발지수 ㉢ 도로(임도)의 기설·계획·총연장, 계획임도시설비, 적정임도밀도 +#### 2) 임도설계의 전산화 + +임도의 설계는 노선측량, 선형 결정·설계도 작성·공사수량 산정, 설계예산 산정의 과정으로 진행되며 각 과정은 서로 밀접한 관계가 있다. 즉 선형이 결정되어야만 설계도 작성 및 공사수량 산출과 설계예산 산정이 진행되지만, 공사수량 및 설계예산이 과다하면 선형은 변경되어야한다. 이러한 과정은 최종적인 선형이 결정될 때까지 반복되며 임도시공 중일지라도 시공대상지의 여건에 따라 설계가 변경되기도 한다. 임도 설계를 계산 및 도면작업을 동시에 수행하는 설계도 작성 및 공사수량 산출과 계산작업만을 수행하는 설계예산 산정의 두가지로 구분하여 전산화 현황을 살펴 보면 다음과 같다. + +##### 가) 설계도 작성 및 공사수량 산출의 전산화 + +임도분야의 경우 임협중앙회에서는 설계프로그램을 자체 개발하여 설계기초자료 산출 및 종단면도·횡단면도·구조물도 작성에 이용하고 있으며 평면도 작성 프로그램은 현재 개발 중에 있다. 일반도로 분야에서는 RP(Road Project), ROCAD 등 여러 종류의 설계도 작성 프로그램이 개발되어 설계기초자료 산출 및 평면도·종단면도·횡단면도·구조물도 작성 등 등고선 기입을 제외한 대부분의 설계도 작성과정이 전산화되었다. 또한 공종별 수량 산출에 있어서 토공량의 산출은 전산화되었으나, 구조물 등 기타 공종의 수량 산출은 스프레드시트를 비롯한 별도의 소프트웨어을 이용하거나 수계산한다. + +##### 나) 설계예산 산정의 전산화 + +설계예산 산정은 단순계산이 반복되는 과정이므로 전산화가 용이하였으며 시스템(프로그램)간의 자료의 호환성도 매우 높다. 현재 국내에서 개발 사용 중인 설계예산 산정 시스템은 수십 개에 달하며, 1996년 조달청에서는 18개사 36개의 프로그램을 선정하였다. 임도 설계예산 산정작업에는 이중 하나인 "STmate"를 주로 사용하고 있다. ※ 프로그램별 내용 + +- ○ STmate를 이용한 설계예산서 작성 +- ① 시스템 개요 ㉠ 전산기기 : PC(KS완성형 한글의 사용이 가능한 AT급 이상), 프린터 ㉡ 기초자료 : 물가자료(노임단가, 자재단가, 중기단가) 및 단가산출근거 ㉢ 운영방식 : 메뉴방식로 담당자가 직접 해당항목번호를 선택 ㉣ 특징 +- - 한글에 의한 검색으로 신속한 확인 및 입력 가능 +- - 자료변경시 관련항목전부에 대한 재계산 실행 +- - 타공사설계시 기설계자료의 계속적인 활용 가능 +- - 자료의 통합관리체제 하의 공사별 자료관리 가능 +- ② 전산처리 흐름도 + +![설계_그림5-2-73_STmate흐름도](<../pic/설계_그림5-2-73_STmate흐름도.png>) + +그림 5-2-73에서 보는 바와 같이 “STmate”는 자료관리에 있어서 일반적으로 “기초자료∼단가계산”의 과정은 모든 공사에 동일하게 적용되므로 공사종류에 관계없이 통합관리되고 있으며, “공사비계산∼간접비계산”의 과정은 해당공사별로 독립관리되고 있다. 그러나 작업을 완료한 후 출력 시에는 해당공사별로 출력이 가능하다. + +- ③ 기초자료작성 및 입력 ㉠ 초기화 : 환율, 노임단가, 소수점, 계산방식, 단가조사시점, 자재비교표 등. ㉡ 단가표입력 및 수정 : 노임, 자재, 경비, 복합단가 등. ㉢ 단가산출 : 일위대가표, 중기사용료 등의 입력 및 수정 +- ④ 출력사항 : 단가표, 단가산출서, 단가산출근거, 일위대가표, 중기대가표, 설계내역서, 공사 원가계산서 등 +- ○ 임협설계시스템을 이용한 설계도서 작성 +- ① 시스템 개요 ㉠ 전산기기 : PC(386급 이상), 플로터(A1 이상), 프린터(레이져), Auto-CAD(ver. 11 이상) ㉡ 사용언어 +- - Clipper(종단면도, 횡단면도, 내역서 등) +- - FORTRAN(토적수량계산서)㉢ 기초자료 : 물가자료(노임단가, 자재단가, 중기단가) 및 단가산출근거, 현지측량자료 및 구조규격 ㉣ 특징 +- - 종단면도, 횡단면도, 구조물도 등의 도화작업 가능(Spread Sheet 이용) +- - 입력, 수정, 자료의 연속성 등 사용이 쉽고 도화작업의 다양성이 있음 +- ② 전산처리 흐름도 + + - ㉠ 종단면도: 그림 5-2-74 + - ㉡ 횡단면도: 그림 5-2-75 + - ㉢ 토공수량산출: 그림 5-2-76 + - ㉣ 내역서 작성: 그림 5-2-77 + +![설계_그림5-2-74_종단면도흐름도](<../pic/설계_그림5-2-74_종단면도흐름도.png>) + +![설계_그림5-2-75_횡단면도흐름도](<../pic/설계_그림5-2-75_횡단면도흐름도.png>) + +![설계_그림5-2-76_토적계산흐름도](<../pic/설계_그림5-2-76_토적계산흐름도.png>) + +![설계_그림5-2-77_내역서흐름도](<../pic/설계_그림5-2-77_내역서흐름도.png>) + +- ③ 기초자료 및 입력 ㉠ 설계도화자료 : 지반고, 계획선, 횡단경사, 추정암선, 구조물의 종류·규격, 토성별횡단선형기울기, 노폭, 측구폭. ㉡ 금원화자료 : STmate와 같음 +- ④ 출력사항 ㉠ 도면 : 횡단면도, 종단면도, 구조물도 ㉡ 부속서류 : STmate와 같음. +- ○ Earth work를 이용한 토적설계 +- ① 시스템 개요 ㉠ 전산기기 : PC 또는 단말기, 프린터 ㉡ 사용기종 : VAX System(산림청 행정전산망 운용기종)㉢ 운영방식 : 문답방식으로 담당자가 직접 제한조건의 값을 입력 ㉣ 특징 : 현지측량인자를 입력하여 토적계산, 토량운용계획 제시 +- ② 기초자료 작성 및 입력 ㉠ 현지측량인자 : 측점, 토성, 경사도, 거리, 평균거리 ㉡ 종단면도인자 : 성·절토고 ㉢ 횡단선형인자 : 노폭, 측구폭, 절토사면기울기, 성토사면기울기 +- ③ 작업 흐름도 + +![설계_그림5-2-78_Earthwork흐름도](<../pic/설계_그림5-2-78_Earthwork흐름도.png>) + +- ④ 출력사항 + +- ④ 출력사항 ㉠ 토적사항 : 측점, 토성, 경사도, 거리, 평균거리, 절토단면적·입적, 성토단면적. 입적, 절토사면길이·면적, 성토사면길이·면적, 임도폭·면적 ㉡ 토량유용계획 : 측점, 거리, 절토입적, 토량환산입적, 유용토량, 잔토량, 부족토량, 누적토량 +##### 다) 임도시공 및 유지관리 분야의 전산화 + +임도 시공 및 유지관리 분야의 전산화는 산림청에서 기본적인 임도시설 현황자료를 수집 입력하고 있을 뿐 거의 전무한 실정이다. 그러나 최근 들어 집중호우로 인한 대규모의 임도 재해가 발생하고 있으므로 우리 나라에 적합한 임도시공 및 유지관리기술 개발에 대한 중요성이 점차 부각되고 있다. 따라서 임도시공 및 유지관리 정보의 데이터 베이스를 구축하는 것은 매우 시급히 이루어져야 할 것이다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 87~117쪽 (인쇄면 457~487쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/6. 시공.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/6. 시공.md new file mode 100644 index 00000000..6baaba67 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/6. 시공.md @@ -0,0 +1,790 @@ +# 6. 시공 + +### 가. 토공사 +#### 1) 절토 +##### 가) 절토사면 기울기 +- ① 지질, 토질, 함수량의 변화, 지하수위, 용수의 상황, 풍화의 정도, 성층상태 등을 종합적으로 고려하여 절취고에 대한 충분한 안전성이 확보될 수 있도록 기울기를 설정한다. +- ② 표준기울기는 경험적으로 (표 5-2-41)과 같다. +##### 나) 절토사면의 형 + +사면의 형식은 (그림 5-2-79)와 같이 3가지로 구분할 수 있다. +- ① {그림 5-2-79(a)}는 단일 기울기로서 절취고 7∼10m 이하의 경암에 적합하고 +- ② {그림 5-2-79(b)}는 암질이 다른 층으로서 층마다 기울기를 다르게 적용한 것이며 +- ③ {그림 5-2-79(c)}는 절취고가 7∼10m를 초과하며 암질이 변화하는 경우에 적합한 공법인데 소단을 만들기 때문에 초기 공사비는 많이 소요되나 시공 후 유지비가 적게 소요되며 교통상으로 안전한 이점이 있고 +- ④ 소단의 폭은 보통1.5m가 표준이고, 소단에는 5∼10%의 횡단물매를 주며 설치높이의 간격은 절취고에 따라 다르나 5∼10m 간격으로 한다. + +![시공_그림5-2-79_본바닥상태와절취사면](<../pic/시공_그림5-2-79_본바닥상태와절취사면.png>) + +표 5-2-41. 절취사면의 표준기울기 + +| 본바닥의 토질 및 지질 | | 절취 고(m) | 사면기울기(할) | +|---|---|---|---| +| 경 암 | | | 0.3∼0.8 | +| 연 암 | | | 0.5∼1.2 | +| 모 래 | | | 1.5∼ | +| 사 질 토 | 다져진것 | 5 이하 | 0.8∼1.0 | +| | | 5∼10 | 1.0∼1.2 | +| | 느슨한것 | 5 이하 | 1.0∼1.2 | +| | | 5∼10 | 1.2∼1.5 | +| 력(礫) 질 토 암괴또는조약돌 섞 인 사질토 | 다져진것또는입도 분포가 양호한 것 | 10 이하 | 0.8∼1.0 | +| | | 10∼15 | 1.0∼1.2 | +| | 다져지지않은것또는입도 분포가 나쁜 것 | 10 이하 | 1.0∼1.2 | +| | | 10∼15 | 1.2∼1.5 | +| 점 토, 점질토 | | 10 이하 | 0.8∼1.2 | +| 암괴또는조약돌섞인 점질토, 점토 | | 5 이하 | 1.0∼1.2 | +| | | 5∼10 | 1.2∼1.5 | +| 주) 위표는 식생 등으로 적절한 보호를 할 경우에 적용할 수 있다. | | | | + +##### 다) 절토사면 조성시 주의사항 + +자연상태의 본 바닥을 절취할 경우에는 비탈면 붕괴가 우려되므로 설계시에 토질조사 또는 지질조사를 실시하여 사면기울기에 대한 타당성과 보호방법 등을 검토한다. 특히 주의할 지역은 다음과 같다. + +- ① 지하수위가 높고 사면에 용수의 우려가 있는 곳 +- ② 사층 등의 투수층과 점토층 등의 불투수성이 교대로 층을 이루고 있으며 그 경계면의 경사도가 절취면의 경사도와 동일한 방향으로 구성되어 있는 곳 +- ③ 수성암의 경사층이 절취면과 동일한 방향으로 경사진 곳 +- ④ 사문암, 혈암, 전판암 등의 변질암이 있는 곳 +- ⑤ 산사태 또는 산허리 붕괴의 위험이 있는 곳 +- ⑥ 단층 또는 단층의 영향을 받고 있는 곳 +- ⑦ 물을 함유한 세립분이 많은 사층 +- ⑧ 연한 점토, 경면표상(鏡面表狀), 모상균열(毛狀龜裂)이 있는 경점토가 있는 곳 +##### 라) 암반절취방법 +- ① 암반은 폭약을 천공속에 장진하여 파쇄하는 방법과 폭약없이 기계력, 수력, 열력, 전기력에 의한 절취방법이 있다. +- ② 방법의 선택은 경연성, 풍화정도, 균열상태 등 암질로서 정하는 경우와 진동, 소음, 비산 등 공해와 안정성 등 현장조건으로 정하는 경우가 있다. +#### 2) 성토 +##### 가) 기초지반 +- ① 성토(Banking)의 기초지반은 성토, 포장의 중량 및 교통하중에 침하하지 않고 안전하게 지지하도록 한다. +- ② 연약지반 위에 성토를 할 경우에는 기초지반이 옆으로 유동되거나 압밀침하를 일으킬 우려가 있으므로 충분히 검토한다. +- ③ 성토고 1m이하로 낮게 성토를 할 경우에는 교통하중에 대한 영향력이 기초지반까지 직접 전달되기 때문에 기초지반에 있는 수분이 성토 상부까지 영향을 미칠 우려가 있으므로 기초지반을 부분적으로 제거하거나 투수성이 좋은 성토재료로 교체하는 것을 검토한다. +- ④ 연약지반 개량공법으로는 치환공법, 압성토(Preloading)공법, 웰 포인트(Well Point) 공법, 샌드드레인(Sand Drain)공법, 약액 주입공법 등이 있다. +##### 나) 성토재료 +- ① 성토재료는 시공의 난이도와 역학적인 성질을 좌우하게 되므로 양질의 재료를 선택하도록 한다. ㉠ 양질재료 : 시공이 용이하고 전단강도가 크며 압축성이 작은 성질을 가진 흙 ㉡ 불량재료 : 흡수성과 압축성이 크거나 부식물이 많이 함유된 흙 +- ② 재료속에 입도가 큰 력석(礫石)이 포함되어 있으면 시공이 곤란하고 다짐작업이 불충분하여 지지력이 불균일 하게 된다. +- ③ 1회 다짐두께는 20∼30cm로 하고 양질의 재료일 수록 포장면에 가까운 윗층부에 포설하도록 하며 이때 포함되는 력석의 최대치수는 20∼30cm 정도로 한다. +##### 다) 다짐 +- ① 다짐의 목적은 성토된 노체, 노상 및 사면 등을 안정된 상태로 유지하고, 교통하중을 지지할 수 있는 내압(耐壓)강도를 향상시킴은 물론 성토 그 자체의 압밀침하를 줄이기 위하여 실시한다. +- ② 성토작업방법은 수평층으로 한층 한층 순차적으로 다지면서 작업을 하며, 다짐상태의 정도를 추정하기 위하여 건조밀도, 포화도 또는 공기공극율, 강도특성 중 하나를 측정하도록 규정하는 방법과 다짐기종별, 다짐회수를 규정하는 방법이 있다. +##### 라) 성토사면의 기울기 +- ① 성토사면 기울기의 설정은 현장의 지형, 토질, 기상조건, 인접하는 물건, 사면 보호공의 종류, 시공법 등을 고려한 안정계산을 실시하여 성토의 안정성이 충분히 보장될 수 있도록한다. +- ② 성토재료의 종류와 성토높이에 따라 정한 경험적인 기울기는 (표 5-2-42)와 같다. 표 5-2-42. 성토사면의 표준기울기 + +| 성 토 재 료 | 성토높이(m) | 사면기울기(할) | +|---|---|---| +| 입도분포가 좋은 모래 | 0∼5 | 1.5∼1.8 | +| 입도분포가 좋은 역질토 | 5∼15 | 1.8∼2.0 | +| 입도분포가 나쁜 모래 | 0∼10 | 1.8∼2.0 | +| 암괴, 조약돌 | 0∼10 10∼20 | 1.5∼1.8 1.8∼2.0 | +| 사질토 | 0∼5 | 1.5∼1.8 | +| 경점질토, 경점토 | 5∼10 | 1.8∼2.0 | +| 연점질토, 연점토 | 0∼5 | 1.8∼2.0 | + +##### 마) 성토사면 조성시 주의사항 +- ① 시공시 안정성검토가 필요한 지역은 다음과 같다. ㉠ 성토높이가 10m를 초과할 경우 ㉡ 높은 함수비의 점성토와 같이 전단강도가 낮은 경우 ㉢ 연약지반 위에 성토할 경우 ㉣ 산사태나 사면붕괴 등을 일으킬 염려가 있는 불안정한 지반 또는 급한 사면에 성토할 경우 +- ② 성토를 높게 시공할 경우에는 그림 5-2-80(a)와 같이 사면 중간에 소단(berme)을 설치한다. 소단은 성토의 안정성을 높이고, 사면 유수로 인한 침식을 방지하며, 유지보수 작업원의 발판으로 이용할 수 있다. +- ③ 소단의 폭은 1∼2m, 높이의 간격은 6m로서 5∼10%의 횡단물매를 주며 필요에 따라 식생이나 배수구를 설치하여 소단면을 보호한다. +- ④ {그림 5-2-80(b)}는 용지면적이나 토량을 절약하기 위하여 하부의 기울기를 표준보다 더 완만하게 하고 그 위에 성토하는 방법이다. +#### 3) 편절·성토 및 절·성토부의 접합부분 처리 +##### 가) 편절·성토 접속부 +- ① 임도 횡단면의 토공이 편절·성토(Cut and Fill)로 시공되는 구간에는 그 접속단에 1 : 4 정도의 물매로 완화구간을 설치하여 노상지지력이 경사방향으로 급변하는 것을 피한다. +- ② 용수나 배수를 위하여 절취면 끝 접속부에 맹구(용수가 많은 경우 구멍 뚫린 관(有孔菅))를 설치하는 것이 좋다. +- ③ 원지반의 지표횡단물매가 1 : 4 이상으로 급할 경우에는 표토를 제거한 후 (그림 5-2-81)과 같이 성토부분의 기초를 계단식 층따기(Bench Cut)로 한다. + +![시공_그림5-2-81_편절토편성토접속횡단면](<../pic/시공_그림5-2-81_편절토편성토접속횡단면.png>) + +| 층따기 치수(cm) | | | +|---|---|---| +| 토성 | 깊이 | 폭 | +| 토사 암 | 50 40 이상 | 100 이상 | + +그림 5-2-81. 편절토, 편성토 접속부분의 횡단면 + +##### 나) 절·성토 접속부 + +절토구간과 성토구간의 종단방향 접속부에는 (그림 5-2-82)와 같이 접속구간을 설치하여 노상지지력의 불연속성을 보강한다. + +![시공_그림5-2-82_절토성토접속종단면](<../pic/시공_그림5-2-82_절토성토접속종단면.png>) + +그림 5-2-82. 절토, 성토 접속부분의 종단면 + +### 나. 사면 보호공사 + +절토, 성토의 사면은 오랜동안 방치하면 강우로 인한 침수와 풍화작용으로 붕괴하게 되므로 현장조건에 적합한 방법으로 보호하여 안정을 유지하여야 한다. + +#### 1) 사면파괴의 원인 +- ① 빗물, 눈 기타의 하중 +- ② 함수량의 증가 +- ③ 식물의 뿌리 등 +- ④ 온도변화에 의한 신축 +- ⑤ 동결과 융해의 반복 +- ⑥ 지진 또는 발파에 의한 충격 +- ⑦ 인장응력에 의한 균열 +- ⑧ 균열 중의 수압 +- ⑨ 함수비에 의한 팽창 +- ⑩ 공극수압의 증가 +- ⑪ 조직의 파괴 +- ⑫ 점착력이 약해질 때 등 +#### 2) 사면파괴의 모형과 원인 +- ① 사면밑 붕괴원(崩壞圓) : 연한 점토성 사면의 길이가 비교적 높을 경우 +- ② 사면 붕괴원(崩壞圓) : 사면의 기울기가 비교적 급할 경우 +- ③ 중앙점(中央點) 붕괴원 : 활면(滑面)이 굳은 층과 접하고 있을 경우 +#### 3) 사면 보호공의 종류 +- ① 식물에 의한 보호공법 : 떼붙이기공, 식생공, 식수공, 파종공 등 +- ② 구조물에 의한 보호공법 : 콘크리트 붙이기공, 돌쌓기공, 돌 및 블록붙이기공, 뿜어붙이기 공, 콘크리트틀공, 돌망태공 등. ※ 공사비, 경관 등으로는 ①의 방법이 유리하나 시공시기, 지질, 토질, 기울기, 용수의 상황 등으로 ①의 방법이 곤란할 때에는 ②의 방법을 적용하거나 또는 ①과 ②의 방법을 혼용한다. +#### 4) 공종별 시공방법 +##### 가) 떼붙이기공 +- ① 줄떼공 : 성토면에 주로 사용하며 폭 10㎝로 잘라 30㎝간격으로 수평으로 붙인다. +- ② 평떼공 : 절취면에 주로 사용하며 떼(30㎝×20㎝)를 비탈면 전체에 떼붙임꽂이로서 사면에 붙인다. +##### 나) 식생공 +- ① 흙, 퇴비, 비료 등의 혼합체와 소량의 물을 섞어 볏짚에 바른 다음 종자를 붙이고 식생판을 만들어 꽂이로 사면에 붙인다. +- ② 연암, 자갈섞인 흙 등의 급사면에 적합하며 식생판공, 식생포대공, 식생구멍공, 식생매트공 등이 있다. +- ③ 그 지역 재래 초본종자인 쑥, 새류, 목초, 목본종자인 싸리나무 등을 혼파한다. +##### 다) 식수공 +- ① 사면에 말뚝을 박아 울타리를 만들고 그 위에 비료를 뿌리고 묘목을 심거나, 사면에 식혈을 파서 흙과 비료를 넣고 식수한다. +- ② 떼붙이기공이나 식생공만으로는 붕괴의 우려가 있는 사면에 이용된다. ※ 관목류로서는 병꽃나무, 개나리, 철쭉류, 조릿대, 싸리류, 국수나무 등이 이용된다. +##### 라) 파종공 +- ① 종자(위핑 그래스, 크로버 등), 비료, 안정제, 양생제, 흙 등을 혼합하여 압력으로 뿜어 붙인다. +- ② 넓은 지역의 사면녹화에 적합하다. +##### 마) 콘크리트 붙이기공 +- ① 연암 등의 사면에 낙석의 우려가 있고 용수가 적은 경우에는 철근 콘크리트, 무근 콘크리트, 아스팔트 콘크리트 붙이기공법을 사용한다. +- ② 철근 콘크리트 붙이기공 : 두께 15cm의 기초호박돌을 깔고, 2m간격의 활동방지공이나 앵커설치 후 철망 또는 철근 조립 콘크리트를 시공한다. +- ③ 무근 콘크리트 붙이기공 : 최소 20cm두께로 시공한다. +- ④ 아스팔트 콘크리트 붙이기공 : 사면의 기울기가 완만한 경우에 시공한다. +##### 바) 돌쌓기와 돌붙이기공 +- ① 돌쌓기공과 블록쌓기공은 사면기울기가 1할 이상으로 급할 경우에 이용된다. +- ② 1할 이하로 완만할 경우에는 돌붙이기공, 블록붙이기공을 이용한다. +##### 사) 뿜어붙이기공 +- ① 시멘트나 아스팔트를 혼합하여 기계적으로 압송하여 뿜어 붙이며, 시멘트 몰탈 뿜어붙이기, 시멘트 콘크리트 뿜어붙이기, 아스팔트 몰탈 뿜어붙이기가 있다. +- ② 사면에 용수가 없고 현재는 붕괴되지 않지만 추후에 풍화낙석이 우려되는 경우의 풍화하기 쉬운 암, 전석, 조약돌 섞인 사면 등에 이용된다. +##### 아) 틀공 +- ○ 콘크리트와 PY틀공 +- ① 높은 사면이나 표준기울기 보다 급한 성토 사면, 용수가 있는 절토사면 등의 식생이 부적합한 곳 또는 식생이 적정해도 표면이 붕괴할 우려가 있는 곳에 이용된다. +- ② 현장타설이나 프리케스트 제품으로 틀의 교차부에 활동방지 말뚝 등을 설치한다. +- ③ 틀안에는 좋은 흙을 되메우고 식생을 하는 것이 좋으나 기울기가 급한 곳, 용수가 많은 곳, 좋은 흙을 얻기가 어려운 곳, 식생으로는 사면유출이 우려되는 곳 등은 틀안에 호박 돌, 큰자갈 등으로 찰임 또는 메붙임을 한다. +- ○ 편책과 목책공 +- ① 편책공은 부식토층을 만들어 식물을 보호하고 강우로 인한 사면 토사의 유출을 방지하며 흙막이로 낙석을 방지할 수 있다. +- ② 나무말뚝을 박고 섶가지나 대나무 등을 엮어 흙막이를 하여 사면을 안정시키며 말뚝의 깊이는 비탈면 동결깊이 보다 깊게 한다. 지장목과 간벌재가 많은 곳은 섶가지나 대나무 대신에 통나무를 이용할 수 있으며 이를 목책공이라고 한다. +- ③ 초·목본류를 혼생시켜 한쪽의 생육이 불량하여도 다른쪽의 생육이 양호하도록 하거나, 초기는 초본류가 그후는 목본류가 사면을 안정토록 하기 위하여 여러종을 혼식 혼파함이 좋다. +##### 자) 돌망태공 +- ① 돌망태는 신축 변형되므로 절취사면에서 용수에 의하여 내부의 토사가 유실되어도 붕괴가 일어나지 않기 때문에 매우 효과적이며, 버드나무 등의 식수도 가능하다. +- ② 비탈면 돌망태(원형, 타원형, 반원형)와 방석돌망태(직사각형)이 있다. +### 다. 포장공사 +#### 1) 포장의 종류와 기능 +##### 가) 포장의 종류 + +포장은 실용적인 면에서 크게 아스팔트콘크리트 포장{可撓性(軟性)鋪裝 : Flexible Pavement}과 시멘트콘크리트 포장(剛性鋪裝 : Rigid Pavement)으로 대별할 수 있다. + +##### 나) 포장층의 구성과 기능 +- ○ 아스팔트콘크리트 포장 +- ① 노상위에 동상방지층, 보조기층, 기층, 중간층, 표층의 순으로 {그림 5-2-83(a)}와 같이 구성되며 +- ② 노상이 연약한 경우에는 노상토가 보조기층으로 침입하는 것을 방지할 목적으로 하천사 또는 양질의 산사를 사용하여 차단층을 시공하고, 한냉지에서는 동상의 위험이 있을 경우에는 모래, 막자갈, 슬래그 등 선택된 재료로서 동상방지용 선택층을 시공한다. + +| 층의호칭 | 대표적인사용재료 | 포포 ( 장장 구두 조께 ) | 구성요소의명칭 | | | | +|---|---|---|---|---|---|---| +| 표 층 | 밀립도아스팔트콘크리트 | | | | 포래두 | | +| | | | | | | 포 | +| 기 층 | 조립도아스팔트콘크리트 | | 시멘트콘크리트슬래브 | | 장브께 | | +| | | | | | | 장 | +| 상층보조기층 | 입도조정부순돌 | | | | 슬의 | | +| | | | | | | 구 | +| 하층보조기층 | 막 자 갈 | | 보 조 기 층 | | | | +| | | | | | | 조 | +| | 노 상 | | 노 상 | | | | + +| 포 | 포 ( | +|---|---| +| 장 | 장 | +| 구 | 두 | +| 조 | 께 ) | + + +- ③ 표층위에 미끄럼 방지와 마모저항을 높이기 위하여 3㎝ 내외의 마모층을 시공하는 경우에도 있으나 이 경우의 마모층은 포장구조계산에는 포함시키지 않는다. +- ○ 시멘트콘크리트 포장 노상위에 보조기층, 기층(별도로 두지 않을 경우도 있음), 시멘트 콘크리트 표층으로 {그림 5- + +2-83(b)}와 같이 구성된다 + +#### 2) 포장의 선택 +##### 가) 입지조건 +- ① 교통조건 : 계획기간의 교통량, 교통의 구성(특히 중교통량), 교통증가의 추이 등 +- ② 토질의 조건으로서 노선의 지반상태 : 지지력의 크기, 노상 및 보조기층 재료의 구득성, 지하수위 상태, 동상조건 +- ③ 기후·기상조건에 따른 포장의 영향 : 강우, 강설, 기온의 변동 등 +- ④ 지형, 특히 산악지역의 편절·편성구간의 비율, 부등침하요소 등. +##### 나) 경제성 +- ① 초기 건설비, 유지관리비, 보수공사에 따른 교통지체비용, 도로이용자 비용, 덧씌우기 또는 재포장비용과 잔존가치 등의 총비용을 비교한다. +- ② 초기 건설비는 시멘트 콘크리트 포장이 10∼20%정도 비싸지만 유지보수비는 아스팔트 포장이 높다. +##### 다) 항목별 비교 + +표 5-2-43. 아스팔트 포장과 시멘트 콘크리트 포장의 비교 + +| 항 목 | | 아스팔트포장 | 시멘트콘크리트포장 | +|---|---|---|---| +| 구 조 | 설계법의신뢰성 | 아스팔트 재료의 역학적 특성이 복잡하 기 때문에 불 학 실한 부분이 많다. | 콘크리트는 재료역학적으로 해명되 어 있기 때문에 아스팔트 포장보다 신뢰성이큰설계가가능 | +| | 적용범위 | 간단한 구조에서 고급인 것에 까지 폭 넓게적용가능 | 간단한 구조에도 이용하고 있으나 일반적으로 고급 포장에 이용된다. | +| 강 도 | 내용년수 | 설계의 목표는 10년, 유지수선에 따라 내용년수를연장할수있다. | 설계의목표는20년 | +| | 내변형, 내마모성 | 변형하여 자국이 생기기 쉽다. 스파이크 타이어에 대한 내 마모성이 적다. | 자국과 같은 변형을 일으키고 내마 모성도일반적으로크다. | +| 표 면 성 상 | 미끄럼저항 | 시공의 양부에 따라 변화가 크고 미끄 럼이쉬운경우가있다. | 미끄럼 저항의 변동이 적고 일반적 으로미끄럼이적다. | +| | 평탄성 | 고급인 포장에는 콘크리트 포장 보다 양호하다. | 줄눈이 있기 때문에 아스팔트 포장 과 동 등의 평탄성은 얻기 어렵다. | +| | 소음, 진동 | 콘크리트 포장에 비하여 소음, 진동이 적은것이많다. | 줄눈에 따라 진동, 거친면에 따라 소음이 아스팔트 포장 보다 일반적 으로크다. | +| | 명색성 | 노면반사가약하고, 운전의피로도는적 으나 야간 주행성에는 떨어진다. | 야간이나 터널내 등에서 밝으나 노 면반사가크다. | +| 시공성 | 시공속도와양생 | 일반적으로 시공속도가 빠른 양생이 불 필요하기 때문에 교통에 개방할 수 있 는시기가빠르다. | 시공속도가 늦기 때문에 대형의 시 공기계가 필요하고 양생기간이 있 기 때문에 교통 개방이 늦어진다. | +| 유 지 수 선 | 유지수선 | 간단한 공법으로 유지수선이 가능하다. 그러므로 지하 매설 물의 설치에 적당하다. | 비교적 복잡한 공법을 채용하지 않 으면안된다. | +| 경제성 | 건설비와유지비 | 건설비는 콘크리트 포장에 비하여 저가 이나 유지수선을 자주 행할 필요가 있 으므로 20년간의 비교에는 비교적 고가 이다. | 유지수 선의 횟수가 적어 좋으나20년 간의 총비용은 낮아진다. 단, 보수의 경우에는 아스팔트 포장보다 높다. | + +#### 3) 아스팔트 포장 +##### 가) 노상 +- ① 노상은 포장체를 통하여 전달되는 분산하중을 충분히 지지하는 동시에 시공중에는 장비와 공사용 차량 등의 하중에 견딜 수 있는 흙부분이다. +- ② 성토부에서는 성토마무리면으로 부터, 절토부에서는 굴착면으로 부터 약 1m 아래부분을 노상이라고 하고 노상의 지지력과 강도는 포장의 두께와 보조기층 및 기층의 공법을 결정하는 중요한 인자가 된다. +- ③ 노상은 충분한 지지력을 갖추고 반복되는 교통하중에 의하여 발생되는 노상토의 압축침 하에 대하여 저항하며 물에 의하여 약화되지 않는 역학적 성질이 요구된다. +- ④ 노상토에 요구되는 품질과 시공기준은 (표 5-2-44)와 같다. 표 5-2-44. 노상토의 품질과 시공기준 + +| 층 별 | 품 질 규 정 | | | | 시 공 기 준 | | | +|---|---|---|---|---|---|---|---| +| | 최 대 치 수 | 입 도 | 소성지수 | 수 침 CBR | 다 짐 도 | 시 공 시 함 수 비 | 1층완성 두 께 | +| 상부노상 | 100㎜ | 4.76㎜이하 : 25-100% 0.074㎜이하 : 0-25% | 10% 이하 | 10% 이상 | 흙의 다짐시험에 의한 γd max의 95% 이상 | 최적함수비를 원칙으로 함. | 20㎝ 이하 | +| 하부노상 | 150㎜ | 4.76㎜이하 : 95%이상 0.074㎜이하 : 5%이하 | 30% 이하 | 5% 이상 | 흙의 다짐시험에 의한 γd max의 90% 이상 | 수정 CBR 5 이상으로 되는 함수비 | 20㎝ 이하 | + +##### 나) 배수 +- ① 포장의 파괴에 직·간접적으로 영향을 크게 미치는 것이 물이므로 포장의 수명은 배수에 달려 있다고 하여도 과언이 아니므로 배수를 잘하면 공사의 효율성도 증진되며 강우에 대한 피해도 예방할 수 있다. +- ② 배수에는 포장표면의 배수와 지하배수로 나눌 수 있고 표면배수는 임도의 선형설계와 밀접한 관계가 있다. +- ③ 임도로 침입하는 물은 인접지대나 노면으로 부터 침투하는 것과 지하면에서 상승하는 경우가 있으며 이러한 침투수를 빨리 배제하기 위하여 침입하기 전에 차단한다. +- ④ 지하수위가 높은 곳과 용수가 많은 장소에서는 노상에 침투하는 지하수를 차단하거나 지하수를 노면 아래 50∼100㎝이하로 저하시키기 위하여 지하배수구를 설치할 필요가 있다. +##### 다) 보조기층과 기층 +- ① 기층과 보조기층은 표층으로부터 전달된 교통하중에 충분히 견디고 그 하중을 분산하여 노상에 과도한 응력을 주지 않으며 노상부나 주변으로부터 물의 침입을 방지하는 중요한 역할을 한다. +- ② 보조기층은 그 두께에 의한 하중분산효과를 기대하여 재료의 질적인 면보다는 경제성에 더 중점을 두기 때문에 현장부근에서 구득할 수 있는 재료를 이용하여 입상재료공법, 시멘트 및 석회 등의 첨가제를 가하여 강도를 개량하는 안정처리공법을 사용한다. +- ③ 기층은 표층 바로 아래에 위치하므로 하중조건도 혹심하고 역학적으로도 안정된 층이 요구되므로 입도조정공법, 아스팔트 안정처리공법, 시멘트 안정처리공법을 사용한다. +- ④ 기층과 보조기층이 구비하여야 할 성질과 기준은 (표 5-2-45)와 같다. 표 5-2-45. 기층 및 보조기층이 구비하여야 할 성질과 기준 + +| 층별 | 물리적인규정 | | | 강도규정 | 시공규정 (1층완성두께) | +|---|---|---|---|---|---| +| | 최대입경 | 입 도 | 소성지수 | | | +| 보 조 기 층 | 50㎜이하1 층완성두께의 1/2이하로 100㎜까지허 용 | 특별한 규 정 없음. | 입도조정: 6 이하 시멘트안정처리 : 9 이하 석회안정처리 : 6∼18 이하 | •수침CBR값>30 •일축압축강도 시멘트안정처리 : 10kg/㎠ 석회안정처리 : 7kg/㎠ | •입상재료20㎝ 이하 •안정처리15-20㎝ | +| 기 층 | 40㎜ 이하 1 층완성두께의 1/2이하 | 별도있음. | 입도조정: 4 이하 시멘트안정처리 : 9 이하 석회안정처리 : 6∼18 이하 역청안정처리 : 9 이하 | •수침CBR값>80 •일축압축강도 시멘트안정처리 : 30kg/㎠ 석회안정처리 : 10kg/㎠ 안정도350kg이상 | 15㎝이하 10-20㎝ 10㎝이하 | +| 주) 주요공법 | | | | | | +| ㉠입상재료공법: 막자갈, 막 부순 돌을 그대로 사용 마무리하며 보조기층에 많이 사용한다. | | | | | | +| ㉡ 입도조정공법 : 2종 이상의 재료를 혼합하여 입도를 조정 사용하며, 노상혼합방식과 중앙혼 | | | | | | +| 합방식이있다. | | | | | | +| ㉢ 시멘트 안정처리공법 : 현지재료 또는 여기에 보충재를 가한 것에 시멘트를 첨가하는 공법 | | | | | | +| 으로서 강도를 높이며 함수 량의 변화를 막고 내구성을 높일 수 있다. | | | | | | +| ㉣ 가열아스팔트 안정처리공법 : 현지재료 또는 여기에 보충재를 가한 것에 아스팔트로 가열처 | | | | | | +| 리하는 공법으로서 중 교통 도로의 기층에 많이 이용하며, 시공성, 내구성이우수하다. | | | | | | +| ㉤ 상온아스팔트 안정처리공법 : 현지재료 또는 여기에 보충재를 가한 것에 유화아스팔트나 커 | | | | | | +| 트백 아스팔트와 같이 점성이 낮은 역청재료를 첨가 혼합하는 공법으로서 경교통도로의 기 | | | | | | +| 층에주로사용한다. | | | | | | +| ㉥ 마카담공법 : 한 층 마무리 두께와 거의 같은 단일 입경이 주골재(쇄석)를 포설하고 전압한 | | | | | | +| 후 그 위에 채움 골 재를 살포하여 주 골재의 간극에 전압, 역입시켜마무리하는공법. | | | | | | +| ㉦ 침투식공법 : 포설한 골재에 역청재료를 살포 침투시켜 골재의 맞물림(Interlocking)과 역청 | | | | | | +| 재의 접착성과 점성에 의하여 골재의 이동이 방지되는 안정된 층을 이루는 공법 | | | | | | + +##### 라) 표층 +- ① 표층은 교통하중이나 기상작용의 영향을 가장 많이 받는 부분으로 좋은 입도의 조·세골재 및 필러의 아스팔트를 첨가한 가연 아스팔트 혼합물을 충분히 다져서 사용한다. +- ② 가연혼합물의 포설은 균일하게 하고 고온인 동안에 전압하여야만 소정의 밀도와 안정도가 얻어진다. +- ○ 아스팔트혼합 +- ① 재료의 가열, 계량, 혼합의 각 작업이 연속적으로 이루어지는 아스팔트 프랜트(AsphaltPlant)에서 제조 - 덤프트럭으로 현장에 운반 - 아스팔트 피니셔(Asphalt Finisher)로 부설 +- - 롤러(roller)로 전압 시공. +- ② 혼합시간은 골재가 아스팔트에 의해 균일하게 피복되는데 소요되는 최소시간(약 45∼60 +##### 초) 이 좋고 혼합온도는 160∼170℃가 좋다. +- ○ 포설 및 다짐 +- ① 혼합물을 포설하는 노면이나 기층면에는 프라임 고팅(Prime Coating)나 택고팅(TackCoating)를 실행한다. ㉠ 프라임 코트 : 커트백 아스팔트(MC-0, MC-1, MC-2)나 아스팔트 유제{RS(C)-3} 등의 프라이머(primer)를 1∼2ℓ/㎡살포한다. 목적은 •입상재료층면에 침수시켜 표면을 안정시킨다. •보조기층 또는 기층의 방수성을 높인다. (수분의 모착상승 차단)•윗층에 포설하는 아스팔트층과의 부착성을 좋게한다. ㉡ 택코트 : 프라임코트를 한 후 교통을 허용하여 표면이 더렵혀지면 기층의 표면에 아스팔트 유제를 0.4∼0.8ℓ/㎡살포하고 그 위의 혼합물층과 접착을 잘 시킨다. +- ② 아스팔트 피니셔로 부설된 혼합물은 110∼140℃로 소정의 밀도(95% 이상)가 되도록 롤러(머캐덤롤러, 탠덤롤러, 타이어롤러 및 진동롤러 등)에 의하여 전압한다. +#### 4) 시멘트 콘크리트 포장 +##### 가) 포장 종류 +- ① 보통콘크리트 포장(무근콘크리트 포장, 줄눈을 둔 콘크리트 포장) : 철근의 보강없이 줄 눈을 배치하여 균열을 허용치 않는 포장, 균열의 발생과 그 확산을 방지하기 위하여 철망(Wire Mesh)을 삽입하는 경우도 이에 속한다. +- ② 철근콘크리트 포장 : 콘크리트 슬래브 단면의 상하를 복철근으로 배치 보강하여 줄눈을 두며 균열발생을 허용하는 포장 - 교대배면, 횡단구조물 접속부, 절·성토 경계부위 등의부등침하로 포장슬래브 자체에 하중집중현상이 일어날 수 있는 곳에 시공하는 방법이다. +- ③ 연속철근 콘크리트 포장 : 보통 콘크리트 포장의 줄눈부는 포장손상의 주원인이 되 고 특히 횡방향 줄눈은 슬래브의 불연속성을 초래하여 주행성에 나쁜 영향을 미친다. 이와 같이 줄눈의 취약점을 근본적으로 개선하기 위하여 콘크리트 슬래브의 단면적의 0.6∼0.8%정도의 철근으로 보강하여 줄눈의 설치없이 미세균열의 발생을 허용하는 포장으로서 줄 눈이 없는 구조이므로 주행감이 크게 개선되고 유지관리비가 거의 소요되지 않는다. +- ④ 프리스트레스트(Pre-stresed) 콘크리트 포장 : 슬래브내에 강선을 배치하여 프리스트레스를 도입하고 줄눈을 두며 균열발생을 허용하는 포장방법이다. +##### 나) 포장 시공 +- ○ 노상조건 +- ① 강성포장에서는 아스팔트 포장의경우보다 상재하중은 매우 넓은 면적에 확산분포되므로 노상의 강도는 매우 적게된다. +- ② 따라서 강성포장의 노상은 큰 지지력은 필요없으나 지지도의 변화가 없이 균등하여야 하는 것이 중요하다. +- ③ 노상의 부분적인 약화를 방지하기 위하여 지하배수를 철저히 하여 노상 마무리면에서 60 ㎝깊이까지는 수위의 상승을 막아야 한다. +- ○ 보조기층 +- ① 슬라브의 지면으로서의 균등성, 안정성, 지지력을 가진 평탄한 접촉면(Interface)을 제공한다. +- ② 노상의 지지력을 증대시키고 포장의 구조적 강성을 증대시킨다. +- ③ 노상이나 차단층의 손상을 방지한다. +- ④ 동상의 영향을 극소화한다. +- ⑤ 줄눈, 균열, 슬래브 단부에서 펌핑현상을 방지한다. +- ⑥ 균열발생과 슬래브 단층의 방지역활을 한다. ※ 펌핑(pumping)현상 : 연약화한 보조기층이 슬래브의 상하 움직임에 따라 작은 공동을 발생시켜 그 부위에 실트질이나 점토분이 모여 줄눈부에 차륜이 재하될 때 물과 함께 뻘이슬래브틈으로 솟아오르는 것. +- ○ 보조기층의 두께 +- 지지력계수에 의한 설계에서는 보조기층의 지지력계수 $k_{30}=20$kg/㎠가 되게 하는 것이 좋다. 그렇지 못할 경우 보조기층 두께는 $k_1/k_2$에 따라 정한다. + +$$\text{지지력계수}=\text{지지력계수 평균값}-\frac{\text{최대치}-\text{최소치}}{C}$$ + +| 개소수 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 이상 | | +|---|---|---|---|---|---|---|---|---|---| +| C | 1.91 | 2.24 | 2.48 | 2.67 | 2.84 | 2.96 | 3.08 | 3.18 | | +| ※ 개소수는 동일한 재료의 노상시공구간에서 절토구간 3개소, 성토구간 3개소 이상 실측치. | | | | | | | | | | + +(예제) 노상의 지지력계수를 6개소에서 6.5, 6.0, 5.6, 4.7, 4.5, 4.4로 측정하였다. + +- ① 노상의 지지력계수: $5.3-(6.5-4.4)/2.67=4.5$kg/㎠ +- 보조기층의 지지력계수비: $20/4.5=4.4$. 그림 5-2-84의 A선에 따르면 보조기층 두께는 55cm이다. +- ② 상층 15cm를 시멘트 안정처리할 경우 B선에서 $k_1/k_2=2.5$이므로 지지력계수는 $20/2.5=8$kg/㎠이다. 하층의 지지력계수비는 $8/4.5=1.8$이고, C선에서 입상재료 약 18cm가 필요하다. 따라서 입상재료 18cm와 시멘트 안정처리재료 15cm를 합한 33cm가 필요하다. + +- CBR에 의한 보조기층 두께 설계: + +$$\text{설계 CBR}=\text{CBR 평균}-\frac{\text{CBR 최대치}-\text{CBR 최소치}}{d}$$ + +표 5-2-46. 노상토의 설계 CBR과 보조기층 두께의 관계(도로포장설계·시공지침) + +| 노상토의 설계 CBR | 2 | 2.5 | 3 | 4 | 5 | 10 이상 | +|---|---:|---:|---:|---:|---:|---:| +| 입상재료만 사용하는 경우(cm) | 60 | 50 | 40 | 35 | 25 | 20 | +| 시멘트 안정처리의 경우(cm) | 20(30) | 20(20) | 20(15) | 15(10) | 15 | 15 | + +주) 설계 CBR이 4 이하인 경우 시멘트 안정처리는 입상재료와 병용하며, 입상재료 두께는 괄호 안의 수치를 취한다. 설계 CBR이 2 미만이면 연약한 노상토로 취급하여 특별히 설계한다. + +표 5-2-47. 설계 CBR 계산용 계수 $d$ + +| 개소수($n$) | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 이상 | +|---|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| $d$ | 1.41 | 1.91 | 2.24 | 2.48 | 2.67 | 2.84 | 2.96 | 3.08 | 3.18 | + +![시공_그림5-2-84_보조기층두께설계곡선](<../pic/시공_그림5-2-84_보조기층두께설계곡선.png>) + +- ○ 포장슬라브의 두께 두께는 교통하중의 양과 크기, 보조기층의 성질, 기상조건, 재료 및 시공법 등에 따라 다르다. 표 5-2-48. 콘크리트판의 두께 + +| 교통량의 구분 | 대형교통량(대/일, 1방향) | 콘크리트판 두께(㎝) | +|---|---|---| +| L 교통 | 100미만 | 15(20) | +| A 교통 | 100이하 250미만 | 20(25) | +| B 교통 | 250이상 1,000미만 | 25 | +| C 교통 | 1,000이상 3,000미만 | 28 | +| D 교통 | 3,000이상 | 30 | +| 주) ( )안은 L, A교통으로, 휨강도를 40㎏/㎠로 한 경우이다. | | | + +- ○ 줄눈 콘크리트판에는 팽창, 수축, 굽힘 등을 어느 정도 허용하고 온도, 습도 등에 따른 응력을 줄일 + +수 있도록 줄눈(Joint)을 설치한다. 줄눈은 그 위치, 기능, 구조에 따라 (표 5-2-49)와 같이 분류하고, 그 모형은 (그림 5-2-85)와 같다. 가로팽창줄눈 + +![시공_그림5-2-85_콘크리트포장줄눈](<../pic/시공_그림5-2-85_콘크리트포장줄눈.png>) + +그림 5-2-85. 콘크리트 포장의 줄눈 + +- - 세로줄눈 +- ① 주로 휘어짐응력(Warping Stress)을 감소시켜서 종방향의 균열발생을 방지하기 위하여 설치한다. +- ② 4.5m를 넘지 않는 것이 좋고, 맹줄눈이나 맞댄줄눈의 구조로서 타이바(Tie Bar)로 보강한다. ※ 타이바 : 줄눈을 가로질러 콘크리트판에 삽입하는 이형봉강으로 줄눈이 벌어지거나 단층이 생기지 않도록 한다. 직경 16㎜, 길이 800㎜, 간격 750㎜로 사용한다. +- ③ 폭은 6∼13㎜, 깊이는 단면의 1/3, 채움부의 최소길이는 10㎜이상을 원칙으로 한다. +- - 가로줄눈 • 가로팽창 줄눈 +- ① 교량접속부, 포장구조가 변하는 위치, 교차접속부에 설치하며, 콘크리트판 구조물에 대한 영향이나 온도상승에 의한 블로우업(blow up)을 방지하기 위함. ※ 블로우업 : 콘크리트의 팽창으로 인하여 팽창줄눈의 틈사이가 없어지고 콘크리트판이 좌굴을 일으켜서 부분적으로 떠오르는 현상. +- ② 주입줄눈재와 줄눈판을 상하에 병용하는 구조로 하고 주입줄눈재는 줄눈의 수밀성을 보존하기 위함이며 주입깊이는 20∼40㎜정도이다. +- ③ 다웰바(dewel bar)는 판의 두께에 따라 직경 25∼32㎜, 길이 500㎜의 것을 배치한다. 표 5-2-49. 콘크리트판 줄눈의 종류 + +| 장소에 의한 분류 | 움직임에 의한 분류 | 구조에 의한 분류 | +|---|---|---| +| 세로줄눈 (longitudinal joint) | 팽창줄눈(expansion joint) 휨줄눈(warp joint) | 팽창줄눈(expansion joint) 타이바를 사용한 맞댄 줄눈(butt joint) 타이바를 사용한 맹줄눈(dummy joint) | +| 가로줄눈 (transversal joint) | 팽창줄눈(expansion joint) 수축줄눈(contraction joint) 휨줄눈(warp joint) | 팽창줄눈(expansion joint) 스립바를 사용한 맹줄눈 스립바를 사용한 맞댄줄눈 타이바를 사용한 맞댄 줄눈 타이바를 사용한 맹줄눈 | +| 주) ㉠ 수축줄눈 : 수축줄눈 또는 맹줄눈은 수분, 온도, 마찰에 의해 발생하는 인장력을 완화시 | | | +| 켜 균열을 억제하기 위하여 설치한다. 수축줄눈이 없으면 포장표층에는 불규칙한 균열이 | | | +| 생긴다. | | | +| ㉡ 팽창줄눈 : 팽창줄눈의 주요기능은 포장이 팽창할 수 있는 공간을 설치함으로서 포장좌굴 | | | +| 의 원인이 될 수 있는 압축응력의 발생을 방지한다. | | | +| ㉢ 시공줄눈 : 시공줄눈은 시공성을 고려하여 설치하며 세로줄눈 사이의 간격은 포장장비의 | | | +| 폭과 포장두께에 따라 결정한다. | | | +| ㉣ 맹줄눈 : 콘크리트 상부에 깊이 6㎝정도의 홈을 만들어 줄눈재를 주입한 것으로서 콘크리 | | | +| 트판단면의 일부가 줄어짐으로서 판이 수축하려는 인장응력이 생겼을 때 균열이 이부분에 | | | +| 생기게 한 것이다. 맹줄눈이 있는 부분에 금이 생겼을 경우는 이것이 수축줄눈의 작용을 | | | +| 한 것이다. | | | +| ㉤ 맞댄줄눈 : 콘크리트판에 절단면을 만들어 이웃하는 콘크리트판을 마주 보게 한 구조로서 | | | +| 수축작용을 미리 막는다. | | | + +• 가로수축 줄눈 + +- ① 콘크리트판의 수축에 의하여 생기는 응력을 경감시키기 위하여 설치한다. +- ② 철망을 사용하지 않은 무근 콘크리트 포장에서 가로 수축줄눈 간격은 6m이하로 하되 다웰바를 삽입하는 것이 바람직하다. +- ③ 철근 또는 철망을 사용하는 콘크리트 포장에서 가로수축 줄눈의 간격은 발생된 균열폭이 넓게 발전되지 않도록 효과적으로 처리하기 위해서는 철근중량과 관련된다. 이 경우 가로수축 줄눈의 간격은 판두께가 25㎝미만인 경우 8m, 25㎝이상의 경우 10m를 표준으로 한다. +#### 5) 콘크리트 블록 포장 +- ① 콘크리트 블록포장(Concrete Block Pavement)은 적당한 재료로 적당한 모양과 크기로 공장에서 대량 생산하여 노면에 포설하는 포장방법이다. +- ② 판석이나 벽돌포장, 목괴포장이 옛날부터 사용되어 왔으나 현재에는 교면포장용으로 아스팔트 블록, 등판로에 소포석, 보도포장에 판석 등이 사용된다. +- ③ 최근에는 서로 맞물려서 교통하중을 분산시키는 포장구조로서 유효한 기능을 가지게 하는 인터록킹 블록(Interlocking Block)을 사용한다. +- ④ 포장의 단면은 (그림 5-2-86)과 같이 블록표층, 안정층(Cushion), 보조기층, 노상의 4단계층으로 구성하고 시공법은 노상 약 1m두께로서 CBR 25이상, 기층(Base Course) 두께는 15cm 정도, 블록과 블록 사이의 간격은 2∼3mm로서 줄눈은 모래로 채우고 횡단물매는 2∼3%로 하고 노측 가장자리에 연석을 설치하여 포장을 보호한다. + +![시공_그림5-2-86_블록설치방법](<../pic/시공_그림5-2-86_블록설치방법.png>) + +그림 5-2-86. 블록설치방법 + +- ⑤ 블록포장의 장점은 다음과 같다. ㉠ 블록은 정확한 규격과 강도에 견디는 재료로서 값싸게 생산이 가능하다. ㉡ 포설이 용이하고 간단한 장비만으로 가능하고 시공즉시 교통을 개방할 수 있다. ㉢ 지형이 불리한 곳(급경사지, 산악지도로)에도 포장이 가능하다. ㉣ 줄눈으로 인하여 표층의 균열이 없고 파손부위를 신속하고 간단하게 보수할 수 있으며 유지보수비가 저렴하다. ㉤ 침하가 큰곳에 대해서는 기존 강성포장 보다 적응성이 우수하고 미관이 수려하다. ㉥ 중차량의 가속, 회전, 정지 등에 의한 횡방향 전단(剪斷)에 높은 저항을 가진다. +#### 6) 자갈도 +- ① 표면에 자갈, 부순돌, 슬래그(Slag) 등에 적당량의 모래와 점토를 혼합한 결합재로 다짐하여 안정을 유도시키며 노면두께는 15∼25cm로 한다. +- ② 자갈도에 요구되는 조건은 다음과 같다. ㉠ 교통하중에 견딜 것 ㉡ 마모 및 凹凸발생에 저항이 클 것 ㉢ 먼지가 나지 않을 것 ㉣ 배수가 양호할 것 +- ③ 표층부의 자갈이 갖추어야 할 성질은 다음과 같다. ㉠ 교통하중으로 파쇄, 마멸되지 않을 것 ㉡ 풍화작용에 대한 저항력이 클 것 ㉢ 입도가 적당하여 공극을 극대화할 수 있는 배합이 될 것 +- ④ 시공법은 다음과 같다. (그림 5-2-87 참조)㉠ 표면공법(表面工法) : 표층저면을 수평으로 2∼3층 나누어 시공한다. ㉡ 상굴공법(箱掘工法) : 동일두께 단면으로 2∼3층 나누어 하층은 대립(12∼40mm), 상층은 소립(3∼12mm)의 자갈을 사용한다. + +![시공_그림5-2-87_자갈도시공법](<../pic/시공_그림5-2-87_자갈도시공법.png>) + +그림 5-2-87. 자갈도의 시공법 + +- ⑤ 노면의 저헝력이 약하므로 다음과 같이 수시 보수를 한다. ㉠ 노면의 평활성 유지(횡단물매 3∼5%)㉡ 바퀴자국의 되메우기 ㉢ 손실재료의 보충 +### 라. 구조물 공사 +- ① 임도의 구조물이란 흙이외의 재료(콘크리트, 강재, 석재 등)을 이용하여 노체 및 임도공간을 유지하기 위한 시설로서 교량, 터널, 옹벽, 배수공, 사면 등 주요 구조물과 임도부속물인 방호책, 낙석방지공 등이 있다. +- ② 구조물은 시설하는데 많은 비용이 소요되고 한 번 파손되면 교통에 많은 지장을 줌은 물론 다시 보수한다는 것은 쉬운 일이 아니므로 임도의 계획, 설계시에 그 필요성, 위치, 효과 등을 면밀히 조사 검토하여야 한다. +#### 1) 다리 +##### 가) 상부구조(Super Structure) +- ① 다리의 주체를 이루고 있는 부분으로서 다리를 통과하는 차량 등 통과물의 하중을 하부에 전달해지는 역할을 한다. +- ② 하중의 전달방법에 따라 항(桁), 트러스, 아아치, 라멘, 현수 Cable 등의 형태를 갖고 있고. +- ③ 바닥판, 바닥틀, 브레이싱 등으로 구성되어 있다. ㉠ 바닥판(Bridge Floor):교통하중을 직접받는 부분으로서 교면(橋面)과 그 밑의 슬라브로 되어 있다. ㉡ 바닥틀(Floor System):바닥을 지지하며 바닥에 가해지는 교통하중을 트러스에 전달하는 역할을 한다. 가로항(橫桁, 床桁)과 세로항(縱桁)으로 구성되어 있다. ㉢ 주트러스(Main Truss):상부 구조의 주체를 이루는 양쪽의 삼각형 형상으로 된 트러스로서 상부구조의 하중을 지점(支點)에 전달하는 역할을 한다. ㉣ 브레이싱(Bracing): 좌우의 트러스를 연결하여 수평하중에 대하여 저항하는 구조 부분이다. •수평 브레이싱(Lateral Bracing) : 횡하중을 지점에 전달하는 역할을 한다. 위치에 따라 상부, 하부 수평 브레이싱으로 나눈다. •수직 브레이싱(Sway Bracing) : 주 트러스의 마주보는 수직재를 연결하는 구조재로서 위치에 따라 중간수직 브레이싱, 단(橋端)수직 브레이싱이 있다. ㉤ 받침부(Bearing) : 상부와 하부를 연결하는 구조부분으로서 상부구조로 부터 모든 하중이 이곳을 통하여 하부로 전달된다. •가동받침(Movable Bearing) : 받침면을 따라 움직일 수 있는 받침으로서 받침면에 수직한 힘에만 저항할 수 있다. •힌지받침(Hinge Bearing) : 이동할 수는 없으나 회전이 가능한 받침으로서 받침을 통과하는 임의의 방향력에 저항할 수 있다. •고정받침(Fixed Bearing) : 이동이나 회전을 할 수 없는 받침으로서 임의의 방향에 대한 반력(反力)과 모우멘트에 저항할 수 있다. +##### 나) 하부구조(Under Structure) +- ① 일반적으로 교대와 교각의 조합으로 이루어져 있다. ㉠ 교대 : 교량양단에 설치되는 구조물로서 교대배면(橋臺背面)의 토압과 상부로 부터의 연직하중을 기초지반에 전달한다. ㉡ 교각 : 상부구조가 2경간(徑間)이상일 경우 교량양단의 교대사이에 있는 교항을 지지하기 위한 각주(脚柱)로서 상부로 부터 하중을 기초지반에 전달한다. + +![시공_그림5-2-88_교대와교각구조_01](<../pic/시공_그림5-2-88_교대와교각구조_01.png>) + +![시공_그림5-2-88_교대와교각구조_02](<../pic/시공_그림5-2-88_교대와교각구조_02.png>) + + +- ② 지상에 돌출되어 나와 있는 부분을 구체(軀體)라고 하고 지반에 접하는 부분을 기초(基礎)라고 한다. +- ③ 기초는 눈에 보이지 않지만 매우 중요한 구조재로서 지반의 성질에 따라 직접기초, 말뚝기초, 우물통기초로 구분된다. +- ○ 교대(Abutment) +- ① 교대의 구조는 (그림 5-2-88(a))와 같이 보를 지지하는슈(shoe)가 위치하는 교좌부(A),a-a선 상단에 토압이나 상재하중으로 부터 오는 압력을 지지하는 흉벽 또는 파라피트(B), 상부에서 전달되는 하중과 배면토압을 지지하는 몸체(C), 하중을 지반으로 전달하는 기초(D)로 이루어진다. +- ② 교대의 종류는 (그림 5-2-89)와 같으며 적정설치높이는 지반 지지력이나 응력에 따라 차이가 있다. + +![시공_그림5-2-89_교대의종류](<../pic/시공_그림5-2-89_교대의종류.png>) + +그림 5-2-89. 교대의 종류 + +- ③ 교대의 안정 ㉠ 연직력 •보, 트러스, 교상, 포장, 난간 등과 같은 상부구조의 중력에 의한 지점의 사하중 •활하중에 의한 지점의 최대하중 •충력하중 •교대의 자중 및 기초 위의 토사중량 ㉡ 수평력 •교대배면의 토사 및 상재하중에 의한 토압 •교량에 자동차가 통과할 때 다리축 방향에 작용하는 견인 및 제동력 •교량위에서 궤도가 곡선을 이룰 때 일어나는 원심력 •풍하중 ㉢ 안정검토 교대는 연직 및 수평하중을 받는 일종의 옹벽이므로 토압론에 의하여 토압을 계산하고 안정의 3조건 즉, 전도(Over Turning), 활동(Sliding), 침하(Settlement)에 대한 안정을 만족하도록 검토한다. +- ○ 교각(Pier) +- ① 교각은 (그림 5-2-88(b))와 같이 상부구조의 지점이 되는 슈(Shoe)를 앉히는 교좌부(A), 상부하중을 기초로 전달하는 몸체(B) 및 기초(C)로 구분된다. +- ② 교각의 종류는 (그림 5-2-90)과 같다. + +![시공_그림5-2-90_교각의종류_01](<../pic/시공_그림5-2-90_교각의종류_01.png>) + +![시공_그림5-2-90_교각의종류_02](<../pic/시공_그림5-2-90_교각의종류_02.png>) + +⒞ 구주식 ⒟ T형 ⒜ 중력식 ⒝ 벽식 + +![시공_그림5-2-90_교각의종류_03](<../pic/시공_그림5-2-90_교각의종류_03.png>) + +![시공_그림5-2-90_교각의종류_04](<../pic/시공_그림5-2-90_교각의종류_04.png>) + + +- ③ 교각의 안정 ㉠ 연직력 : 교각의 자중, 상부구조물의 중량, 통과할 하중 및 충격하중 등 ㉡ 수평력 : 활하중의 견인력, 풍압, 유수압, 지진력, 유수, 유목 및 선박 등에 의한 충격력 등 ㉢ 풍압, 유수압 ㉣ 안정검토 : 활동 또는 전도에 대한 안정, 재료의 파괴에 대한 안정, 유수의 집중에 의한 세굴에 대한 안정을 만족하도록 한다. +##### 다) 교량의 종류 +- ① 용도에 따라 - 도로교, 철도교, 인도교 +- ② 교면의 위치에 따라 - 상로교(Deck Bridge), 중로교(Half-Through Bridge), 하로교(Through Bridge), 2층교(2-Storied Bridge) +- ③ 구조형식에 따라 ㉠ 판구조 : 슬래브교(Slab Bridge)㉡ 보구조 : 판항교(Plate Girder Bridge), I항교, Box항교, 합성항교 등 + +| (a) 상로교 (b) 중로교 (c) 하로교 (d) 이층교 | (a) 하프형 사장교 | +|---|---| +| | (b) 방사형 사장교 | + +![시공_그림5-2-91_교량의종류_01](<../pic/시공_그림5-2-91_교량의종류_01.png>) + +![시공_그림5-2-91_교량의종류_02](<../pic/시공_그림5-2-91_교량의종류_02.png>) + +![시공_그림5-2-91_교량의종류_03](<../pic/시공_그림5-2-91_교량의종류_03.png>) + +㈀ 교면위치에 따른 교량 ㈁ 케이블형상에 따른 사장교 + +![시공_그림5-2-91_교량의종류_04](<../pic/시공_그림5-2-91_교량의종류_04.png>) + +![시공_그림5-2-91_교량의종류_05](<../pic/시공_그림5-2-91_교량의종류_05.png>) + +(a) 단순항교(a)(b)(b) 연속항교 ㈃ 랭거교(c) 게르바항교 ㈂ 지지조건에 따른 항교 ㈄ 로제교 + +| (a) | (a) 진정식 현수교 | +|---|---| +| (b) | (b) 자정식 현수교 | +| (c) | ㈆ 현수교 | +| | (a) | +| | (b) | +| | ⒪ 타이드 아치교 | +| ㈅ 각종형식의 라멘교 | | + +![시공_그림5-2-91_교량의종류_06](<../pic/시공_그림5-2-91_교량의종류_06.png>) + +![시공_그림5-2-91_교량의종류_07](<../pic/시공_그림5-2-91_교량의종류_07.png>) + +![시공_그림5-2-91_교량의종류_08](<../pic/시공_그림5-2-91_교량의종류_08.png>) + +![시공_그림5-2-91_교량의종류_09](<../pic/시공_그림5-2-91_교량의종류_09.png>) + +그림 5-2-91. 교량의 종류 + +##### 라) 하중 +- ○ 하중의 종류 +- ① 주하중 : 사하중, 활하중, 충격, 프리스트레스, 콘크리트 크라프의 영향, 콘크리트 건조수축의 영향, 토압, 수압, 부력 또는 양압력 등 +- ② 부하중 : 풍하중, 온도변화의 영향, 지진의 영향 등 +- ③ 특수하중 : 설하중, 지반변동의 영향, 지점이동의 영향, 파압, 원심하중, 제동하중, 가설시하중, 충돌하중, 기타 +- ○ 사하중(死荷重) 교량의 자중 및 교량에 부과되는 물체들의 중량 표 5-2-50. 재료의 단위중량(㎏/㎥) + +| 재 료 | 단 위 중 량 | 재 료 | 단 위 중 량 | +|---|---|---|---| +| 강재, 주강, 단강 주철 알미늄 철근콘크리트 프리스트레스트 콘크리트 | 7,850 7,250 2,800 2,500 2,500 | 콘크리트 시멘트 모르터 목재 역청재(방수용) 아스팔트 포장 | 2,350 2,150 800 1,100 2,300 | + +- ○ 활하중(活荷重)차량, 군중 등 교량위를 이동하는 하중으로서 자동차 하중은 표준트럭하중(DB하중)과 차선하 + +중(DL하중)으로 구분된다. 표 5-2-51. DB 하중 + +| 교량등급 | 하 중 W(t) | 총중량 1.8W(t) | 전륜하중 0.1W(kg) | 후륜하중 0.4W(kg) | +|---|---|---|---|---| +| 1등교 | DB-24 | 43.2 | 2,400 | 9,600 | +| 2등교 | DB-18 | 32.4 | 1,800 | 7,200 | +| 3등교 | DB-13.5 | 24.3 | 1,350 | 5,400 | +| 주) 1등교 : 고속도로, 국도 | | | | | +| 2등교 : 국도일부, 지방도, 특별시도 | | | | | +| 3등교 : 군도, 비법정도이나 근래는 거의 2등교 수준이상으로 설계 | | | | | + +- - 보도하중 +- ① 바닥판과 바닥틀 설계시 : 500㎏/㎥ +- ② 주항설계시는 (표 5-2-52)와 같다. 표 5-2-52. 보도 등에 재하하는 등분포 하중 + +| 지 간 장 L(m) | L≤80 | 80≤L≤130 | L>130 | +|---|---|---|---| +| 하 중(㎏/㎡) | 350 | 430-L | 300 | + +- - 충격하중: 교면의 요철, 차량의 가속과 감속, 전후차량들의 협동작용 등의 이유로 정하중(靜荷重)보다 큰 동적영향을 교량에 미치는데 이를 충격하중이라고 하고 활하중에 충격계수를 곱하여 구한다. + +$$ +I=\frac{15}{40+L}\leq0.3 +$$ + +단, $L$은 활하중이 재하된 지간(支間) 부분의 길이(m)이다. +#### 2) 옹벽 +##### 가) 옹벽의 종류 + +옹벽(retaining wall)은 절토·성토를 사면의 기울기가 흙의 안식각보다 클 경우에 토압에 저항하여 흙의 붕괴를 방지하기 위하여 시설하는 구조물로서 형상이나 역학적 특성에 따라 (그림5-2-92)와 같이 구분한다. + +![시공_그림5-2-92_옹벽의종류](<../pic/시공_그림5-2-92_옹벽의종류.png>) + +그림 5-2-92. 옹벽의 종류 + +##### 나) 옹벽의 적용기준과 경제성 + +표 5-2-53. 옹벽 선택의 일반적인 기준 + +| 종 류 | 형 상 | 옹벽높이 | 특 징 | 채용상의유의점 | 경제성 | +|---|---|---|---|---|---| +| 블록쌓기 (돌쌓기) 옹 벽 | | •공적: 3m 이하 •찰쌓기뒤채움 콘크리트없음 : 5m 이하 뒷채움콘크리트 있음 : 7m 이하 | •경사면 기울기, 경사길이 및 평면선형 등을 자유로이 변화 시킬수있음 | •사면의보호 •토압이 작은 경우(내면의 원지반이 단 단한 경우나 배면토가 양 호한 경우 등) | •다른형식에 비교하여 경 제적임 | +| 중력식옹벽 | | •5m 이하 | •콘크리트 옹벽 가운데에는 시 공이 가장 용 이함 | • 기초지반이 좋은 경우 (저면반력이 크다) • 말뚝기초가 되는 경우는 부적당 | •높이가 낮은 경우는 경제 적임 •높이가 4m이 상의 경우는 비경제적임 | +| 반중력식 옹 벽 | | •10m이하가 많 음 •15m까지 이용 되는 예는 많 다. | •산악임도의 확 폭등에유리 •자립되지 않으 므로 시공상 주의를요함 | • 기초지반이 견고한장소 | •비교적 경제 적임 | +| 켄티레버식 옹 벽 (역T형,L 형) | | •3m∼10m | •뒤꿈치판상의 흙중량을 옹벽 의 안정에 이 용함 | •보통기초지반 이상이 바람직 함 •기초지반이좋지 않은경우에이 용되는예는있 음(저면반력은 비교적적다) | •비교적경제적 임 | +| 버팀벽식 옹 벽 (부벽식) | | •6m이상 | •구체의 콘크리 트량은 켄티레 버식 옹벽에 비하여 적을 수도 있으나 시공에 난점이 있음 | • 기초지반이 좋지 않은 경 우에 이용되 는 예는 있음 (저면반력은 비교적 적음 다) | •높이,기초의 조건에 따라 경제성이 좌 우됨 | +| 기타의옹벽 (특수옹벽) | 지형조건, 지반조건, 환경 조건 및 각종의 제약 조건 등에 따라 적당히 채용됨 | | | | | + +![시공_옹벽하중도_01](<../pic/시공_옹벽하중도_01.png>) + +![시공_옹벽하중도_02](<../pic/시공_옹벽하중도_02.png>) + +![시공_옹벽하중도_03](<../pic/시공_옹벽하중도_03.png>) + +![시공_옹벽하중도_04](<../pic/시공_옹벽하중도_04.png>) + +![시공_옹벽하중도_05](<../pic/시공_옹벽하중도_05.png>) + +##### 다) 하중 + +옹벽에 작용하는 하중은 자중, 상재하중, 토압, 수압, 부력, 설하중, 지진하중 등이 있다. +- ① 상시 : 사하중 + 활하중(상재하중) + 토압 +- ② 지진시 : 사하중 + 지진시토압 + 지진력 +##### 라) 옹벽의 안정 + +옹벽외력에 대하여 안정하기 위하여 안정의 3조건 즉, 전도 및 활동을 하지 말아야 하고, 침하를 일으키지 않아야 한다. 이들 안정은 실하중(Service Load)에 의하여 검사한다. + +#### 3) 배수시설 +- ① 임도는 일반적으로 표고가 높은 산간부에 설치되고 있으므로 습도가 높고 온도가 낮음은 물론 강우량도 많고 강우빈도가 높은 것이 보통이다. 일조시간에 제약을 받기 때문에 습윤하여 시공상 부적당한 토질로 되어 있는 경우도 많으며, 특히 북사면은 이와 같은 영향이 현저하다. +- ② 이와 같은 좋지 않은 조건에서는 대개 물에 의하여 영향을 받을 우려가 많으므로 시공중에는 물론이고 시공후에도 배수에 충분히 유의하는 것이 필요하다. +- ③ 따라서 배수는 임도의 수명과 기능을 유지하기 위한 중요한 인자이기 때문에 설계나 시공 시에 지형, 토질, 기상, 지하수의 상황 등을 충분히 검토하여 그 위치, 형식, 수량을 적정하게 결정하여야 한다. +- ④ 임도의 배수는 (그림 5-2-93)과 같이 대상구역에 따라 표면배수, 지하배수, 임도용지 외의배수로 구분할 수 있다. +##### 가) 표면배수시설 +- ① 노면배수시설 : 길어깨 배수시설, 중앙분리대 배수시설 +- ② 사면배수시설 : 사면끝 배수시설, 도수로 배수시설(세로 배수시설), 소단 배수시설(가로 배수시설) +##### 나) 지하배수시설 +- ① 땅깍기 구간의 지하 배수시설 : 가로지하 배수구(맹암거 등), 세로지하 배수구(횡단배수구) +- ② 흙쌓기 구간의 지하 배수시설 +- ③ 절·성 경계부의 지하 배수시설 +##### 다) 임도 인접지 배수시설 +- ① 사면어깨(산마루) 배수시설 : 산마루 측구, 감쇄공(energy dissipater) 등의 배수시설 +- ② 배수구 및 배수관 : 집수정, 배수구, 배수관 및 맨홀 등의 배수시설 + +![시공_그림5-2-93_임도배수의종류](<../pic/시공_그림5-2-93_임도배수의종류.png>) + +그림 5-2-93. 임도배수의 종류 + +##### 라) 강우유출량 추정 + +배수 구조물의 단면을 결정하기 위한 유출량(설계유량, 계획홍수량)을 결정하는 방법에는 합리식, 표면유출법, 수문곡선 추적법 등이 있다. + +합리식(Lauterburg 식)은 다음과 같다. + +$$Q=\frac{1}{3.6}rfA$$ + +- $Q$: 유출량(㎥/sec) +- $r$: 도달시간 강우강도(㎜/hr, 최근 30년간 최대 시우량) +- $f$: 유출계수(표 5-2-54 참조) +- $A$: 집수면적(㎢) + +표 5-2-54. 유출계수($f$) + +| 표면상태와 지역상태 | 유출계수(f) | 지역의 상태 | 유출계수(f) | +|---|---|---|---| +| 아 스 팔 트 포 장 콘 크 리 트 포 장 자 갈 도 공 원 잔 디 수 림 도 심 지 구 주 택 지 역 공 장 지 역 운동장, 공원, 공지 | 0.92∼0.98 0.85∼0.95 0.30∼0.40 0.30∼0.40 0.40 0.90∼0.95 0.70∼0.80 0.60∼0.75 0.40∼0.60 | 급 한 산 지 3 기 층 의 산 악 기복있는 토지 및 수림 평 탄 한 경 지 관 개 의 답 산 지 의 계 천 평 지 의 계 천 임 목 이 많 은 곳 임 목 이 적 은 곳 독 나 지 | 0.75∼0.90 0.70∼0.80 0.50∼0.60 0.45∼0.60 0.70∼0.80 0.75∼0.85 0.45∼0.75 0.35∼0.45 0.45∼0.55 0.55∼0.60 | + +표 5-2-55. 집수유역 크기별 최대유출량 + +| 집수면적 ha | 유출량(Q) ㎥/sec | 최대유출량(Q) 1 ㎥/sec | 비고 | +|---|---|---|---| +| 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 10.0 20.0 30.0 40.0 50.0 | 0.048 0.097 0.146 0.194 0.234 0.292 0.340 0.389 0.437 0.486 0.972 1.944 2.916 3.888 4.861 | 0.058 0.110 0.175 0.233 0.292 0.349 0.408 0.467 0.524 0.583 1.167 2.333 3.499 4.667 5.833 | Lauterburg식(이용) a = 유출계수(0.5) A : 면적(㎡) h : 최대시우량(70㎜/hr) | + +##### 마) 배수시설의 설계 +- ① 측구 및 배수시설의 배수유량은 Manning 식으로 계산한다. + +$$Q=AV,\qquad V=\frac{1}{n}R^{2/3}I^{1/2}$$ + +- $Q$: 배수유량(㎥/sec) +- $n$: 조도계수(표 5-2-56 참조) +- $A$: 측구단면적(㎡) +- $R$: 경심 또는 동수반경(m) +- $V$: 평균유속(m/sec) +- $I$: 측구의 물매 +- ② 조도계수는 (표 5-2-56)과 같고 막파기 측구에서는 유수로 인한 세굴이 없으야 하므로(표 5-2-57) 이하로 유속을 제한하여야 한다. 표면이 평활한 측구 또는 수로일지라도 유속은 4m/sec를 넘지 않아야 한다. 표 5-2-56. 조도계수 n의 값 + +| 배수로표면의 재료 | n의 값 | 배수로표면의 재료 | n의 값 | +|---|---|---|---| +| 보 통 흙 | 0.02 | 굵 은 돌 찰 쌓 기 | 0.025 | +| 떼로 덮힌 흙(수심15cm이하) | 0.04 | 아 스 팔 트 콘 크 리 트 | 0.02 | +| 떼로 덮힌 흙(수심15cm이상) | 0.06 | 거 친 콘 크 리 트 | 0.02 | +| 밀 생 한 풀 로 덮 힌 흙 | 0.1 | 매 끈 한 콘 크 리 트 | 0.015 | +| 다 져 진 역 질 토 | 0.04 | 흄 관 | 0.012 | +| 굵 은 돌 메 쌓 기 | 0.03 | 콜 게 이 트 파 이 프 | 0.02 | + +표 5-2-57. 세굴을 막기 위한 최대한도의 유속 + +| 표 면 상 태 | 허용할 수 있는 최대유속(m/sec) | +|---|---| +| 노출된 흙 점토를 품지 않은 가는 모래 또는 실트 단단한 로움 단단한 점토 잔돌 섞인 점토 거친 잔돌 연한 혈암 단단한 가지로 덮힌 흙 풀 사이에 흙이 노출하고 있을 때 목초처럼 약한 잎을 가진 풀로 덮힌 흙 양질토가 떼로 덮혀 있을 때 | 0.5 0.8 1.2 1.2 1.2 1.5 0.8 1.5 1.5 2.0 | + +(예제) 그림 5-2-94와 같은 막파기 사다리꼴형 측구의 배수가능 유량과 안전도를 검토한다. $n=0.02$, $I=4\%$, 산악지 집수면적 10.0ha, 강우강도 40mm/hr, 배수관 간격 200m, 자갈도 전 노폭은 5m이다. + +단면적과 윤변장은 다음과 같다. + +$$A=\frac{1.7+0.5}{2}\times0.3=0.33\,\mathrm{m^2}$$ + +$$P=0.5+2\sqrt{0.6^2+0.3^2}=1.84\,\mathrm{m},\qquad R=\frac{A}{P}=0.179\,\mathrm{m}$$ + +Manning 공식으로 구한 평균유속과 배수가능 유량은 다음과 같다. + +$$V=\frac{1}{n}R^{2/3}I^{1/2}=50\times0.3176\times0.20=3.176\,\mathrm{m/sec}$$ + +$$Q=AV=0.33\times3.176=1.05\,\mathrm{m^3/sec}$$ + +자갈도 유출계수 0.35, 산악지 유출계수 0.825, 노면 집수면적 0.005km², 산악지 집수면적 0.10km²를 적용하면 예상 유출량은 다음과 같다. + +$$Q=\frac{1}{3.6}\times40\times(0.005\times0.35+0.10\times0.825)=0.936\,\mathrm{m^3/sec}$$ + +안전율 25%를 적용한 필요 유량은 $0.936\times1.25=1.17$ m³/sec이다. 따라서 $1.05<1.17$ m³/sec이므로 이 측구 단면은 유출량을 감당하기 어렵다. + +표 5-2-58. Manning 공식을 이용한 흄·토관 크기별 유량 + +| 토 관 크 기 | 유 량 | +|---|---| +| 직경 30㎝ ($r=15$㎝) | $Q=0.278$㎥/sec | +| 직경 40㎝ ($r=20$㎝) | $Q=0.599$㎥/sec | +| 직경 50㎝ ($r=25$㎝) | $Q=1.087$㎥/sec | +| 직경 60㎝ ($r=30$㎝) | $Q=1.766$㎥/sec | +| 직경 70㎝ ($r=35$㎝) | $Q=2.667$㎥/sec | +| 직경 80㎝ ($r=40$㎝) | $Q=3.806$㎥/sec | +| 직경 90㎝ ($r=45$㎝) | $Q=5.207$㎥/sec | +| 직경 100㎝ ($r=50$㎝) | $Q=6.899$㎥/sec | + +표 5-2-59. 집수면적 매설물매에 대한 관경 + +| 매설물매 집수면적ha | 콘크리트관경(단위 ㎝) | | | | +|---|---|---|---|---| +| | 5%이상 10%미만 | 10%이상 15%미만 | 15%이상 20%미만 | 20% 이상 | +| 0.6 미만 0.6∼0.8 0.8∼1.0 1.0∼2.0 2.0∼3.0 3.0∼4.0 4.0∼5.0 5.0∼6.0 6.0∼7.0 7.0∼8.0 8.0∼11.0 11.0∼14.0 14.0∼16.0 16.0∼18.0 18.0∼20.0 20.0∼25.0 25.0 이상 | 30 40 40 50 60 80 80 80 80 80 100 100 | 30 30 40 50 50 60 60 80 80 80 80 100 100 100 100 | 30 30 30 40 50 50 60 60 80 80 80 80 100 100 100 100 | 30 30 30 40 50 50 60 60 60 80 80 80 80 100 100 100 | + +##### 바) 표면배수 +- ① 측구측구(Roadside Drain ; Side Ditch)는 노면과 인접된 사면의 물을 배수하기 위하여 임도의 종 + +단방향에 따라 설치하는 배수구로서, 측구의 형상과 구조는 배수량, 경제성, 교통에 대한 안정성 등에 따라 정한다. + +![시공_그림5-2-94_막파기측구](<../pic/시공_그림5-2-94_막파기측구.png>) + + +- ○ 막파기 측구 : +- - (그림 5-2-94)와 같이 V형과 사다리꼴형이 있고, 비탈면에 설치할 경우에는 비탈기슭에 폭 50cm 정도의 소단을 설치하여 비탈의 토사유입을 막는다. +- - V형은 그레이더로 성형하고 유지관리에 편리하며, 사다리꼴형은 배수량이 큰 이점이 있다. +- - 폭과 깊이는 배수량과 관계가 깊으므로 단면의 10∼20% 정도는 토사의 퇴적을 예상하여 미리 여유있게 설계한다. +- - 종단구배가 급한 곳, 모래, 실트와 같이 침식의 우려가 있는 곳에서는 사용하지 않는 것이 좋다. +- ○ 붙임측구 +- - (그림 5-2-95)와 같이 측구바닥의 세굴을 방지하기 위하여 떼, 조약돌 등을 편평한 곡면으로 붙이거나, 바닥과 측면 또는 측면을 돌쌓기, 블록쌓기로 V형이나 사다리꼴형으로 설치한다. + +![시공_그림5-2-95_붙임측구](<../pic/시공_그림5-2-95_붙임측구.png>) + + +- - 떼, 조약돌을 이용한 편평한 곡면은 배수량이 그다지 많지 않은 곳에 설치하고, 돌쌓기 블록쌓기의 사다리꼴형은 배수량이 많은 곳 또는 종단구배가 약간 급한 곳에 설치한다. +- ○ 콘크리트 측구 +- - (그림 5-2-96)과 같이 L형과 U형의 무근 또는 철근 콘크리트제로서 프리케스트(Precast)형과 현장타설형이 있다. +- - 프리케스트 제품은 (그림 5-2-96)의 우측표와 같이 U형(KS 4016, 4017), L형(KSF 4005)으로서 한국공업규격으로 시판되고 있다. +- - L형은 하중으로 손상되기 쉬우므로 측구 밑을 충분히 다지거나 필요에 따라서는 콘크리트기초공을 하여야 하고, U형 측구는 측압에 대한 저항성이 적으므로 측압이 있는 곳에서는 사용에 주의를 하여야 한다. + +![시공_그림5-2-96_콘크리트측구](<../pic/시공_그림5-2-96_콘크리트측구.png>) + +그림 5-2-96. 콘크리트 측구(단위: mm) + +- ○ 횡단배수구 +- - 암거 +- ① 노면에서 상당한 깊이에 설치하는 것으로 +- ② 종류 : 석재, 콘크리트관, 흄관, 코루게이트(Corrugate)관, T. H. P관, BOX 등이 있다. +- - 개거 +- ① 노면에 드러나 있는 배수구 +- ② 종류 : 석재, 콘크리트, 목재 등이 이용되고 있다. +- ③ 개거의 기능은 경사진 임도에서 우수가 노면수 형태로서 노면을 따라 계속 흐르면 심한 노면침식이 발생할 우려가 있으므로 이를 예방하기 위하여 노면수의 유하거리를 차단하여 노면외부로 유출시키기 위함이다. +- ④ 가장 간단한 개거의 설치방법은 말구가 약 10cm 내외의 중경목 통나무 2개를 꺽쇠와 말뚝으로서 고정시키며, 이 통나무 사이의 폭은 통나무 하나 크기 정도로 한다. 이때 이 사이에 들어가는 통나무는 임도가 이용되지 아니할 경우에는 제거하여 임도 노견 위에 두도록 한다. 최근에는 조립식이나 규격화된 횡단구가 일반화되고 있다. +- ⑤ 개거를 설치할 경우에는 임도를 통행하는 차량이 안전하고 통행차량에 의하여 파손되지 않음은 물론 유수를 안전한 곳으로 배수할 수 있어야 한다. + +![시공_그림5-2-97_횡단배수구와측구배치](<../pic/시공_그림5-2-97_횡단배수구와측구배치.png>) + + +![시공_그림5-2-98_암거의모형](<../pic/시공_그림5-2-98_암거의모형.png>) + + +![시공_그림5-2-99_개거의종류와모형1](<../pic/시공_그림5-2-99_개거의종류와모형1.png>) + +그림 5-2-99. 개거의 종류와 모형(1) + +![시공_그림5-2-100_개거의종류와모형2](<../pic/시공_그림5-2-100_개거의종류와모형2.png>) + +그림 5-2-100. 개거의 종류와 모형(2) + +- ③ 세월공 도로를 횡단하여 설치하는 호상(弧狀)의 유로로서 가능한 한 호의 길이를 길게 하여 차량의 + +통행이 편리하게 하고, 또한 수로면은 돌붙임 콘크리트(찰붙임) 또는 콘크리트를 타설한다. 특히, 세월공은 다음과 같은 곳에 주로 설치한다. + +- ○ 선상지, 벼랑 등을 횡단할 때 +- ○ 황폐계류를 횡단할 때 +- ○ 관거 등에서 복토할 흙이 부족할 때 +- ○ 계상물매가 급하여 노면 상부로부터 유입하는 형태가 될 때 ○평시에는 유수가 없고 홍수시에만 물이 많이 흐르는 계곡 +- ④ 사면 배수 +- ○ 절취부와 성취부의 사면에 유하수에 의한 침식으로 사면이 붕괴되어 임도에 피해를 유발시키는데 이를 방지하기 위하여 비탈면 보호공과 함께 비탈면배수시설을 설치하여 사면 침식을 방지한다. +- ○ 비탈면의 배수에는 강수, 표면유수가 비탈면에 들어오지 못하도록 하는 것(산마루 측구)과 비탈면을 흐르는 물과 비탈면 속의 지하수를 안전하게 비탈면 밖에 있는 배수시설을 유도하기 위한 것(소단배수구, 종배수구, 맹거 등)이 있다. +- ○ 산마루 측구와 소단배수구는 유수량이 적고 물의 침투로 인하여 배수구의 측면파괴 우려가 있는 곳에서는 막파기를 하여도 좋지만 유량이 많을 때에는 소일시멘트(SoilCcement), 콘크리트 등으로 저면과 측면을 보호하는 것이 좋다. +- ○ 종배수구는 산마루의 측구, 소단배수구에서 차단된 우수를 비탈면에 피해를 주지 않도록 종단방향으로 설치되며 철근 콘크리트 U형, 반원흄관, 철근콘크리트관 등이 사용된다. +- ○ 맹거(盲渠)는 지표면에 가까운 지하 침투수를 집수하여 배수하기 위한 구조물로서 가운데는 조립(粗粒)재료, 바깥으로는 세립재료로서 토사의 유입을 막아 투수성이 좋도록 한다. +- ○ 맹암거(盲暗渠)는 용수량이 많은 곳이나 여러개의 맹거가 합류된 곳에 구멍 뚫린 관을 넣어 집수배수하는 구조물로서 배치형태는 W형과 화살형이 있다. +- ○ 맹거대용으로 돌망태, 포러스(Porus)콘크리트관, 합성수지, 네트(Net)관 등이 있으나 현지에 적합한 것을 선정한다. + +![시공_그림5-2-101_사면배수시설](<../pic/시공_그림5-2-101_사면배수시설.png>) + +그림 5-2-101. 사면배수시설 + +##### 사) 지하배수 +- ① 보조기층 및 노상의 지하배수 +- ○ 노상의 투수계수가 비교적 작고 인접지역으로 부터 침투수가 보조기층내로 유입할 우려가 있는 곳, 지하수가 보조기층까지 오를 우려가 있는 곳, 한랭지의 동상을 입을 우려가 있는 곳에 필요하다. +- ○ 보조기층의 배수가 불충분하면 보조기층, 노상의 지지력이 감소하고 한랭지에는 동상현상이 조장된다. 콘크리트 포장에서는 공동(空洞)이 생기고 분니현상(噴泥現象 : Pumping)이 일어나고, 역청포장에서는 재료의 분리가 촉진되어 표층파괴의 원인이 된다. +- ○ 보조기층 지하배수구는 측구 밑에 구멍뚫린 관(내경 20-30cm), 구멍 수 50개 이상(관둘레 면적 1㎡당)이 좋고, 맹거를 설치할 경우에는 상폭 30-60cm, 하폭 30cm로 굴착하고 입도가 큰 자갈이나 부순돌을 넣어 그 둘레는 모래로 채운다. +- ② 비탈면 용수의 지하배수 +- ○ 비탈면의 용수는 비탈면의 침식과 용수의 유출지층에 따라 활동붕괴의 우려가 있으며, 보통 절토부와 성토부의 경계는 용출수의 통로가 되어 지하수위가 높고, 또 외부로부터 침투수를 유도하여 용수량을 증가시킨다. +- ○ 지하배수(Subsurface Drainage)에는 비탈면돌망태, 맹거, 수평배수공, 수평배수층 등의 시설이 있다. 돌망태배수는 용수가 많은 비탈면에 (그림 5-2-102)와 같이 맹거와 공용하여 비탈면 침식과 비탈면 토사유출 및 붕괴방지에 사용하며 원형, 편평형, 이불형 등이 있다. +- ③ 옹벽뒷채움의 배수 +- ○ 옹벽뒷면에 물이 고이면 흙의 함수량이 증가하고 단위중량이 증가하여 내부 마찰각과 점착력이 감소하며, 점성토에서는 함수팽창을 일으키고 토압이 증대함은 물론 기초판 저면에서는 지반지지력이 저하된다. + +![시공_그림5-2-102_돌망태사용예](<../pic/시공_그림5-2-102_돌망태사용예.png>) + +그림 5-2-102. 돌망태의 사용(예) + +- ○ 이를 막기 위하여 옹벽뒷면에 호박돌 또는 깬 호박돌 등을 채워 배수층을 만들고 여기에 집수된 물을 비닐관 등으로 만든 수발공에 따라 옹벽전면으로 배수한다. +- ○ 수발공은 무근, 철근콘크리트 옹벽에서는 뒷면 뒷채움돌 하단에 약 5m 간격으로 지그재그(Zigzag)식으로 설치하고, 돌쌓기와 콘크리트 브록쌓기에서는 2∼3㎡에 1개소씩 설치한다. +- ○ 뒷채움 호박돌층 두께는 절토의 경우 상하부 모두 30∼40cm의 동일 두께로 하지만, 성토의 경우는 옹벽의 상부에서 20∼40cm로 하고 하부로 갈수록 두껍게 한다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 118~154쪽 (인쇄면 488~524쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/2. 임도/7. 유지보수.md b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/7. 유지보수.md new file mode 100644 index 00000000..e5e41920 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/2. 임도/7. 유지보수.md @@ -0,0 +1,39 @@ +# 7. 유지보수 + +### 가. 사리도 +- ① 사리도의 정상적인 노면을 유지하기 위하여 가장 중요한 부분은 배수다. 횡단구배 5∼6%정도로서 노면의 배수와 종단구배방향의 배수를 측구로 유도하여 노외로 배수하게 된다. +- ② 노면의 정지는 가능한한 비가 온 후 노면이 습윤한 상태에서 실시한 것이 좋다. +- ③ 방진처리는 물, 염화칼슘, 폐유, 타르, 아스팔트 유제 등이 사용된다. +- ④ 갓길이나 노측이 교통으로 인하여 노면 보다 높아 노면배수가 잘 되지 않을 경우에는 그 레이더로서 정형하고 로울러로 다지며 제초나 예불을 1년에 1번 이상 실시한다. +### 나. 사면 + +지형이 험준하고 강수량이 일시적 집중적이고 사면유지에 각별한 관심이 있어야 한다. +#### 1) 식생 사면 +- ① 나무가 너무 크게 되면 풍우에 넘어져서 비탈면 붕괴의 원인이 되기도 하고 가시거리에 지장을 주므로 교통의 장애가 될 수 있으므로 적당한 시기에 가지치기를 한다. +- ② 떼붙임을 한 사면의 유지는 떼를 잘 생육시키는데 있으므로 1년에 1∼2회 정도 예취하여 다른 식물의 생장을 막아 주어야 하지만, 파종공, 식생판공은 예취할 필요가 있으므로 유지에 간단하다. +- ③ 사면구배, 토질, 배수상황을 고려하고 강우량과 사면은 관계가 깊으므로 강우시 각별한 대책을 강구하고 사면으로 직접물이 흐르지 않도록 배수에 충분한 주의를 요한다. +#### 2) 뿜어 붙이기 사면 +- ① 토질, 용수의 유무, 뿜어 붙이기 두께, 보강철근의 유무 등에 의하여 결함부는 균열이 점점 확대되어 그 수명은 달라진다. +- ② 용수나 토질에 의한 결함부 - 뿜어 붙이기 비탈면 보수공은 적합치 않다. +- ③ 보강철강이 없는 결함부 - 그 부분을 제거한 후 보강철강을 넣고 앵커용 볼트로 본바닥에 고정시킨 후 재시공한다. +#### 3) 사면 구조물 + +구조물은 수시 점검하여 결함부의 원인을 제거하고 보강하거나 보수한다. +- ① 옹벽 : 전도, 활동, 침하, 균열 등에 의하여 파손되기 때문에 특히 주의할 것은 성토지반 옹벽기초부의 세굴이다. +- ② 돌쌓기, 돌붙이기 콘크리트 붙임공 : 균열 또는 침하로 파손되기 때문에 기초침하, 용수의 내압에 주의하고 줄눈의 콘크리트 두께가 얇아 초목이 붙어살면 조기제거하여 줄눈을 봉한다. +- ③ 돌메쌓기 : 바닥세굴, 기초부침하, 배면의 토압과 수압 증대, 용수, 돌사이의 초목 등이 원인으로서 균열을 발견하기 어려우므로 배불림에 주의한다. +- ④ 틀종류 : 용수가 있거나 토질이 연약한 사면에서 효과적이지만 본바닥이 약하기 때문에 배불림, 균열, 틀안에 메운 돌의 이탈 등을 주의한다. +### 다. 배수공 + +배수구는 항상 설계시의 유수단면적이 유지될 수 있도록 급한 종단구배로 인한 유토, 지조와 낙엽 등에 의하여 유수단면적이 적어질 우려가 있으므로 수시점검하여 보수한다. + +- ① 측구, 개거 : 노면배수를 유출하기 위하여 설계되었기 때문에 산지부 등의 표면수가 유입되지 않도록 한다. +- ② 관거, 암거 : 막힘으로 인하여 유수능력이 저하되어 물이 넘쳐 노면이나 성토사면에 재해를 일으키기 때문에 인력, 진공흡입기, 기계 등에 의하여 청소하거나 잘 막히는 곳은 개조한다. 종단관거는 수시로 퇴적물을 청소할 수 있도록 20∼30m 간격으로 물받이를 설치하며, 특히 개거 또는 측구와 연결되는 관거는 물받이를 설치하여 이어지도록 한다. +### 라. 노면관리 +- ① 제설(Snow Removed) : 적은 강설에는 체인 또는 스노우 타이어로서 자동차의 통행이 가능하지만 10cm 이상에서는 통행이 곤란하므로 제설판(Snow-Plough) 또는 그레이더(Grader)로 제설한다. ㉠ 밀어내기 제설 : 덤프트럭, 모터그레이더, 불도저, 휠트랙터 등에 제설판을 달거나, 불도 져, 그레이더의 토공판을 그대로 이용한다. ㉡ 뿜어내기 제설 : 전용기계나 자동화 또는 트랙터에 달아서 기계전면부분의 눈을 뿜어내기 장치(Blower)로 10∼40m 측면으로 날려보낸다. ㉢ 반출제설 : 트럭 등에 싣고 사설장(捨雪場)에 운반하는 방법이며 트랙트 셔블과 스노우로더(Snow Loader)등이 이용된다. +- ② 결빙 : 적설한랭지에서 기온이 0℃ 이하로 되면 노면이 동결된다. 특히 곡선부나 급구배지 등에서는 위험율이 커지므로 마찰저항이 증대되는 모래, 부순돌, 석탄재, 염화칼슘, 소금 등을 준비하여 뿌린다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 155~156쪽 (인쇄면 525~526쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/3. 훼손지복구/1. 토석채취지복구.md b/resources/knowledge/original/산림과임업기술(임도)/3. 훼손지복구/1. 토석채취지복구.md new file mode 100644 index 00000000..9441d3d0 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/3. 훼손지복구/1. 토석채취지복구.md @@ -0,0 +1,339 @@ +# 1. 토석채취지복구 + +토석채취지 복구라 함은 채석(석재 채취) 작업이 종료된 직후에 채석적지(채석장, 採石跡地) + +를 식생녹화공사에 적합하도록 잘 정리하고, 붕괴방지를 위한 사면안정공사를 실시한 후 가급적 경관적이며 자연 친화적인 식생으로 최선의 기술로 훼손된 임지를 빠른 시일내에 다시 녹화시키는 일이라 하겠다. + +### 가. 채석적지(採石跡地) 유형 + +채석적지의 유형구분은 구분 목적에 따라 다음과 같이 구분할 수 있다. +#### 1) 채석적지 유형분류 기준 +##### 가) 용도 및 암종에 따른 구분 +- ○ 건축재 : 내·외장 벽재 및 바닥재 +- - 조립질(중립질) 회백색 화강암류 및 편마암류(포천, 거창, 익산, 남원, 원주, 제천, 천안, 영주지역 석재) +- - 조립질 담홍색 화강암(문경, 상주, 진안, 무주, 운천지역 석재) +- - 거정질 화강암질 편마암류[점촌(목화석), 하동(설화석) 등] +- - 암회색 섬록암류[영천, 함양(마천), 고흥(금산), 담양지역 석재] +- ○ 공예재 : 묘비석, 기념비, 조각재, 가구재, 생활용품재 +- - 중(세)립질 회백색–청회색 화강암류(강화, 원주, 제천, 영주, 천안, 익산, 남원지역 석재) +- - 세립질 흑색사암 및 셰일류[충남 보령(웅천), 보은 지역 석재] +- - 화강암질 편마암류[점촌, 하동, 중원(엄정석) 지역 석재] +- - 화산암류(현무암 : 철원, 제주지역 석재. 유문암류 : 청송, 삼랑진, 영덕지역 석재) +- ○ 산림골재 +- - 아스콘 : 아스팔트용 쇄골재 +- - 레미콘 : 콘크리트용 쇄골재 +- - 토목용 : 방조제 제방 매립재, 도로 로반재 +##### 나) 암질(암석의 풍화정도)에 의한 구분 +- ○ 경암(硬岩) : 암석의 압축강도 500 ㎏/㎠ 이상이고, 겉보기 비중이 약 2.7–2.5 g/㎥ 이상인 암석 +- ○ 준경암(準硬岩) : 암석의 압축강도 100–500 ㎏/㎠이고, 겉보기 비중이 약 2.5–2.0 g/㎥ 인 암석 +- ○ 연암(軟岩) 및 파쇄암(破碎岩) : 암석의 압축강도 100 ㎏/㎠ 미만이고, 겉보기 비중이 약 2 g/㎥ 미만인 암석은 연암, 파쇄성이 많은 암석은 파쇄암 표 5-3-1. 암질별 암석의 물리적 성질 + +| 종 류 | 압축강도(㎏/㎠) | 흡수율(%) | 겉보기비중(g/㎥) | +|---|---|---|---| +| 경 암(석) | 500 이상 | 5 미만 | 약 2.7–2.5 | +| 준경암(석) | 100 – 500 | 5 – 15 | 약 2.5–2 | +| 연 암(석) | 100 미만 | 15 이상 | 약 2 미만 | + +자료 : 채석적지 복구공사의 계획·시공 및 준공검사에 관한 기준개발연구, 1993. + +##### 다) 채석방식에 의한 구분 +- ○ 경사면 채석방식 : 잔벽면에 계단을 설치하지 아니하고 채석함 +- ○ 계단식 채석방식 : 잔벽면에 계단을 설치하고 채석함 +- ○ 수직벽식 채석방식 및 기타 채석방식 : 건축용원석·규격 석재의 채석방식·수직벽형성, 기타 +##### 라) 채석 잔벽(殘壁)의 경사도에 의한 구분 +- ○ 절벽지 : 1 : 0.6 (60°) 이상 +- ○ 중절벽지 : 1 : 0.6–0.8 (51°–59°) +- ○ 급경사지 : 1 : 0.8 (50°) 이하 +##### 마) 채석허가면적 및 잔벽사면장의 규모에 의한 구분 +- ○ 소규모 채석장 : 허가면적이 2.0ha 이하 +- ○ 중규모 채석장 : 허가면적이 2.1ha∼5.0ha +- ○ 대규모 채석장 : 허가면적이 5.1ha 이상 +##### 바) 암반구조에 의한 구분 +- ○ 다절리성 암반 : 절리·습곡·단층·편리 등 암반구조상 균열부분이 많은 암구 +- ○ 중절리성 암반 : 균열부분이 중간 정도의 구조 +- ○ 소절리성 암반 : 균열부분이 적은 구조 (절리가 적은 잔벽은 녹화 곤란함)※ 절리 : 암반 중에 뚜렷하게 나타나는 균열로서 채굴에 있어서 발파의 효과, 파쇄암석의 크 + +기, 채석 후 잔벽의 녹화공사 등에 큰 영향을 미치게 된다. + +#### 2) 채석적지의 부위별 명칭 + +일반적으로 채석허가면적은 채석면적(채석장, 산물처리장, 기타)과 부대시설면적(진입로, 관리사, 기타)으로 구성되며, 채석적지에서의 각 부위별 명칭은 다음과 같다 + +![복구_그림5-3-1_채석적지부위별명칭](<../pic/복구_그림5-3-1_채석적지부위별명칭.png>) + +A : 벌채구역(허가구역에 포함)B : 돌림배수로 C : 절암(절취) 벽면의 (중앙부위의) 비탈어깨(法肩)D : 절암벽면의 비탈밑(法尻)D′: 본래사면의 비탈밑(法尻)E : 절암벽면의 비탈길이(사면장)E′: 절암벽면의 비탈(수직)길이(수직에 가까울 때)F : 절암벽면의 수직부위의 밑점G : 절암벽면의 수직높이 H : 절암벽사면(잔벽사면 : 채석적지 사면)의 사면적 I : 절암벽 수직면의 단면적(거의 수직으로 채석할 때) J : 절암벽 사면, 수직면, 밑면이 형성하는 채취 후 잔치된 토석체적 계산용 단면적 K : 본래 산지표면 L : 표토제거후 암반면M : 표토제거깊이N : 채취(채석장)부위 밑면길이(편평하게 된 지역)O : 토사채취량 계산용 구적도 단면적 α: 채취후 절암벽면과 밑면(수평선)에 의하여 형성되는 잔벽의 경사도 β: 본래 산지표면의 경사도 P : 절암벽면(E)과 수직벽면에 의하여 형성되는 삼각형의 밑면길이 Q : P 부분의 평면적(Pm × Sm = Qm2)R : N 부분의 평면적(Nm × Sm = Rm2)S : 비탈밑(D) 부위의 (좌에서 우까지) 전체길이 T : 산물처리장의 비탈끝 U : 산물처리장의 퇴적부위길이 V : 산물처리장의 평면적(Um × Sm = Vm2)W : 퇴적토사단면적(폐석 또는 퇴적토사)X : 산물처리장의 퇴적토사지의 사면적 그림 5-3-1. 채석적지 부위별 명칭 + +#### 3) 채석적지 유형 + +채석적지 복구를 위한 유형 구분은 앞에서 설명한 채석적지 유형 구분 기준(암종, 암질, 암반 구조, 석재용도, 채석방식, 채석잔벽의 경사도, 채석장규모)에 따라 구분할 수 있으나 여기서는 최대한 간편화 하기 위하여 석재용도와 채석방식에 의하여 구분('93. 산림청)하였다. 채석적지는 쇄골재 채석장, 석재 채석장과 특수석재 채석장으로 3구분할 수 있으며 석재 채석장은 다시 건축용 석재 채석장과 토목용 석재 채석장으로, 특수석재 채석장은 갱굴식, 굴하식채굴지와 석회석 채굴지로 구분할 수 있다. + +표5-3-2. 채석적지 표준유형 + +| 기본유형번호 | 기본유형 | 용도유형 | 구분기준 | +|---|---|---|---| +| 1 | 쇄 골 재 채 석 장 | 1-0 쇄골재 채석장 | 쇄골재 생산시설이 있는 채석장 (경사면식+소단형성식 채굴) | +| 2 | 석 재 채 석 장 | 2-1 건축용 석재 채석장 (수출용 원석 포함) | 수직벽식+소단형성식 채굴 | +| | | 2-2 토목용 석재 채석장 (매립용 석재 포함) | 경사면식+소단형성식 채굴 | +| 3 | 특수석재 채 석 장 | 3-1 특수 채석장 | 갱굴식·굴하식 채굴 | +| | | 3-2 석회석 채굴장 | 석회석 채굴(대규모) | + +자료 : 채석적지 복구공사의 계획·설계·시공 및 준공검사에 관한 기준개발연구, 1993. + +### 나. 채석지 복구공사 +#### 1) 복구공사 계획 + +채석사업 종료기간이 가까워지면 채석적지에 대하여 비탈다듬기공사와 산물처리장 부지정리 공사를 실시한 후 안정·녹화공사를 위한 공사일정계획, 공정계획을 수립하여 설계서작성, 승인, 시공 및 준공에 대한 세부계획을 수립해야한다. + +#### 2) 복구공사설계 + +채석적지에 대한 복구공사설계는 다음순서에 의하여 실시한다. +##### 가) 설계자료조사 +- ○ 최대 강우강도 및 강우량, 집수면적 및 적정수로규격, 공사용 재료 등 수로설계자료 +- ○ 채석잔벽의 형태 및 지질(토질)별 면적 +- ○ 객토 재료의 양부·적부 및 소요량 +- ○ 각종 공종의 시공재료의 구득난이도 여부, 운반거리, 신소재 재료·신공법 적용여부 +- ○ 설계내역작성에 필요한 단가 +##### 나) 현지조사 +- ○ 채석적지 현황 및 붕괴위험도 조사 채석적지의 입지조건과 붕괴위험도 구분을 위하여 다음 사항을 조사한다(부록1. 급경사지 붕 + +괴위험도 조사 야장 참조). + +- - 지형요인 •사면의 경사도 •사면 방향 •사면의 규모 : 사면의 길이, 높이 •종단면형 : 사면의 종단 형태로 ①돌출부, ②사면 상부 凹凸, ③사면 하부 凹凸, ④사면 전체 凹凸, ⑤직선사면 등으로 구분 조사한다. •사면형상 : 사면의 횡단형상(직선형, 미근형, 곡형)과 종단형상(凸형사면, 직선사면, 凹형사 +##### 면) 을 조합·구분한 것으로 +- ① 凸形尾根型사면 +- ④ 凸형직선사면 +- ⑦ 凸형谷型사면 +- ② 직선미근형사면 +- ⑤ 직선직선사면 +- ⑧ 직선곡형사면 +- ③ 凹형미근형사면 +- ⑥ 凹형직선사면 +- ⑨ 凹형곡형사면 등으로 구분 조사한다. •변각점 : 사면경사의 변환점으로 ① 확실, ② 명료, ③ 불 명료 등으로 구분한다. +- - 지질 및 토질요인 •암석 : 지질도 및 현지 확인조사에 의한다. •표토의 깊이 : 뿌리가 많이 분포하는 지점까지의 깊이(Rooting depth)를 조사한다. •기반암의 풍화상태 : 암석의 풍화정도에 의하여 ① 풍화토(RS), ② 미 풍화토(CW), ③ 연암(HW), ④ 보통암(MW), ⑤ 경암(SW)으로 구분 조사한다. •기암의 균열간격 : 암석의 절리 또는 틈의 간격으로 ① 10cm 이하, ② 11∼30cm, ③ 31∼50cm, ④ 51cm 이상으로 구분 조사한다. •불연속면(절리)의 크기 : 절리의 틈새(mm)와 길이(m)를 조사한다. •불연속면의 충진상태 : 암석의 절리 등 균열부위의 상태로 ① 개구(開口) ; 비어있는 상태, ② 협재 ; 진흙 등 타 물질로 채워져 있는 상태, ③ 밀착 ; 가는 틈만 있는 상태, 등으로 구분 조사한다. •불연속면의 방향수 : 절리의 방향수를 조사한다(보통 1∼3 방향 임). •사면과 불연속면의 경사관계 : 암석의 절리방향과 사면의 경사방향과의 관계로 7구분 조사한다(부록1. 급경사지 붕괴위험도 조사 야장 참조). •단층의 유무 +- - 환경요인 •사면 또는 주위의 식생 : 수종, 수고, 경급, 피도(%)를 조사한다. •붕괴 이력 : 사면 또는 인접사면에서의 붕괴 이력으로 ① 있다(상부, 중부, 하부, 사면전 +##### 체) 와 ② 없다로 구분 조사한다. + +•용수상태 : 사면상의 용출수의 유무상태로 ① 항시 존재, ② 강우시 존재, ③ 없다 로 구분한다. •대책공 상황 : 사면에 기 설치된 안정 및 녹화공사 시설물이 있을 경우 공종 및 파손상태 등을 기술한다. •토지이용상황 : 사면의 상·하부의 토지이용상태를 조사한다. +- ○ 채석지 부위별 면적측량 채석지복구 공종배치도 작성을 위하여 채석부위(보전구역, 채석잔벽, 산물처리장 및 퇴적구역, + +진입로 및 기타구역)별 평판측량으로 평면도(축척 1 : 1,200)를 작성한다. 채석잔벽은 일반적으로 평균 비탈물매가 경사도 60°이상으로 급하기 때문에 평면적 뿐만 아니라 사면적도 계산해야 한다. 잔벽의 사면적은 분사식 씨뿌리기 또는 종비토 뿜어붙이기공사에 활용된다. + +- ○ 현지설계 기초조사 +- - 공작물 배치도 작성 설계서작성에 필요한 설계기초조사로 채석적지의 부위별 면적과 규모, 경사도, 길이, 너비, 소 + +단길이 등을 확인하고 수로의 위치, 소단의 위치, 각종 공종의 배치상태를 도시한 견취도(見取圖)를 작성한다. + +- - 공종별 치수(크기)조사 견취도상에 배치된 공종별크기(상장, 하장, 높이, 경사도, 비탈높이, 면적)를 조사한다. +- - 현지채취재료의 운반량조사 현지채취재료의 운반거리와 운반조건 등을 건설표준품셈에 의하여 운반량을 산출한다. +##### 다) 설계서작성 + +설계서는 공사설명서, 일반시방서, 특별시방서, 예정공정표, 예산내역서, 일위대가표, 단가산출 서, 각 공종별 경비계산서, 공종별 수량계산서, 각종 소요자재 총괄표, 토적표, 산출기초 순으로 작성한다. + +- ○ 설계에 필요한 재료 설계에 필요한 주요 재료에는 석재, 목재, 철재, 철사돌망태, 시멘트, 골재, 콘크리트블록, 떼, + +종자, 묘목, 비료, 토양안정제 등이 있다. + +- - 석재 : 자연석 : 전석, 야면석, 호박돌, 사석, 잡석, 조약돌, 자갈 가공석 : 마름돌, 견치돌, 막깬돌, 깬잡석, 깬자갈, 깬조약돌 +- - 목재 : 통나무, 우듬지(초두목), 가지, 바자, 판재 +- - 철재 : 철근, 철판, 철사, 철관, 와이어 로프 +- - 철사 돌망태 +- - 시멘트, 골재(잔 골재, 굵은 골재) +- - 시멘트 몰터, 콘크리트, 철근 콘크리트 +- - 콘크리트블록(쌓기블록, 붙이기블록), 콘크리트 관, 콘크리트 격자블록, 벽돌 (인조목, 의목) +- - 합성재 블록, 합성재 관, 합성재 격자 블록(합성재 : PVC, PE, PET, PP, HDPE, FRP,GRT, RTR, RPM) +- - 낙석방지망 : 철사망, 합성재 망 +- - 떼 : 풀포기·새류, 자연생 떼, 재배 떼 +- - 묘목 : 내환경수종, 환경녹화수종, 녹화수종, 사방수종, 교목류, 관목, 저목 +- - 종자 : 초류종자, 재래초류종자, 외래초류종자, 목본류종자 +- - 종비토 : 종자+비료+흙+유기질+안정제+물+… +- - 식생대류 : 식생반(판), 식생자루, 식생대, 식생벨트, 토목섬유, 기타 +- - 피복재 : 철사망, 거적, 망(합성망, 유기재망…), 비닐, 기타 +- - 비료 : 유안, 요소, 초안, 과석, 증과석, 산림용 고형복합비료 +- ○ 설계에 필요한 공종 설계에 필요한 안정·녹화공사용 주요 공종(공법)은 계간 안정공사, 산지비탈 안정·녹화공 + +사, 절·성토비탈 안정·녹화공사, 기타 공사로 구별할 수 있으며, 각 공사별 주요 공종(공법)은 다음과 같다. + +- - 계간 안정공사 •사방 댐 •수제 •구곡막이(골막이) •보막이 •바닥막이 •둑쌓기 •낮은 바닥막이(대공) •밑막이 •기슭막이 •계간 수로내기 +- - 산지비탈 안정·녹화공사 •비탈다듬기 •단쌓기 •단끊기 •선떼 붙이기 •땅속 흙막이 •조공 •누구막이 •줄떼 다지기 •흙막이 •평떼 붙이기 •돌쌓기·블록쌓기 •띠떼 심기 •돌 붙이기 •새심기 •축대벽 •비탈덮기 •수로내기 •등고선구공법 •속도랑내기(암거공사) •씨 뿌리기 •울짱얽기 •나무심기 +- - 절·성토비탈 안정·녹화공사 •힘줄박기 •식생공법 •격자틀 붙이기 •분사식 씨뿌리기 •앵커박기 •종비토 뿜어붙이기 •주입공사 •새집공법 •낙석방지망 덮기 •식생상공법 •낙석저지책 세우기 •소단상 객토식수공법 •콘크리트 뿜어붙이기 •차폐수벽공법 +- ○ 공종(공법)별 부호견취도 작성시 공종표시 부호는 다음과 같이 표시한다. + +![복구_그림5-3-2_주요재료의부호](<../pic/복구_그림5-3-2_주요재료의부호.png>) + +그림 5-3-2. 주요 재료의 부호 + +![복구_그림5-3-3_주요공종의부호_01](<../pic/복구_그림5-3-3_주요공종의부호_01.png>) + +![복구_그림5-3-3_주요공종의부호_02](<../pic/복구_그림5-3-3_주요공종의부호_02.png>) + +![복구_그림5-3-3_주요공종의부호_03](<../pic/복구_그림5-3-3_주요공종의부호_03.png>) + +그림 5-3-3. 주요 공종(공법)의 부호 + +### 다. 복구방법 + +채석지 안정·녹화공사는 복구준비 조치공사와 복구공사로 구분 실시한다. +#### 1) 복구준비 조치공사 + +채석지 안정·녹화공사를 가능하게 하기 위하여 복구준비 조치공사로 비탈다듬기공사와 잔벽소단설치공사를 한다. + +##### 가) 보전구역의 비탈다듬기공사 + +채석장과 인접지와의 사이에 있는 보전구역이 붕괴되지 않도록 비탈면 다듬기공사와 흙막이 공사를 실시해야 한다. + +- ○ 비탈면이 토사인 경우에는 사면상부에서 하부를 향하여 뜬돌(浮石) 등을 제거하여 비탈면을 편평하게 한다. +- ○ 비탈면이 암석인 경우에는 곡괭이, 빅 햄머(Big hammer) 또는 소형 착암기에 의하여 암석을 삭박하거나 낙석위험 암반은 제거한다. 끝 손질한 비탈면의 요철에 대해서는 암질에 따라 다르지만 요철높이 30cm 정도까지 다듬기공사를 하는 것이 좋다. +##### 나) 잔벽의 비탈다듬기 공사 + +노천채굴이 끝난 채석장의 잔벽은 잔벽면의 붕괴를 방지하기 위하여 암석의 풍화정도와 암석의 불연속면(절리, 균열부 등)의 방향 등에 따라 적당한 높이와 너비를 가진 소단(小段)을 설치해야 하며 적당한 기울기가 유지되도록 사면을 다듬는다. + +- ○ 채석장 잔벽의 비탈다듬기공사는 높이 10m 마다 2m 이상의 너비를 갖는 소단을 계단식으로 설치하며 잔벽의 경사도는 60°를 초과하지 않는 것을 원칙으로 하나 암질(암석의 풍화 정도)에 따라 다음과 같이 다르게 설치한다. 표 5-3-3. 암질에 따른 비탈경사와 소단폭 + +| 암질 (암석풍화정도) | 비탈 경사(°) | 소단폭(m) | 소단간 사거리(m) | +|---|---|---|---| +| 경 암 | 80 이하 | 2 이상 | 20 이하 | +| 보통암 | 75 이하 | 2 이상 | 20 이하 | +| 연 암 | 70 이하 | 2 이상 | 15 이하 | +| 토 사 | 45 이하 | 1∼2 | 5 이하 | + +- ○ 하부에 설치하는 소단의 너비는 상부에 설치하는 소단의 너비보다 넓게 해서 상부의 물매보다 하부의 물매를 완만하게 하며 잔벽의 높이가 높을 경우 상부로 갈수록 소단간 높이를 하부에서 보다 낮게 조성하는 것이 안정녹화 공사시공에 효과적이다. + +![복구_그림5-3-4_쇄골재채석장잔벽모형](<../pic/복구_그림5-3-4_쇄골재채석장잔벽모형.png>) + +잔벽의 평균 기울기 그림 5-3-4. 쇄골재 및 토목·매립용 채석장(계단식 채굴)에서의 잔벽설정 모형도 + +![복구_그림5-3-5_원석채석장잔벽모형](<../pic/복구_그림5-3-5_원석채석장잔벽모형.png>) + +잔벽의 평균 기울기 그림 5-3-5. 건축 및 수출용 원석 채석장(수직벽 및 계단식 채굴)에서의 잔벽설정 모형도 + +#### 2) 복구공사 + +채석적지를 ①보전구역, ②채굴잔벽, ③산물처리장 및 퇴적장구역과 ④진입로 등 기타구역으로 구분하여 안정공사를 실시한다. + +##### 가) 보전구역 안정·녹화공사 + +채석잔벽의 상부에 있는“보전구역”에는 주로 돌림수로와 흙막이공사로 사면을 안정시키고 새심기, 씨 뿌리기와 나무심기 등으로 녹화한다. 절개지 상단부에는 낙상 및 붕괴예방을 위하여 위해방지시설(철책) 및 산비탈 돌쌓기를 설치한다. + +##### 나) 채굴잔벽의 안정·녹화공사 + +채굴잔벽은 채석 후 암반절개 사면으로서“복구준비 조치공사”가 되어있지 않은 지역에서는 비탈다듬기공사를 통하여 소단을 설치하고 잔벽높이를 조성하여 안정·녹화공사에 기반을 조성한다. 소단상에는 객토 식수공법에 의하여 수목을 식재 녹화시키고 내측에 횡수로를 설치한다. 소단 간 사면에는 위치에 따라 종수로를 설치하고 암반사면의 요·철정도에 따라 새집공법이나 식생상공법에 의하여 녹화시키며 연약지반에 대하여는 돌 단쌓기로 사면을 안정시킨다. 이상의 공법으로 녹화가 불가능한 경질의 암반사면은 분사식 씨뿌리기나 종비토 뿜어붙이기에 의하여 사면을 녹화시킨다. 잔벽 하부에 낙석저지책 또는 차폐수벽공법이 적용되기도 한다. + +- ○ 소단의 높이는 토질에 따라 절개비탈면이 암반으로 형성된 지역은 직고 20m 이하 간격으로 하되 기슭막이 또는 산비탈돌쌓기·파식공·덩굴식물 등 녹화공법이 가능하도록 폭 2m 이상으로 소단을 설치한다. +- ○ 소단에는 식생의 녹화를 위하여 최소한 70cm 이상 객토를 실시한다. +- ○ 기슭막이 또는 산비탈 돌쌓기는 붕괴위험을 방지하기 위하여 야면석 또는 채석장의 폐석(L : 30∼45cm)으로 찰쌓기를 실시한다. +- ○ 소단내 객토의 유출방지를 위하여 소단내측에 암·명거시설을 하거나 찰쌓기 또는 혼합(떼+돌)쌓기 등으로 시설한다. +- ○ 절개비탈면의 표면에 요철이 많아 시공하기 쉬운 부분은 새집 공법, 식생상 공법 또는 종 비토 뿜어붙이기 공법으로 시공한다. +- ○ 안정된 암벽 절개지역은 절리방향이 비탈면방향과 거의 직각일 때는 토양이 붙을 수 있도록하고 종자 뿜어붙이기 또는 종비토 뿜어붙이기 공법으로 시공한다. +- ○ 절개사면·암반의 절리방향이 사면방향과 동일한 지역은 앵커박기 또는 록볼트공으로 암석붕괴를 방지한다. +##### 다) 산물처리장 및 퇴적장구역의 안정·녹화공사 + +채굴적지의 평탄부분에 대해서는 70cm 이상으로 객토한 후 파식에 의하여 녹화시키며 퇴적장의 불안정한 사면은 수로내기, 축대벽(옹벽), 기슭막이, 흙막이공사에 의하여 사면을 안정시킨다. + +- ○ 급경사지 (30°∼45°) +- - 직고 5m 이하 간격으로 심줄박기나 폭 1∼2m의 소단을 설치하고 단상에는 산비탈돌쌓기 또는 선떼붙이기를 시공한 후 씨뿌리기 또는 줄떼다지기로 피복한다. +- - 지표수 용출로 인한 침식이 우려될 때에는 소단상 후면에 수로내기(반원관등)를 하고 사면 길이가 20m 이상으로 긴 지역은 종수로를 설치하여 안전하게 유출시킨다. +- - 단간 비탈면에는 줄떼다지기·씨 뿌리기·새심기 등 조기피복하여 토사유출을 방지한다. +- - 최하단부는 콘크리트 축대벽·돌기슭막이 등을 시공하여 토압을 지탱시킨다. +- - 성토면적이 넓거나 성토량이 많은 경우에는 중복부에 땅속흙막이나 심줄박기를 알맞게 시공한다. +- - 암괴나 토사로 성토되었을 때는 점토로 복토하고 파식을 하거나 구덩이를 파고 충분한 객 토를 한 후 식재한다. +- - 단상에는 1.5m 간격으로 대묘(60cm 이상)를 식재하고 ha당 5,000본의 사방수종 또는 적지적수를 식재한다. +- ○ 완경사지 (30°미만) +- - 직고 5m 이하 간격으로 폭 1∼2m의 소단을 설치하고 단상에 흙막이 또는 선떼붙이기를 시공한 후 파종 또는 식재한다. +- - 흙쌓기 비탈면 길이가 길어 토압이 클때는 중복부위에 땅속흙막이, 심줄박기 등 알맞는 공법을 적용한다. +- - 단간 비탈면에는 줄떼다지기, 씨뿌리기, 새심기 등을 하여 피복한다. +- - 성토지 하단부는 토압지탱상 필요한 때는 콘크리트 축대벽·기슭막이·산비탈돌쌓기 등을 시공한다. +- - 암괴나 사토로 성토되었을 때는 점토로 복토하고 파식을 하거나 구덩이를 파고 충분한 객 토를 한 후 식재한다. +- - 평탄한 지역의 끝부분에는 둑을 1∼2m 높이로 설치하여 지표수가 성토지 법면으로 흐르지 않도록 한다. +- - 평탄지역은 사방 50m 간격으로 수로를 설치하고 수로합류지점은 누구막이를 시공한 후 하류로 원활하게 배수되도록 돌 수로를 시공한다. +- - 상록대묘(60cm 이상)를 ha당 5,000본의 사방수종 또는 적지적수를 식재한다. +##### 라) 진입로 기타구역에 대한 안정·녹화공사 + +주로 진입로등이 포함되는 완경사지로 계곡부의 붕괴우려지에는 계간부에 기슭막이, 골막이 등을 시공하여 계상과 산각을 고정하고 토·사력이 많이 유출될 우려가 있을 경우에는 사방댐을 시공하여 토석류를 유치 고정한다. 그외 사면에는 새심기, 줄 씨뿌리기와 나무심기로 녹화시킨다. 표 5-3-4. 경사도별 퇴적지(성토지) 안정·녹화공사 + +| 구 분 | 30°미만 | 30°∼45° | +|---|---|---| +| 상단부 | ·땅속흙막이 ·단끊기 ·돌림수로 ·선떼 붙이기 ·흙막이 ·조공 ·줄떼 다지기 ·새심기 ·파식 | ·땅속흙막이 ·단끊기 ·돌림수로 ·선떼 붙이기 ·흙막이 ·조공 ·줄떼 다지기 ·파식 | +| 중복부 | ·땅속흙막이 ·단끊기 ·돌림수로 ·선떼 붙이기 ·흙막이 ·조공 ·줄떼 다지기 ·새심기 ·파식 | ·심줄심기 ·땅속흙막이 ·단끊기 ·돌림수로 ·산비탈 돌쌓기 ·흙막이 ·선떼 붙이기 ·조공 ·줄떼 다지기 ·새심기 ·파식 | +| 하단부 | ·기슭막이 ·산비탈 돌쌓기 ·수로공 ·선떼붙이기 ·흙막이 ·줄떼 다지기 ·새심기 ·파식 | ·기슭막이 또는 축대벽 ·산비탈 돌쌓기 ·수로공 ·선떼 붙이기 ·흙막이 ·줄떼 다지기 ·새심기 ·파식 | + +![복구_그림5-3-6_채석잔벽안정녹화정면도](<../pic/복구_그림5-3-6_채석잔벽안정녹화정면도.png>) + +그림 5-3-6. 채석잔벽 안정·녹화공사 개념도 (정면도) + +![복구_그림5-3-7_채석잔벽안정녹화측면도](<../pic/복구_그림5-3-7_채석잔벽안정녹화측면도.png>) + +그림 5-3-7. 채석잔벽 안정·녹화공사 개념도 (측면도) + +표 5-3-5. 채석적지 표준유형에 대한 안정·녹화공사 표준공종(공법) 배치기준 + +| 부 위 별 적 용 공 종 (공 법) | 단 위 | 유형 1. 쇄골재채취장 | +|---|---|---| +| - (잔벽주위 토석구역 : 보전구역 : 600㎡) ① 산비탈 돌쌓기 (길이 4m × 6개소) (높이 0.5m) ② 돌 수로내기 (소형) (0.3 × 0.9 × 0.3m) ③ 새심기 (새·솔새 등의 풀포기) ④ 녹화식수공법 (교목수종은 수고 1m 이상) - (채굴잔벽비탈 구역 : 사면적 3,500㎡, 평면적 1,700㎡) ① 비탈 다듬기 (3,500㎡ × 0.15m) ② 돌 단쌓기 (높이 1m) ③ 돌 수로내기 (소형) (0.3 × 0.9 × 0.3m) (종배수로) ④ 새집공법 (길이 3m × 높이 1m 돌쌓기 구조) (녹화식수 6본/집) ⑤ 소단상 객토식수공법 (침·활·관목 혼효식재) (소단연장 230m × 너비 1m × 두께 0.3m 객토 = 70㎥) ⑥ 객토자루새심기 (20ℓ × 150개) (객토 3㎥) ⑦ 덩굴식물녹화공법 (담쟁이, 등나무 기타) ⑧ 차폐수벽공법 (가로수 규격의 대묘) * 분사식 씨뿌리기공법 * 종비토 뿜어붙이기공법 - (산물처리장 및 퇴적장구역 : 6,800㎡) ① 비탈 다듬기 (1,000㎡ × 0.2m) ② 돌 단쌓기 (높이 1m) ③ 산비탈 돌쌓기 (높이 0.5m) (깊이 4m × 25개소) ④ 옹벽 (석축 높이 2m·대석 사용) ⑤ 돌 수로내기 (소형) (0.3 × 0.9 × 0.3m) ⑥ 돌 수로내기 (중형) (0.5 × 1.5 × 0.5m) ⑦ 돌 조공 (잡석사용) ⑧ 새심기 (새, 솔새 등의 풀포기) | m m ㎡ 본 ㎥ m m 개소 ㎥ (객토) 본 ㎥ (객토) 본 ㎥ (객토) (자루/주) 본 m ㎡ ㎡ ㎥ m m m m m m ㎡ | 24 120 100 250 520 100 100 50 (45) (300) 70 (500) 3 (600) (500) 50 200 100 100 30 400 50 300 100 | + +(계속) + +| 부 위 별 적 용 공 종 (공 법) | 단 위 | 유형 1. 쇄골재채취장 | +|---|---|---| +| ⑨ 줄 떼심기 (반떼 사용) ⑩ 줄 씨뿌리기 (줄너비 0.2m × 3,000m = 600㎡) ⑪ 녹화식수공법 (교목수종은 수고 1m 이상의 대묘) ⑫ 차폐수벽공법 (가로수 규격의 대묘) *객토공사 (6,800㎡ × 0.1m = 680㎥/2) - (진입로·기타 구역 : 900㎡) ① 비탈 다듬기 (900㎡ × 0.05m) ② 산비탈 돌쌓기 (높이 0.5m) (길이 4m × 8개소) ③ 돌 수로내기 (소형) (0.3 × 0.9 × 0.3m) ④ 새심기 (새, 솔새 등의 풀포기) ⑤ 줄 씨뿌리기 (줄너비 0.2m × 300m = 600㎡) ⑥ 녹화식수공법 (교목수종은 수고 1m 이상 대묘) (* : 도시지역 또는 특수한 경우에 한함) | m ㎡ 본 m ㎥ ㎥ m m ㎡ ㎡ 본 | 300 600 3,490 30 340 50 32 30 50 60 300 | +| (1ha 당묘목 식재본수 합계) (덩굴식물 제외) | (본) | (5,000) | +| 합 계 | | | + +※ 채석적지 면적 1ha 기준 + +#### 3) 공종(법)별 시공요령 + +채석적지 안정·녹화공사로 계간안정공사, 산지비탈 안정·녹화공사와 절·성토 안정·녹화공사가 있으며 이들 공사에 따라 많은 공종과 공법이 있으나“사방”공종·공법과 중복되므로 여기서는 채석지 안정·녹화공사에 주요 공종(공법)인 비탈 다듬기, 단끊기, 울짱얽기, 분사식 씨 뿌리기, 종비토 뿜어붙이기, 새집공법, 차폐수벽공법, 소단상 객토식수공법, 콘크리트 뿜어붙이기, 앵커박기, 낙석방지망 덮기, 낙석저지책 세우기 등에 대한 시공요령을 기술코자 한다. + +##### 가) 비탈다듬기 (뭉기기, 뭉개기, 整度工, 法切工) + +비탈다듬기는 불규칙한 사면 또는 사면의 불안정한 토석층을 완화하여 안정된 비탈면을 조성할 목적으로 시공하는데 경사가 심한 비탈면을 일정한 경사도로 유지하도록 땅깎기를 하며 깊은 곳은 메우는 공사를 말한다. 일반적으로 비탈다듬기 기울기는 토사의 안식각(安息角)을 한계점으로 하는 것이 안전하다. + +- ○ 시공장소 기복이 심한 산복비탈 또는 절·성토사면, 암반 절개사면 +- ○ 시공요령 +- - 사면기울는 대상지의 종단면도를 작성하여 결정하되 지질, 경사, 주변의 지형과 공법 등에 따라 조화있게 결정한다. +- - 사면기울가 급한지역은 선 떼붙이기 및 산비탈 돌쌓기 등으로 조정한다. +- - 비탈다듬기는 산꼭대기부터 시작하여 산아래로 진행하며 부토가 많은 지역은 속도랑공사 및 땅속흙막이 공사를 시공한 후 비탈 다듬기를 하는 것이 효과적이다. +- - 비탈 다지기공사후에는 뜬 흙이 비탈에 안착할 때까지 일정기간은 비 바람에 노출되어야하며 그 후에 다른 공종을 시공한다. +- - 비탈 다지기공사에 의해서 잡목이나 그루터기가 매몰되는 경우에는 비탈다듬기 공사전에 이것을 미리 정리하여 매몰되지 않도록 시공한다. +- - 채굴공사 마지막 단계에 이를 때에는 비탈다듬기공사를 동시에 진행하면서 채굴하여 채굴 작업 이후의 비탈 녹화공사를 위한 비탈다듬기 공사가 용이하게 진행될 수 있도록 한다. 채굴면의 凹凸면에 대개 30cm 이내로 비교적 평편하게 다듬는다. +- - 채석지 보전구역과 퇴적장 비탈면에 대해서도 가급적 최대로 안정 경사도가 되도록 균질하게 다듬고, 수로공사의 위치 등에 대해서는 미리 터 파기공사를 한다. +- - 기계에 의한 비탈다듬기공사는 토사의 절취량이 많고, 지형적으로도 기계에 의한 시공이 가능한 경우에 채용한다. 주요한 사용기계에는 불도져, 백호우, 트랙터셔블, 굴착기 등이 있으며, 암반에서는 착암기 등 + +으로 다듬어야 한다. 기종 및 규격은 시공지의 지질, 지형에 적합한 것을 선정해야 한다. + +##### 나) 단끊기 (비탈단끊기, 계단끊기, 階段工, 段切工) + +비탈다듬기 공사를 실시한 사면에 수평단을 끊고 초·목본류를 파식하여 황폐된 나지에 식생을 조성하려는 기초공사이다. 산복사면 길이를 줄이고 수평면을 유지케 하므로써 사면에 유하 되는 토사를 저지하고 유수를 분산시키므로 침식을 방지하는 동시 식생조성에 필요한 기반조성을 위한 것으로 선떼붙이기나 조공, 흙포대 흙막이 및 씨뿌리기를 병행 실시하는 공종이다. 수토보전(水土保全) 공사로서도 계획·시공한다. + +- ○ 시공장소 비탈다듬기 공사가 끝난 산복사면 +- ○ 시공요령 +- - 단끊기는 상부로부터 하부로 향하여 시공하며 단상(段上)에는 될 수 있는 대로 재래의 표토를 존치하도록 한다. +- - 단 끊기는 수평으로 실시하며 단폭(계단나비)은 일반적으로 50∼70cm으로 하지만 비탈면의 기울기가 급할 때에는 계단폭을 좁게하여 상하 계단간의 비탈면 기울기를 완만하게 한다. +- - 단끊기에 의하여 생산되는 토사의 처리는 시공경비와 관계가 많으므로 절취토사의 이동은 최소한도로 한다. +##### 다) 단쌓기(段積工) + +경사가 급한지역에서 비탈다듬기 공사나 단끊기 공사로 생산된 토사가 많은 사면을 조기에 안정·녹화하기 위하여 높이와 너비가 일정한 계단을 연속적으로 붙여 구축하는 비탈안정 녹화 공종으로 사용재료에 따라 떼, 돌, 돌·떼, 짚망, 흙포대, 합성재 단쌓기가 있다. + +- ○ 시공장소급경사지로 부토(浮土)가 많은 사면 +- ○ 시공요령 +- - 용수로 인하여 붕괴위험성이 있는 장소에서는 속도랑내기를, 시공높이가 높은경우에는 땅 속흙막이 또는 흙막이 공작물을 겸하여 시공한다. +- - 떼단쌓기(段積立芝工, Stepped mini-terrace sodding works)는 단끊기 및 떼붙이는 요령은 선떼붙이기(7급)와 같으며 떼단의 높이와 너비는 30cm 정도로 한다. 동일 비탈면에 연속적으로 시공하는 떼단의 수는 5단을 초과하지 않도록 해야하며 5단 이상 + +일 경우에는 5단을 쌓은 후 돌쌓기와 같은 보다 견고한 흙막이 공작물을 시공하고 떼단의 나비보다 더 넓은 정도의 작은단(小段)을 설치한 다음 그위에 떼단쌓기를 계속한다. + +- - 돌이 많은 지역에서는 떼대신 돌(잡석)을 이용하여 돌 단쌓기(段積石工)를 한다. +- - 석재가 많은 지역에서는 떼대신 석재로 단(段)을 쌓으면서 돌 사이에 떼를 넣어 돌과 떼가 일체가 되도록“돌·떼단쌓기"를 시공하는 것이 경제적이고 효과적이다. +- - 떼를 구하기 어려운 장소에서 떼 대신 볏짚을 위 아래로 구부려 넣고 단 위에는 묘목을 심고 풀씨를 파종하는“볏짚 단쌓기"를 한다. + +![복구_그림5-3-8-9_떼단및볏짚단쌓기](<../pic/복구_그림5-3-8-9_떼단및볏짚단쌓기.png>) + +<측면도> <측면도>그림 5-3-8. 떼단쌓기 그림 5-3-9. 볏짚 단쌓기 + +##### 라) 조공(條工, 筋工) + +황폐사면(각종 붕괴지 절·성토사면)에 나무와 풀을 파식하기 위하여 산복비탈면에 수평으로 계단을 끊고 앞면에는 떼, 새포기, 잡석 등으로 낮게 쌓아 계단을 보호하며 뒷면에는 흙을 채워서 파식상을 조성한 후 파식하는 산복녹화공법이다. + +--- + +- 기준 파일: `산림과임업기술(임도).pdf` +- 원문 위치: PDF 157~176쪽 (인쇄면 527~546쪽) diff --git a/resources/knowledge/original/산림과임업기술(임도)/_index.md b/resources/knowledge/original/산림과임업기술(임도)/_index.md new file mode 100644 index 00000000..e643e35e --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/_index.md @@ -0,0 +1,16 @@ +# 산림과임업기술(임도) — 자료 목록 + +> 출처 미상 과거 기술자료다. 현행 설계 기준이 아니며, 사용 제한과 품질점검 결과는 [_meta.md](<_meta.md>)를 먼저 확인한다. + +- [원본 PDF](<원본/산림과임업기술(임도).pdf>) +- **2. 임도** + - [1. 총론](<2. 임도/1. 총론.md>) — PDF 1~7쪽, 인쇄면 371~377쪽 + - [2. 임도구조](<2. 임도/2. 임도구조.md>) — PDF 8~18쪽, 인쇄면 378~388쪽 + - [3. 임도계획](<2. 임도/3. 임도계획.md>) — PDF 19~47쪽, 인쇄면 389~417쪽 + - [4. 노선측량](<2. 임도/4. 노선측량.md>) — PDF 48~86쪽, 인쇄면 418~456쪽 + - [5. 설계](<2. 임도/5. 설계.md>) — PDF 87~117쪽, 인쇄면 457~487쪽 + - [6. 시공](<2. 임도/6. 시공.md>) — PDF 118~154쪽, 인쇄면 488~524쪽 + - [7. 유지보수](<2. 임도/7. 유지보수.md>) — PDF 155~156쪽, 인쇄면 525~526쪽 +- **3. 훼손지복구** + - [1. 토석채취지복구](<3. 훼손지복구/1. 토석채취지복구.md>) — PDF 157~176쪽, 인쇄면 527~546쪽 +- [추출 그림](pic/) diff --git a/resources/knowledge/original/산림과임업기술(임도)/_meta.md b/resources/knowledge/original/산림과임업기술(임도)/_meta.md new file mode 100644 index 00000000..5aeb43c3 --- /dev/null +++ b/resources/knowledge/original/산림과임업기술(임도)/_meta.md @@ -0,0 +1,38 @@ +# 산림과임업기술(임도) + +> **구조 교정 진행 중 (2026-09-06)**: 수식의 분수·위첨자와 표의 병합 셀을 원문과 대조하여 교정하고 있다. 전체 페이지 이미지는 Markdown에 넣지 않으며, 표·수식·도면 단위로 필요한 자료만 수록한다. + +- 원본 파일: `원본/산림과임업기술(임도).pdf` +- 수록 범위: PDF 176쪽, 인쇄면 371~546쪽 +- 확인된 장절: `2. 임도` 7개 절과 `3. 훼손지복구`의 `토석채취지복구` +- 발행처·발행연도·저자: **근거 미확인** — 제공된 발췌본에 표지·판권·서지정보 없음 +- 성격: 과거 임도 기술 해설 발췌본(보조 참고) +- 변환본 목록: [_index.md](<_index.md>) + +## 적용 제한 + +- 폐지된 「산림법」 조문, 1·2급 임도 구분, VAX·FRNET 사례 등이 수록되어 현행 기준으로 사용할 수 없다. +- 수치·공식·시설기준은 현행 법령·행정규칙과 `technical_info/`를 우선 확인한다. +- 이 문서의 값은 비교·연혁 확인용 후보일 뿐 프로그램 기본값이나 확정값으로 채택하지 않는다. +- 발행정보가 확인되기 전에는 다른 문서의 직접 근거로 승격하지 않는다. + +## 변환 및 품질점검 (2026-09-06) + +- `original/_pipeline/pdf2md.py`로 1차 변환한 뒤 원문의 장·절에 따라 Markdown 8개로 분할하고 제목 계층을 복원했다. +- 각 PDF 쪽의 인쇄면 번호(371~546)와 정확히 일치하는 단독 숫자만 본문에서 제외했다. 문장·수식·표 안의 숫자는 제거하지 않았다. +- 정규화한 원문 3,079개 검증 줄의 앞 12자를 분할본 전체와 대조한 결과 누락 0개(커버리지 100%)다. +- 그림 118개를 추출했으며 Markdown 링크 누락은 0개다. +- PDF 글자의 실제 좌표 간격으로 원문 어절 공백을 복원했다. PDF 줄 끝 경계는 임시 표식으로 보존한 뒤 한국어 형태소 분석으로 공백 유무만 판정했으며, 기존 어절 내부의 공백은 임의 변경하지 않았다. +- 띄어쓰기 복원 전후에 공백을 제외한 문자열이 동일한지 검사해 본문 문자 변경이 없음을 확인했다. +- 일부 PDF 색상 프로필 오류 메시지가 있었으나 본문 추출과 그림 저장은 완료됐다. +- 각 문서 끝에 들어갔던 PDF 전체 176쪽의 통페이지 이미지 부록은 제거했다. 벡터 도면이 표로 오인된 설계 문서의 7개 구간만 도면 범위로 잘라 해당 본문 위치에 배치했다. + +### 구조 대조 결과와 사용법 + +- 검색용 평문에는 PDF의 2차원 배치 특성상 분수·위첨자·병합 셀이 선형화된 곳이 남아 있다. +- 수식 조각을 제목으로 오인한 9개 항목을 일반 본문으로 바로잡고, `표 5-2-2`의 앞·뒤 바퀴거리 값을 한 셀 안에서 구분했다. +- 인쇄면 458~459쪽의 트래버어스 계산을 원문과 직접 대조하여 `표 5-2-29`, 폐합오차·폐합비 식, 측선별 위거·경거 조정량, `표 5-2-30`을 행별 구조로 복원했다. +- `5. 설계.md` 정밀 점검에서 `표 5-2-32`~`표 5-2-36`의 합쳐진 측점 데이터를 행별로 복원하고, 점고법 체적식·시공면고식·중기 손료의 지수·Box 귀면의 제곱근을 원문 배치에 따라 교정했다. 벡터 구조도·전산처리 흐름도를 표로 오인한 블록은 제거하고 해당 원문 면 이미지로 대체했다. +- 원문의 구식 이중선 등호 글리프가 Markdown 194줄에 498개 남아 있음을 확인하여 모두 일반 등호 `=`로 통일했다. +- 수식·표의 의미는 원본 PDF와 직접 대조하며, Markdown에는 통페이지가 아닌 필요한 표·수식·도면 범위만 사용한다. +- `누락 0개`는 검색용 평문의 문자 존재 검증이며, 의미·배치는 176개 원문 대조 이미지가 보존한다. diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-25_삼각좌표에따른흙의분류도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-25_삼각좌표에따른흙의분류도.png new file mode 100644 index 00000000..920fb364 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-25_삼각좌표에따른흙의분류도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-26_통일분류법을위한소성도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-26_통일분류법을위한소성도.png new file mode 100644 index 00000000..32125ba4 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-26_통일분류법을위한소성도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-27_중심선과영선의위치비교.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-27_중심선과영선의위치비교.png new file mode 100644 index 00000000..00f3caf9 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-27_중심선과영선의위치비교.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-28_경사지임도의영선과기면.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-28_경사지임도의영선과기면.png new file mode 100644 index 00000000..fc13bd6b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-28_경사지임도의영선과기면.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-29_표적판과지지봉.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-29_표적판과지지봉.png new file mode 100644 index 00000000..f1cbd166 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-29_표적판과지지봉.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-30_토우로프.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-30_토우로프.png new file mode 100644 index 00000000..75488458 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-30_토우로프.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-31_개산물매와수정.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-31_개산물매와수정.png new file mode 100644 index 00000000..2e0d65d3 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-31_개산물매와수정.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-32_굴곡부의영선과중심선.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-32_굴곡부의영선과중심선.png new file mode 100644 index 00000000..2ac0e342 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-32_굴곡부의영선과중심선.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-33_능선부와계곡부의종단물매.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-33_능선부와계곡부의종단물매.png new file mode 100644 index 00000000..d7a2a468 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-33_능선부와계곡부의종단물매.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-34_방위각법트래버어스측량.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-34_방위각법트래버어스측량.png new file mode 100644 index 00000000..24395d65 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-34_방위각법트래버어스측량.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-35_편각법트래버어스측량.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-35_편각법트래버어스측량.png new file mode 100644 index 00000000..97a6fe34 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-35_편각법트래버어스측량.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-36_내각법트래버어스측량.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-36_내각법트래버어스측량.png new file mode 100644 index 00000000..8eeb7b41 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-36_내각법트래버어스측량.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-37_트래버어스측정치조건.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-37_트래버어스측정치조건.png new file mode 100644 index 00000000..03c515a4 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-37_트래버어스측정치조건.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_01.png new file mode 100644 index 00000000..ac493210 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_02.png new file mode 100644 index 00000000..4fed8da9 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-38_트래버어스방위각산출_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-39_방위각과방위의관계.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-39_방위각과방위의관계.png new file mode 100644 index 00000000..943f73e3 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-39_방위각과방위의관계.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-40_편각과방위의관계.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-40_편각과방위의관계.png new file mode 100644 index 00000000..63f411e9 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-40_편각과방위의관계.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-41_내각과방위의관계.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-41_내각과방위의관계.png new file mode 100644 index 00000000..242cd40b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-41_내각과방위의관계.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-42_위거와경거의관계.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-42_위거와경거의관계.png new file mode 100644 index 00000000..a3e9f82d Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-42_위거와경거의관계.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_01.png new file mode 100644 index 00000000..d77de968 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_02.png new file mode 100644 index 00000000..e3a2c02e Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-43_곡선의종류_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-44_곡선부의구조.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-44_곡선부의구조.png new file mode 100644 index 00000000..d3a9c5e3 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-44_곡선부의구조.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-45_두절선상교점설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-45_두절선상교점설치법.png new file mode 100644 index 00000000..126d6415 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-45_두절선상교점설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-46_편각에의한곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-46_편각에의한곡선설치법.png new file mode 100644 index 00000000..88acfb75 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-46_편각에의한곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-47_시준선장애물곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-47_시준선장애물곡선설치법.png new file mode 100644 index 00000000..92430abf Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-47_시준선장애물곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-48_교점접근불가곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-48_교점접근불가곡선설치법.png new file mode 100644 index 00000000..89f2cc94 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-48_교점접근불가곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-49_BC와EC장애물곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-49_BC와EC장애물곡선설치법.png new file mode 100644 index 00000000..4c4b6fff Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-49_BC와EC장애물곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-50_중앙종거곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-50_중앙종거곡선설치법.png new file mode 100644 index 00000000..419eba53 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-50_중앙종거곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-51_평행한두직선반향곡선.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-51_평행한두직선반향곡선.png new file mode 100644 index 00000000..74180c8e Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-51_평행한두직선반향곡선.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-52_평행하지않은두직선반향곡선.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-52_평행하지않은두직선반향곡선.png new file mode 100644 index 00000000..45a44ec7 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-52_평행하지않은두직선반향곡선.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-53_복심곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-53_복심곡선설치법.png new file mode 100644 index 00000000..d78de18a Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-53_복심곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-54_배향곡선의간격.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-54_배향곡선의간격.png new file mode 100644 index 00000000..78ac3fb7 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-54_배향곡선의간격.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-55_배향곡선설치법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-55_배향곡선설치법.png new file mode 100644 index 00000000..4b7cfe2f Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-55_배향곡선설치법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-56_종단곡선길이와가시거리.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-56_종단곡선길이와가시거리.png new file mode 100644 index 00000000..dd031f61 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-56_종단곡선길이와가시거리.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-57_종단곡선길이별가시거리.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-57_종단곡선길이별가시거리.png new file mode 100644 index 00000000..024030a3 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-57_종단곡선길이별가시거리.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-58_종단곡선측점종횡거.png b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-58_종단곡선측점종횡거.png new file mode 100644 index 00000000..ac783576 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/노선측량_그림5-2-58_종단곡선측점종횡거.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-1_채석적지부위별명칭.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-1_채석적지부위별명칭.png new file mode 100644 index 00000000..4eda46c2 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-1_채석적지부위별명칭.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-2_주요재료의부호.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-2_주요재료의부호.png new file mode 100644 index 00000000..c3ef5b4f Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-2_주요재료의부호.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_01.png new file mode 100644 index 00000000..c3ba97c9 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_02.png new file mode 100644 index 00000000..83a7b78a Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_03.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_03.png new file mode 100644 index 00000000..8386310e Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-3_주요공종의부호_03.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-4_쇄골재채석장잔벽모형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-4_쇄골재채석장잔벽모형.png new file mode 100644 index 00000000..ed11700b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-4_쇄골재채석장잔벽모형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-5_원석채석장잔벽모형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-5_원석채석장잔벽모형.png new file mode 100644 index 00000000..beb4d9ae Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-5_원석채석장잔벽모형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-6_채석잔벽안정녹화정면도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-6_채석잔벽안정녹화정면도.png new file mode 100644 index 00000000..48a862e7 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-6_채석잔벽안정녹화정면도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-7_채석잔벽안정녹화측면도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-7_채석잔벽안정녹화측면도.png new file mode 100644 index 00000000..7a3433ab Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-7_채석잔벽안정녹화측면도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-8-9_떼단및볏짚단쌓기.png b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-8-9_떼단및볏짚단쌓기.png new file mode 100644 index 00000000..54b58194 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/복구_그림5-3-8-9_떼단및볏짚단쌓기.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-59_합경거와합위거.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-59_합경거와합위거.png new file mode 100644 index 00000000..353b24a0 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-59_합경거와합위거.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-60_탄젠트값트래버어스제도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-60_탄젠트값트래버어스제도.png new file mode 100644 index 00000000..473bed92 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-60_탄젠트값트래버어스제도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-61_삼각함수값트래버어스제도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-61_삼각함수값트래버어스제도.png new file mode 100644 index 00000000..b9f4e54b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-61_삼각함수값트래버어스제도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-62_평면도작성예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-62_평면도작성예.png new file mode 100644 index 00000000..0d67ddd8 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-62_평면도작성예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-63_종단면도작성예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-63_종단면도작성예.png new file mode 100644 index 00000000..48e7c6c4 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-63_종단면도작성예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-64_평면선형과종단선형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-64_평면선형과종단선형.png new file mode 100644 index 00000000..714fe08b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-64_평면선형과종단선형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-66_구조물도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-66_구조물도.png new file mode 100644 index 00000000..4df18b71 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-66_구조물도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-67_표준도작성예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-67_표준도작성예.png new file mode 100644 index 00000000..67876fb2 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-67_표준도작성예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-68_용지도작성예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-68_용지도작성예.png new file mode 100644 index 00000000..aa00ed55 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-68_용지도작성예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-69_사각주의점고.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-69_사각주의점고.png new file mode 100644 index 00000000..fc388b02 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-69_사각주의점고.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-70_Box단면도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-70_Box단면도.png new file mode 100644 index 00000000..ec53b2bc Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-70_Box단면도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-71_유토곡선.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-71_유토곡선.png new file mode 100644 index 00000000..c80b08ac Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-71_유토곡선.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-72_FRNET흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-72_FRNET흐름도.png new file mode 100644 index 00000000..bc6ca0bc Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-72_FRNET흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-73_STmate흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-73_STmate흐름도.png new file mode 100644 index 00000000..5051e5dc Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-73_STmate흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-74_종단면도흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-74_종단면도흐름도.png new file mode 100644 index 00000000..d2e8f24f Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-74_종단면도흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-75_횡단면도흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-75_횡단면도흐름도.png new file mode 100644 index 00000000..d54b1243 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-75_횡단면도흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-76_토적계산흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-76_토적계산흐름도.png new file mode 100644 index 00000000..1bfead59 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-76_토적계산흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-77_내역서흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-77_내역서흐름도.png new file mode 100644 index 00000000..35f6133b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-77_내역서흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-78_Earthwork흐름도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-78_Earthwork흐름도.png new file mode 100644 index 00000000..6030af97 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/설계_그림5-2-78_Earthwork흐름도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-100_개거의종류와모형2.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-100_개거의종류와모형2.png new file mode 100644 index 00000000..0d57ac1b Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-100_개거의종류와모형2.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-101_사면배수시설.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-101_사면배수시설.png new file mode 100644 index 00000000..24daf317 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-101_사면배수시설.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-102_돌망태사용예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-102_돌망태사용예.png new file mode 100644 index 00000000..bc08eb68 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-102_돌망태사용예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-79_본바닥상태와절취사면.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-79_본바닥상태와절취사면.png new file mode 100644 index 00000000..2decd8b0 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-79_본바닥상태와절취사면.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-81_편절토편성토접속횡단면.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-81_편절토편성토접속횡단면.png new file mode 100644 index 00000000..0640fd0c Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-81_편절토편성토접속횡단면.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-82_절토성토접속종단면.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-82_절토성토접속종단면.png new file mode 100644 index 00000000..9b596c01 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-82_절토성토접속종단면.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-84_보조기층두께설계곡선.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-84_보조기층두께설계곡선.png new file mode 100644 index 00000000..94b41f47 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-84_보조기층두께설계곡선.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-85_콘크리트포장줄눈.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-85_콘크리트포장줄눈.png new file mode 100644 index 00000000..e40e1891 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-85_콘크리트포장줄눈.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-86_블록설치방법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-86_블록설치방법.png new file mode 100644 index 00000000..f5ec6a46 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-86_블록설치방법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-87_자갈도시공법.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-87_자갈도시공법.png new file mode 100644 index 00000000..561dce30 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-87_자갈도시공법.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_01.png new file mode 100644 index 00000000..fdaab4c0 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_02.png new file mode 100644 index 00000000..bf7bb72a Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-88_교대와교각구조_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-89_교대의종류.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-89_교대의종류.png new file mode 100644 index 00000000..6d9650e4 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-89_교대의종류.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_01.png new file mode 100644 index 00000000..af89cdd8 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_02.png new file mode 100644 index 00000000..de5cb703 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_03.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_03.png new file mode 100644 index 00000000..7a9a978e Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_03.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_04.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_04.png new file mode 100644 index 00000000..87289c5d Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-90_교각의종류_04.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_01.png new file mode 100644 index 00000000..41da4dae Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_02.png new file mode 100644 index 00000000..251e258d Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_03.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_03.png new file mode 100644 index 00000000..1888d337 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_03.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_04.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_04.png new file mode 100644 index 00000000..f898fe98 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_04.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_05.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_05.png new file mode 100644 index 00000000..602a4bf6 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_05.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_06.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_06.png new file mode 100644 index 00000000..4f3ece95 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_06.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_07.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_07.png new file mode 100644 index 00000000..55d68478 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_07.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_08.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_08.png new file mode 100644 index 00000000..87fcf703 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_08.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_09.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_09.png new file mode 100644 index 00000000..d111ee20 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-91_교량의종류_09.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-92_옹벽의종류.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-92_옹벽의종류.png new file mode 100644 index 00000000..693d124c Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-92_옹벽의종류.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-93_임도배수의종류.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-93_임도배수의종류.png new file mode 100644 index 00000000..18826be1 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-93_임도배수의종류.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-94_막파기측구.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-94_막파기측구.png new file mode 100644 index 00000000..02a676c6 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-94_막파기측구.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-95_붙임측구.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-95_붙임측구.png new file mode 100644 index 00000000..121155bd Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-95_붙임측구.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-96_콘크리트측구.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-96_콘크리트측구.png new file mode 100644 index 00000000..089fe589 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-96_콘크리트측구.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-97_횡단배수구와측구배치.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-97_횡단배수구와측구배치.png new file mode 100644 index 00000000..ac456219 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-97_횡단배수구와측구배치.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-98_암거의모형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-98_암거의모형.png new file mode 100644 index 00000000..8a0f3edc Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-98_암거의모형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-99_개거의종류와모형1.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-99_개거의종류와모형1.png new file mode 100644 index 00000000..50ef21bb Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_그림5-2-99_개거의종류와모형1.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_01.png new file mode 100644 index 00000000..052b2174 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_02.png new file mode 100644 index 00000000..d76a9f29 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_03.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_03.png new file mode 100644 index 00000000..779b1073 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_03.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_04.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_04.png new file mode 100644 index 00000000..04d0248c Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_04.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_05.png b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_05.png new file mode 100644 index 00000000..9a8f43da Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/시공_옹벽하중도_05.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-10_중경사지역의계곡임도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-10_중경사지역의계곡임도.png new file mode 100644 index 00000000..a9e7e894 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-10_중경사지역의계곡임도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-11_편평한주계곡의계곡임도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-11_편평한주계곡의계곡임도.png new file mode 100644 index 00000000..fdb24186 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-11_편평한주계곡의계곡임도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-12_완경사지형의평형노망.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-12_완경사지형의평형노망.png new file mode 100644 index 00000000..609067cc Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-12_완경사지형의평형노망.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-13_급경사긴사면의사행형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-13_급경사긴사면의사행형.png new file mode 100644 index 00000000..dd261810 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-13_급경사긴사면의사행형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-14_능선임도의어골형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-14_능선임도의어골형.png new file mode 100644 index 00000000..dad5df92 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-14_능선임도의어골형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-15_능선임도형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-15_능선임도형.png new file mode 100644 index 00000000..d0daba1c Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-15_능선임도형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-16_산정부순환임도형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-16_산정부순환임도형.png new file mode 100644 index 00000000..7f5c1d47 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-16_산정부순환임도형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-17_계곡분지의순환임도형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-17_계곡분지의순환임도형.png new file mode 100644 index 00000000..5d43a8c1 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-17_계곡분지의순환임도형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-18_반대사면으로부터의임도이용형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-18_반대사면으로부터의임도이용형.png new file mode 100644 index 00000000..dcc96f03 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-18_반대사면으로부터의임도이용형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-19_양각기에의한물매설정.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-19_양각기에의한물매설정.png new file mode 100644 index 00000000..9e2cc557 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-19_양각기에의한물매설정.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-20_양각기사용예.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-20_양각기사용예.png new file mode 100644 index 00000000..c393e8b1 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-20_양각기사용예.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-21_임도망계획도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-21_임도망계획도.png new file mode 100644 index 00000000..22570013 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-21_임도망계획도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-23_노망배치형태별개발지수.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-23_노망배치형태별개발지수.png new file mode 100644 index 00000000..7efa64a1 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-23_노망배치형태별개발지수.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-24_임도운반비의추정도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-24_임도운반비의추정도.png new file mode 100644 index 00000000..32831bd6 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-24_임도운반비의추정도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-7_적정임도가격산출모식도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-7_적정임도가격산출모식도.png new file mode 100644 index 00000000..01a327d7 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-7_적정임도가격산출모식도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-8_ha당임목축적별적정임도밀도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-8_ha당임목축적별적정임도밀도.png new file mode 100644 index 00000000..ab6c9fc2 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-8_ha당임목축적별적정임도밀도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-9_급경사지역의계곡임도.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-9_급경사지역의계곡임도.png new file mode 100644 index 00000000..de004fd8 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도계획_그림5-2-9_급경사지역의계곡임도.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-4_자동차바퀴의구동형.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-4_자동차바퀴의구동형.png new file mode 100644 index 00000000..aecb0063 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-4_자동차바퀴의구동형.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-5_완화구간의형태.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-5_완화구간의형태.png new file mode 100644 index 00000000..89d1cb39 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-5_완화구간의형태.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_01.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_01.png new file mode 100644 index 00000000..854124a4 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_01.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_02.png b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_02.png new file mode 100644 index 00000000..e70cbf50 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/임도구조_그림5-2-6_굴곡부의가시거리확보방법_02.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-1_임도의기능과이용특성.png b/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-1_임도의기능과이용특성.png new file mode 100644 index 00000000..f3ad88f2 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-1_임도의기능과이용특성.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-2_임내생산물의운송체계.png b/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-2_임내생산물의운송체계.png new file mode 100644 index 00000000..d94d82c2 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/pic/총론_그림5-2-2_임내생산물의운송체계.png differ diff --git a/resources/knowledge/original/산림과임업기술(임도)/원본/산림과임업기술(임도).pdf b/resources/knowledge/original/산림과임업기술(임도)/원본/산림과임업기술(임도).pdf new file mode 100644 index 00000000..7f3d2e28 Binary files /dev/null and b/resources/knowledge/original/산림과임업기술(임도)/원본/산림과임업기술(임도).pdf differ diff --git a/ui_template/ui_template_overlay.ts b/ui_template/ui_template_overlay.ts index 607c6093..70c79471 100644 --- a/ui_template/ui_template_overlay.ts +++ b/ui_template/ui_template_overlay.ts @@ -2,7 +2,9 @@ import "./ui_template_overlay.css"; import { CURRENT_PROJECT_ID_KEY } from "@config/config_frontend"; import { t } from "./ui_template_locale"; import { makePanelDraggable } from "./ui_template_overlay_drag"; -import { fetchProjectWorkflowState } from "../B01_Dashboard/B01_Dashboard_Api_Fetch"; +// 워크플로 상태는 공용 창구 하나로 받는다 — 화면마다 따로 부르면 진입에서 같은 답을 +// 두 번 받는다(2026-09-06 실측). 그 창구가 짧은 시간 동안 캐시한다. +import { fetchWorkflowState } from "../A00_Common/b_workflow_nav"; const TITLE_OVERLAY_STATE_KEY = "frd_workflow_title_overlay_open"; const PROGRESS_OVERLAY_STATE_KEY = "frd_workflow_progress_overlay_open"; @@ -124,7 +126,7 @@ function createProjectNameTag(): HTMLElement { tag.className = "ui-workflow-overlay__project"; const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY); if (!projectId) return tag; - void fetchProjectWorkflowState(projectId) + void fetchWorkflowState(projectId) .then((state) => { const name = state.project_name ?? ""; tag.textContent = name;