Merge remote-tracking branches 'origin/sub_laptop_1' and 'origin/sub_laptop_3' into main_laptop_1

This commit is contained in:
2026-10-17 22:21:29 +09:00
5 changed files with 80 additions and 10 deletions
+1 -1
View File
@@ -120,7 +120,7 @@ const apply = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Ap
}),
changed: () => changed,
terrain: () => "sheet",
stationSnap: () => true,
snap: () => ({ stationSnap: true, stationSnapStep: 20 }), // 390-5 — 켬끔 · 간격 한 벌
initial: { current: () => ({ mode: "follow" }), keep: () => (kept += 1) },
onApplied: () => (rebuilt += 1),
});
@@ -134,6 +134,7 @@ const types = [
{ type_id: "box", name: "BOX", style: { color: "#e11d48" } },
{ type_id: "pipe", name: "배수관", style: { color: "#2563eb" } },
];
let lag = false;
const selects = [];
const moves = [];
let redrawn = 0;
@@ -142,20 +143,35 @@ marks.setPlanMarkSource("p1", {
types: () => types,
intervalM: () => 20,
select: (id) => selects.push(id),
move: (id, to) => moves.push([id, to]),
// 옮김 = 알약 목록이 그 자리로(`lag` 면 늦게 옴 — 관 목록)
move: (id, to) => {
moves.push([id, to]);
if (!lag) structures.find((s) => s.structure_id === id).chainage_m = to;
},
});
const canvas = { isConnected: true, parentElement: parent };
let line = EAST;
let picked = -1;
const status = { textContent: "" };
const scene = () => ({ toScreen, view: { width: 400, height: 300 }, rotationRad: 0 });
const scene = () => ({
toScreen,
pxPerMeter: 2,
view: { width: 400, height: 300 },
rotationRad: 0,
});
const style = { getPropertyValue: () => "" };
const draw = () => {
const fake = fakeContext(canvas);
marks.drawStructureMarks(fake.ctx, scene(), line, style);
return fake.log;
};
/** 한 걸음 판정 뒤 — 그려서 기다림을 풀고 처음 자리로. */
const settle = () => {
draw();
structures[0].chainage_m = 40;
structures[1].chainage_m = 80.17;
};
const input = marks.bindStructureMarks(
{
canvas,
@@ -213,16 +229,19 @@ out.dragStatus = status.textContent;
out.movesBeforeRelease = moves.length;
input.release();
out.dragMove = moves[moves.length - 1];
settle();
out.dragDoneStatus = status.textContent;
// 노선 밖 — 끝(200) · 시점(0)에 붙음
input.press(80, 0);
input.move(9999, 0);
input.release();
out.pastEnd = moves[moves.length - 1];
settle();
input.press(80, 0);
input.move(-500, 0);
input.release();
out.beforeStart = moves[moves.length - 1];
settle();
// 옛 소수 관(80.17) — 눌렀다 반올림 자리에서 떼면 안 옮김 · 1 m 끌면 정수
const count = moves.length;
input.press(160.34, 0);
@@ -233,18 +252,22 @@ input.press(160.34, 0);
input.move(162.2, 0);
input.release();
out.oldDecimalMoved = moves[moves.length - 1];
settle();
// ④ 방향키 — 고른 마커(A) · 교각점 안 고름 = 노선 따라 1 m · 뗄 때 한 번
selection = { chainageM: 40, structureId: "A" };
key("keydown", "ArrowRight");
key("keyup", "ArrowRight");
out.keyRight = moves[moves.length - 1];
settle();
key("keydown", "ArrowLeft");
key("keyup", "ArrowLeft");
out.keyLeft = moves[moves.length - 1];
settle();
key("keydown", "ArrowUp"); // 노선과 직각 = → · ↑ 는 +
key("keyup", "ArrowUp");
out.keyUpPerpendicular = moves[moves.length - 1];
settle();
// 서→동이 아니라 동→서 노선 — 오른쪽(동) = 뒤로
line = [
[200, 0],
@@ -253,7 +276,27 @@ line = [
key("keydown", "ArrowRight");
key("keyup", "ArrowRight");
out.keyRightWestward = moves[moves.length - 1];
settle();
line = EAST;
// 관 목록이 늦게 옴 — 연달아 두 번 눌러도 두 걸음(옮긴 자리 · 고름을 목록이 따라올 때까지 쥠)
lag = true;
selection = { chainageM: 80.17, structureId: null };
key("keydown", "ArrowRight");
key("keyup", "ArrowRight");
selection = { chainageM: 81, structureId: null }; // 관 고름이 새 자리로(followMovedPipe)
const heldLog = draw();
out.lagHeldAt = heldLog.filter((s) => s.width === 15).map((s) => s.at);
key("keydown", "ArrowRight");
key("keyup", "ArrowRight");
out.lagTwoSteps = moves.slice(-2);
lag = false;
structures[1].chainage_m = 82; // 목록이 따라옴
selection = { chainageM: 82, structureId: null };
out.lagCaught = draw()
.filter((s) => s.width === 15)
.map((s) => s.at);
settle();
selection = { chainageM: 40, structureId: "A" };
// 교각점 고름 = 교각점 방향키 몫(마커 안 옮김)
picked = 2;
const before = moves.length;
@@ -49,6 +49,7 @@ def test_초안은_계약_RouteDraft_꼴(out):
"curveLock",
"curveArc",
"stationSnap",
"stationSnapStep",
"terrain",
}
n = len(draft["nodes"])
@@ -57,6 +58,7 @@ def test_초안은_계약_RouteDraft_꼴(out):
)
assert draft["curveOn"] == [True, False, True] and draft["curveRadius"] == [None, 25, None]
assert draft["stationSnap"] is True and draft["terrain"] == "sheet"
assert draft["stationSnapStep"] == 20 # 390-5 간격도 함께 실림
assert out["body"]["initial"] == {"mode": "follow"}
assert "balanced_profile" not in out["body"] # 손으로 고친 노선 = 계획고 옮김만(349-0v)
assert "as_initial" not in out["body"] # 손으로 고친 노선 = 초기값 그대로
@@ -102,6 +102,12 @@ def test_방향키_노선_따라_1m(got) -> None:
assert got["keyUpPerpendicular"] == ["A", 41] # 직각 = → · ↑ 가 +
assert got["keyRightWestward"] == ["A", 39] # 노선이 서쪽으로 가면 → = 뒤로
assert got["keyWithNodePicked"] == 0 # 교각점 고름 = 교각점 방향키 몫
def test_관_목록이_늦게_와도_연달아_두_걸음(got) -> None:
assert got["lagHeldAt"] == [[162, 0]] # 옮긴 자리 · 고름 그대로(목록은 아직 80.17)
assert got["lagTwoSteps"] == [["pipe-80.17", 81], ["pipe-80.17", 82]]
assert got["lagCaught"] == [[164, 0]] # 목록이 따라오면 목록 자리
assert got["keyNoPick"] == 0