best version

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-17 15:06:51 +03:00
co-authored by Cursor
parent 4f253b860f
commit 643d834ba7
5 changed files with 310 additions and 289 deletions
+2
View File
@@ -294,6 +294,7 @@ export const api = {
seed = 42,
outputDir = "sonar_dataset",
objectScale = 1,
objectScaleIsMax = false,
beamCount = 45,
lengthCount = 45,
modelFile,
@@ -306,6 +307,7 @@ export const api = {
formData.append("seed", String(seed));
formData.append("outputDir", outputDir || "sonar_dataset");
formData.append("objectScale", String(objectScale ?? 1));
formData.append("objectScaleIsMax", objectScaleIsMax ? "true" : "false");
formData.append("beamCount", String(beamCount ?? 45));
formData.append("lengthCount", String(lengthCount ?? 45));
formData.append("model", modelFile, modelFile.name || "model.obj");
+10 -3
View File
@@ -13,6 +13,7 @@ export const useDatasetStore = defineStore("dataset", {
modelFile: null,
modelFileName: "",
objectScale: 1,
objectScaleIsMax: false,
beamCount: 45,
lengthCount: 45,
lastResult: null,
@@ -117,7 +118,7 @@ export const useDatasetStore = defineStore("dataset", {
this.busy = true;
this.statusText = "Генерация датасета…";
this.pushLog(
`Старт: count=${this.count}, seed=${this.seed}, beams=${this.beamCount}, length=${this.lengthCount}, scale=${this.objectScale}, dir=${this.outputDir}, model=${this.modelFileName}`,
`Старт: count=${this.count}, seed=${this.seed}, beams=${this.beamCount}, length=${this.lengthCount}, scale=${this.objectScale}${this.objectScaleIsMax ? " (макс.)" : ""}, dir=${this.outputDir}, model=${this.modelFileName}`,
);
try {
const result = await api.datasetGenerate({
@@ -125,6 +126,7 @@ export const useDatasetStore = defineStore("dataset", {
seed: Number(this.seed) || 0,
outputDir: String(this.outputDir || "sonar_dataset"),
objectScale: Number(this.objectScale) || 1,
objectScaleIsMax: !!this.objectScaleIsMax,
beamCount: Number(this.beamCount) || 45,
lengthCount: Number(this.lengthCount) || 45,
modelFile: this.modelFile,
@@ -133,8 +135,11 @@ export const useDatasetStore = defineStore("dataset", {
this.resolvedOutputDir = result?.outputDir || null;
const s = result?.stats || {};
this.statusText = `Готово: ${result.count} сцен → ${result.outputDir}`;
const scaleNote = result.objectScaleIsMax
? `scale=1…${result.objectScale ?? this.objectScale} (макс.)`
: `scale=${result.objectScale ?? this.objectScale}`;
this.pushLog(
`Модель: ${result.objectName || this.modelFileName} (${result.objectVertexCount || "?"} вершин), scale=${result.objectScale ?? this.objectScale}, ширина=${result.beamCount ?? this.beamCount}, длина=${result.lengthCount ?? this.lengthCount}. class 1 = object.`,
`Модель: ${result.objectName || this.modelFileName} (${result.objectVertexCount || "?"} вершин), ${scaleNote}, ширина=${result.beamCount ?? this.beamCount}, длина=${result.lengthCount ?? this.lengthCount}. class 1 = object.`,
);
this.pushLog(
`Записано ${result.count} сцен. С объектом: ${s.withObject}, без: ${s.withoutObject}.`,
@@ -143,8 +148,10 @@ export const useDatasetStore = defineStore("dataset", {
`Видимость: nearly_hidden=${s.nearly_hidden || 0}, partial=${s.partial || 0}, visible=${s.visible || 0}, absent=${s.absent || 0}.`,
);
for (const item of result.written || []) {
const scalePart =
item.objectScale != null ? `, scale=${Number(item.objectScale).toFixed(3)}` : "";
this.pushLog(
`${item.stem}: pts=${item.pointCount}, object=${item.objectPointCount}, ${item.visibility}`,
`${item.stem}: pts=${item.pointCount}, object=${item.objectPointCount}, ${item.visibility}${scalePart}`,
);
}
+77 -12
View File
@@ -119,7 +119,17 @@ function onHighlightClassChange(event) {
</label>
<label class="field">
<span>Относительный масштаб объекта</span>
<span class="field-label-row">
<span>Относительный масштаб объекта</span>
<label class="check-inline" title="Верхняя граница: для каждой сцены масштаб случайный от 1 до заданного значения">
<input
v-model="store.objectScaleIsMax"
type="checkbox"
:disabled="store.busy"
/>
макс.
</label>
</span>
<input
v-model.number="store.objectScale"
type="number"
@@ -128,7 +138,14 @@ function onHighlightClassChange(event) {
step="0.05"
:disabled="store.busy"
/>
<span class="ref-caption">1.0 = размер после нормализации mesh; &gt;1 увеличивает объект</span>
<span class="ref-caption">
<template v-if="store.objectScaleIsMax">
Верхняя граница: для каждой сцены масштаб случайно из [1 значение] (имитация разной высоты АНПА).
</template>
<template v-else>
1.0 = размер после нормализации mesh; &gt;1 увеличивает объект
</template>
</span>
</label>
<label class="field">
@@ -142,7 +159,7 @@ function onHighlightClassChange(event) {
:disabled="store.busy"
/>
<span class="ref-caption">
Ширина рельефа (X): N лучей = N точек по ширине сетки дна.
Поперечные лучи эхолота (X): N лучей = N возвратов по ширине галса.
</span>
</label>
@@ -157,7 +174,7 @@ function onHighlightClassChange(event) {
:disabled="store.busy"
/>
<span class="ref-caption">
Длина рельефа (Y): L = число точек по длине сетки дна.
Пинги вдоль курса (Y): L возвратов по длине. Итого точек сцены: N×L (первый отклик луча).
</span>
</label>
@@ -283,12 +300,23 @@ function onHighlightClassChange(event) {
<style scoped>
.dataset-layout {
grid-template-columns: 320px minmax(0, 1fr);
align-items: stretch;
height: calc(100vh - 56px);
min-height: 0;
max-height: calc(100vh - 56px);
overflow: hidden;
gap: 12px;
padding: 12px;
}
.dataset-sidebar {
width: 320px;
max-width: 100%;
overflow: auto;
width: auto;
max-width: none;
height: 100%;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
align-content: start;
}
.panel {
padding: 14px 16px 20px;
@@ -338,6 +366,27 @@ function onHighlightClassChange(event) {
gap: 4px;
font-size: 13px;
}
.field-label-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.check-inline {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: var(--muted-text);
cursor: pointer;
user-select: none;
white-space: nowrap;
}
.check-inline input {
width: auto;
margin: 0;
accent-color: var(--chain-selected-border, #6ea8ff);
}
.field input,
.field select {
padding: 6px 8px;
@@ -424,17 +473,19 @@ function onHighlightClassChange(event) {
font-size: 11px;
}
.dataset-content {
min-height: 0;
height: calc(100vh - 76px);
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 12px 12px 0;
min-width: 0;
min-height: 0;
height: 100%;
overflow: hidden;
padding: 0;
}
.viewer-wrap {
position: relative;
flex: 1;
min-height: 280px;
flex: 1 1 auto;
min-height: 0;
border: 1px solid var(--header-border);
border-radius: var(--radius-sm, 6px);
overflow: hidden;
@@ -456,6 +507,7 @@ function onHighlightClassChange(event) {
}
.log-panel {
flex: 0 0 140px;
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
@@ -466,10 +518,23 @@ function onHighlightClassChange(event) {
.log {
margin: 0;
flex: 1;
min-height: 0;
overflow: auto;
font-size: 11px;
line-height: 1.35;
white-space: pre-wrap;
color: var(--muted-text);
}
@media (max-width: 1100px) {
.dataset-layout {
grid-template-columns: 1fr;
grid-template-rows: minmax(200px, 36vh) minmax(0, 1fr);
height: calc(100vh - 56px);
max-height: calc(100vh - 56px);
}
.dataset-sidebar {
height: 100%;
}
}
</style>