fix: rebind imported experiments to active inputs
This commit is contained in:
@@ -27,7 +27,7 @@ DAS·DAS-PHAT·GCC-PHAT 위치추정으로 주파수 대역별 acoustic map과 g
|
||||
|
||||
## 사용자 입력 불러오기
|
||||
|
||||
문서는 다음 순서로 불러오는 것이 안전합니다.
|
||||
문서는 다음 순서로 불러오면 asset 연결까지 한 번에 확인하기 쉽습니다.
|
||||
|
||||
1. **Scene**: `.scene.json`
|
||||
2. **Array**: 선택 사항인 `.array.json`; 또는 **비교 배열** preset 사용
|
||||
@@ -35,8 +35,11 @@ DAS·DAS-PHAT·GCC-PHAT 위치추정으로 주파수 대역별 acoustic map과 g
|
||||
4. **Assets**: Scene이 참조하는 원본 이미지와 오디오
|
||||
|
||||
Scene을 불러오면 현재 Experiment의 `sceneId`와 scan plane을 Scene에 맞추고 기존 asset 연결을
|
||||
해제합니다. Array를 불러오면 현재 Experiment의 `arrayId`를 맞춥니다. 별도 Experiment는 현재
|
||||
Scene과 Array를 참조해야 하므로 마지막에 불러오세요.
|
||||
해제합니다. Array를 불러오면 현재 Experiment의 `arrayId`를 맞춥니다. 별도 Experiment는 어느
|
||||
시점에 불러와도 문서 자체를 먼저 검증한 뒤 `sceneId`와 `arrayId`를 현재 열린 Scene·Array에
|
||||
자동으로 연결합니다. 이후 현재 입력을 기준으로 관계 검증을 다시 수행하므로 원래 참조 ID가 달라도
|
||||
연결 대기로 실행이 막히지 않으며, 모든 분석 대역은 보존됩니다. Nyquist·scan 같은 실제 관계 오류는
|
||||
그대로 거부됩니다.
|
||||
|
||||
Scene JSON에는 원본 파일 byte가 없습니다. **Assets**에서 Builder에 사용한 파일을 다시 선택하면
|
||||
Camera가 SHA-256을 계산해 manifest에 연결합니다. 같은 이름이라도 내용이 바뀌면 거절됩니다.
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="workspace-tools input-file-grid" aria-label="입력 파일">
|
||||
<label class="file-button file-choice" title="Scene JSON을 선택하세요."><span class="file-sequence">1</span><span><strong>Scene</strong><small>장면·음원</small></span><input id="scene-input" type="file" accept="application/json,.json" /></label>
|
||||
<label class="file-button file-choice" title="사용자 배열이 있을 때 Array JSON을 선택하세요."><span class="file-sequence">2</span><span><strong>Array</strong><small>마이크 배열</small></span><input id="array-input" type="file" accept="application/json,.json" /></label>
|
||||
<label class="file-button file-choice" title="Experiment를 먼저 열 수 있습니다. 참조 ID가 다른 동안에는 실행만 비활성화됩니다."><span class="file-sequence">3</span><span><strong>Experiment</strong><small>분석 설정 · 선로드 가능</small></span><input id="experiment-input" type="file" accept="application/json,.json" /></label>
|
||||
<label class="file-button file-choice" title="Experiment를 먼저 열 수 있습니다. sceneId와 arrayId는 현재 열린 Scene·Array에 자동으로 연결됩니다."><span class="file-sequence">3</span><span><strong>Experiment</strong><small>분석 설정 · ID 자동 연결</small></span><input id="experiment-input" type="file" accept="application/json,.json" /></label>
|
||||
<label class="file-button file-choice" title="Scene에 사용한 원본 파일을 다시 선택하세요."><span class="file-sequence">4</span><span><strong>Assets</strong><small>오디오·이미지</small></span><input id="asset-input" type="file" accept="audio/*,image/*,.wav,.flac,.mp3,.ogg,.m4a,.png,.jpg,.jpeg,.webp,.svg" multiple /></label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1568,16 +1568,30 @@ async function importDocument(kind, input) {
|
||||
try {
|
||||
const value = await readJsonFile(file);
|
||||
if (generation !== state.importGenerations[kind]) return;
|
||||
let importedExperimentReferences = null;
|
||||
let issues;
|
||||
if (kind === "array") {
|
||||
issues = await validateArrayDefinition(value);
|
||||
} else if (kind === "scene") {
|
||||
issues = await validateScene(value);
|
||||
} else {
|
||||
// An Experiment is a useful editable document even before its referenced
|
||||
// Scene or Array has been loaded. Validate its own contract here, then let
|
||||
// validateCurrent() keep Run disabled until the document IDs line up.
|
||||
// Validate the imported document independently before changing any
|
||||
// references. Then bind it to the open workspace and run the relationship
|
||||
// checks as well, so import convenience does not weaken the contract.
|
||||
issues = await validateExperiment(value);
|
||||
if (generation !== state.importGenerations[kind]) return;
|
||||
if (issues.length === 0) {
|
||||
importedExperimentReferences = {
|
||||
sceneId: value.sceneId,
|
||||
arrayId: value.arrayId,
|
||||
};
|
||||
value.sceneId = state.scene.id;
|
||||
value.arrayId = state.arrayDefinition.id;
|
||||
issues = await validateExperiment(value, {
|
||||
arrayDefinition: state.arrayDefinition,
|
||||
scene: state.scene,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (generation !== state.importGenerations[kind]) return;
|
||||
if (issues.length > 0) throw new Error(issues.slice(0, 4).map(formatIssue).join(" · "));
|
||||
@@ -1606,14 +1620,14 @@ async function importDocument(kind, input) {
|
||||
: kind === "experiment"
|
||||
? ` · 분석 대역 ${state.experiment.frequencyBands.length}개`
|
||||
: "";
|
||||
const pendingReferences = kind === "experiment"
|
||||
? [
|
||||
value.sceneId !== state.scene?.id ? `Scene ${value.sceneId}` : null,
|
||||
value.arrayId !== state.arrayDefinition?.id ? `Array ${value.arrayId}` : null,
|
||||
].filter(Boolean)
|
||||
: [];
|
||||
const referenceStatus = pendingReferences.length > 0
|
||||
? ` · ${pendingReferences.join(" · ")} 연결 대기`
|
||||
const referencesChanged = kind === "experiment" && (
|
||||
importedExperimentReferences?.sceneId !== state.scene.id ||
|
||||
importedExperimentReferences?.arrayId !== state.arrayDefinition.id
|
||||
);
|
||||
const referenceStatus = kind === "experiment"
|
||||
? referencesChanged
|
||||
? ` · 현재 Scene ${state.scene.id} · Array ${state.arrayDefinition.id}로 재연결`
|
||||
: " · 현재 Scene · Array 연결 확인"
|
||||
: "";
|
||||
setRunStatus(`${file.name} ${kind} 문서를 불러왔습니다.${bandStatus}${referenceStatus}`);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user