This commit is contained in:
2026-07-19 11:36:25 +09:00
parent db817b940a
commit e18753416f
7 changed files with 106 additions and 46 deletions
+16 -5
View File
@@ -1,6 +1,10 @@
.b03-file {
min-height: calc(100vh - var(--app-header-height, 0px));
background: linear-gradient(180deg, var(--color-canvas, #ffffff) 0%, var(--color-mist-violet, #edecff) 100%);
background: linear-gradient(
180deg,
var(--color-canvas, #ffffff) 0%,
var(--color-mist-violet, #edecff) 100%
);
padding: 0 var(--spacing-24) var(--spacing-48) var(--spacing-24); /* 상단 여백은 main-layout 마진으로 조정하므로 padding-top은 0 */
}
@@ -52,7 +56,10 @@
gap: var(--spacing-8);
cursor: pointer;
text-align: center;
transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s);
transition:
background var(--transition-base, 0.2s),
border-color var(--transition-base, 0.2s),
box-shadow var(--transition-base, 0.2s);
}
.b03-file__dropzone:hover {
@@ -140,7 +147,10 @@
display: flex;
flex-direction: column;
gap: var(--spacing-20);
transition: transform var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s);
transition:
transform var(--transition-base, 0.2s),
border-color var(--transition-base, 0.2s),
box-shadow var(--transition-base, 0.2s);
}
.b03-file__card:hover {
@@ -258,7 +268,9 @@
font-size: var(--text-body-sm, 14px);
cursor: pointer;
margin-bottom: var(--spacing-8); /* 파일 선택 버튼 하단 마진 추가 */
transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s);
transition:
background var(--transition-base, 0.2s),
border-color var(--transition-base, 0.2s);
}
.b03-file__file-info {
@@ -373,4 +385,3 @@
grid-template-columns: 1fr; /* 모바일에서는 1행 1열 구조 */
}
}
@@ -10,6 +10,7 @@ import { createWorkflowPanelHandle } from "@ui/ui_template_overlay";
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style.css";
const COLLAPSED_KEY = "b05-route-profile-collapsed";
const HORIZONTAL_SCROLLBAR_HEIGHT = 16;
function normalizedLongitudinal(data: LongitudinalSection): LongitudinalSection {
return {
@@ -43,11 +44,9 @@ export function createRouteProfilePanel(onSelectStation: (stationId: string) =>
function draw(): void {
if (!detail || body.clientWidth <= 0 || body.clientHeight <= 0) return;
const availableWidth = Math.max(1, body.clientWidth - 30);
const height = body.clientHeight;
const width = Math.max(
availableWidth,
longitudinalMinimumWidth(detail.longitudinal, stationInterval),
);
const height = Math.max(1, body.clientHeight - HORIZONTAL_SCROLLBAR_HEIGHT);
const minimumWidth = longitudinalMinimumWidth(detail.longitudinal, stationInterval);
const width = Math.max(availableWidth, minimumWidth);
lastWidth = body.clientWidth;
lastHeight = height;
body.replaceChildren(
@@ -60,6 +59,7 @@ export function createRouteProfilePanel(onSelectStation: (stationId: string) =>
stationInterval,
width,
height,
minimumWidth,
),
);
}
@@ -11,6 +11,8 @@ const LONG_WIDTH = 1200;
const LONG_HEIGHT = 220;
const CROSS_WIDTH = 560;
const CROSS_HEIGHT = 250;
const CROSS_GRID_MIN_WIDTH = 480;
const CROSS_GRID_GAP = 16;
const LONG_PAD = { left: 62, right: 24, top: 30, bottom: 52 };
const CROSS_PAD = { left: 58, right: 20, top: 20, bottom: 52 };
@@ -119,6 +121,7 @@ export function createLongitudinalProfile(
configuredStationInterval?: number,
widthPx = LONG_WIDTH,
heightPx = LONG_HEIGHT,
minimumWidthPx = widthPx,
): HTMLElement {
const samples = data.samples.filter(validElevation);
if (samples.length < 2) return emptyView(L("B06_Profile_View_NoLongitudinal"));
@@ -133,6 +136,8 @@ export function createLongitudinalProfile(
role: "img",
"aria-label": L("B06_Profile_View_Longitudinal"),
});
svg.style.width = "100%";
svg.style.minWidth = `${minimumWidthPx}px`;
svg.append(svgElement("rect", { width: widthPx, height: heightPx, class: "b06-chart__bg" }));
const maxChainage = Math.max(data.length_m, samples[samples.length - 1]?.chainage_m ?? 1, 1);
@@ -499,6 +504,7 @@ export function createSectionView(): SectionViewController {
const longitudinalPanel = document.createElement("section");
longitudinalPanel.className = "b06-section__panel";
const longitudinalMinWidth = longitudinalMinimumWidth(detail.longitudinal, stationInterval);
longitudinalPanel.append(
createLongitudinalProfile(
detail.longitudinal,
@@ -507,8 +513,9 @@ export function createSectionView(): SectionViewController {
yScale,
(stationId) => selectStation(stationId, true),
stationInterval,
Math.max(renderWidth, longitudinalMinimumWidth(detail.longitudinal, stationInterval)),
Math.max(renderWidth, longitudinalMinWidth),
LONG_HEIGHT,
longitudinalMinWidth,
),
);
@@ -521,8 +528,11 @@ export function createSectionView(): SectionViewController {
crossHeading.append(crossTitle, crossCount);
const grid = document.createElement("div");
grid.className = "b06-section__grid";
const columnCount = renderWidth >= 976 ? 2 : 1;
const cardWidth = (renderWidth - (columnCount - 1) * 16) / columnCount;
const columnCount = Math.max(
1,
Math.floor((renderWidth + CROSS_GRID_GAP) / (CROSS_GRID_MIN_WIDTH + CROSS_GRID_GAP)),
);
const cardWidth = (renderWidth - (columnCount - 1) * CROSS_GRID_GAP) / columnCount;
if (detail.cross_sections.length) {
detail.cross_sections.forEach((section) =>
grid.append(
@@ -182,6 +182,10 @@
max-width: none;
}
.b06-cross-card > .b06-section__chart {
width: 100%;
}
.b06-section__heading {
display: flex;
align-items: end;
+37 -13
View File
@@ -1,20 +1,27 @@
import sys
import os
from pathlib import Path
# Add project root to sys.path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from B03_FileInput.B03_FileInput_Engine_Analyze import (
analyze_las_metadata,
analyze_prj_metadata,
analyze_tif_metadata,
analyze_las_metadata,
)
BASE_DIR = Path("D:/02_Software_Prog/임도설계 및 견적자동화 프로그램 개발")
PRJ_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/prj/result.prj"
TIF_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/tif/result.tif"
LAS_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/las/cloud_merged.las"
PRJ_PATH = (
BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/prj/result.prj"
)
TIF_PATH = (
BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/tif/result.tif"
)
LAS_PATH = (
BASE_DIR
/ "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/las/cloud_merged.las"
)
def run_tests():
print("--- 1. Testing PRJ Metadata Extraction ---")
@@ -25,10 +32,18 @@ def run_tests():
print(f" {k}: {v}")
# Assertions based on PLAN.md expectations
assert prj_meta.get("epsg") == 5187, f"Expected horizontal EPSG to be 5187, got {prj_meta.get('epsg')}"
assert prj_meta.get("crs_status") == "custom_vertical_crs", f"Expected custom_vertical_crs, got {prj_meta.get('crs_status')}"
assert prj_meta.get("vertical_crs") is not None, "Expected vertical_crs metadata to be present"
assert "KNGeoid24" in prj_meta["vertical_crs"]["name"], f"Expected KNGeoid24 in vertical crs name, got {prj_meta['vertical_crs']['name']}"
assert prj_meta.get("epsg") == 5187, (
f"Expected horizontal EPSG to be 5187, got {prj_meta.get('epsg')}"
)
assert prj_meta.get("crs_status") == "custom_vertical_crs", (
f"Expected custom_vertical_crs, got {prj_meta.get('crs_status')}"
)
assert prj_meta.get("vertical_crs") is not None, (
"Expected vertical_crs metadata to be present"
)
assert "KNGeoid24" in prj_meta["vertical_crs"]["name"], (
f"Expected KNGeoid24 in vertical crs name, got {prj_meta['vertical_crs']['name']}"
)
print("PRJ test passed successfully.")
else:
print(f"PRJ file not found at {PRJ_PATH}")
@@ -41,7 +56,9 @@ def run_tests():
print(f" {k}: {v}")
assert tif_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {tif_meta.get('epsg')}"
assert tif_meta.get("crs_status") == "identified", f"Expected identified, got {tif_meta.get('crs_status')}"
assert tif_meta.get("crs_status") == "identified", (
f"Expected identified, got {tif_meta.get('crs_status')}"
)
assert tif_meta.get("vertical_crs") is None, "Expected no vertical crs for TIF file"
print("TIF test passed successfully.")
else:
@@ -59,12 +76,19 @@ def run_tests():
print(f" {k}: {v}")
assert las_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {las_meta.get('epsg')}"
assert las_meta.get("crs_status") == "custom_vertical_crs", f"Expected custom_vertical_crs, got {las_meta.get('crs_status')}"
assert las_meta.get("vertical_crs") is not None, "Expected vertical_crs metadata to be present"
assert "KNGeoid24" in las_meta["vertical_crs"]["name"], f"Expected KNGeoid24 in vertical crs name, got {las_meta['vertical_crs']['name']}"
assert las_meta.get("crs_status") == "custom_vertical_crs", (
f"Expected custom_vertical_crs, got {las_meta.get('crs_status')}"
)
assert las_meta.get("vertical_crs") is not None, (
"Expected vertical_crs metadata to be present"
)
assert "KNGeoid24" in las_meta["vertical_crs"]["name"], (
f"Expected KNGeoid24 in vertical crs name, got {las_meta['vertical_crs']['name']}"
)
print("LAS test passed successfully.")
else:
print(f"LAS file not found at {LAS_PATH}")
if __name__ == "__main__":
run_tests()
+16 -5
View File
@@ -63,9 +63,13 @@ for rel_path, abs_path in list(all_wiki_files.items()):
else:
status = status_match.group(1).strip()
if status not in ["draft", "stable", "stale"]:
errors.append(f"[Status] `{rel_path}.md` has invalid status '{status}'. Must be draft, stable, or stale.")
errors.append(
f"[Status] `{rel_path}.md` has invalid status '{status}'. Must be draft, stable, or stale."
)
elif status == "stale":
warnings.append(f"[Stale Page] `{rel_path}.md` is marked as stale and needs updates from raw inputs.")
warnings.append(
f"[Stale Page] `{rel_path}.md` is marked as stale and needs updates from raw inputs."
)
# Rule 5: page_id required for pages/
if "pages/" in rel_path:
@@ -75,7 +79,9 @@ for rel_path, abs_path in list(all_wiki_files.items()):
# Check for broken wikilinks in content
links = wikilink_pat.findall(content)
for link in links:
link_clean = link.strip().replace("\\", "/").split("#")[0] # ignore anchor for file existence check
link_clean = (
link.strip().replace("\\", "/").split("#")[0]
) # ignore anchor for file existence check
if not link_clean:
continue
found = False
@@ -108,8 +114,13 @@ for rel_path, abs_path in list(all_wiki_files.items()):
if file_name_no_ext not in index_content:
# check if relative path is in index
rel_path_no_ext = rel_path.replace(".md", "")
if rel_path_no_ext not in index_content and rel_path_no_ext.split("/")[-1] not in index_content:
warnings.append(f"[Orphan Page] `{rel_path}.md` is not linked or mentioned in index.md.")
if (
rel_path_no_ext not in index_content
and rel_path_no_ext.split("/")[-1] not in index_content
):
warnings.append(
f"[Orphan Page] `{rel_path}.md` is not linked or mentioned in index.md."
)
print("=== LINT ERRORS ===")
for e in sorted(list(set(errors))):