From 42be74328c8920397084427e6fdc5ee2495ea973 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 5 Mar 2026 20:47:28 +0000 Subject: [PATCH] SAR Search Pattern Update --- README.md | 2 +- server/routes/simulations.go | 5 +- src/lib/SimulationSidebar.svelte | 1 + src/lib/SimulationTable.svelte | 102 +- src/lib/simulationState.svelte.ts | 1 + src/routes/simulation/[id]/+page.svelte | 1062 ++++++++--------- src/routes/simulation/[id]/print/+page.svelte | 620 +++++----- 7 files changed, 865 insertions(+), 928 deletions(-) diff --git a/README.md b/README.md index c7f4366..803ba51 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Returns a JSON array of all indexed simulations, including their ID, name, creat ### `POST /api/simulations/create` Creates a new simulation entry. -- **Request Body:** JSON object containing the combined configurations (e.g., `search`, `uav`, `ugv`). The configuration *must* contain at least one search pattern definition (either `spiral`, `lawnmower`, or `levy`) inside the JSON. +- **Request Body:** JSON object containing the combined configurations (e.g., `search`, `uav`, `ugv`). The configuration *must* contain at least one search pattern definition (either `spiral`, `lawnmower`, `levy`, or `sar`) inside the JSON. - **Behavior:** Checks if an identical config exists. If so, it returns the existing simulation ID/Name for overwriting. If not, it allocates a new `simulation_X` incrementally, inserts it into the database, builds the file directory in `../results`, and returns the new ID/Name. Returns `400 Bad Request` if payload is not valid JSON or lacks a known search pattern. - **Response:** JSON object `{"id": , "name": }` diff --git a/server/routes/simulations.go b/server/routes/simulations.go index a9ca387..ed148e8 100644 --- a/server/routes/simulations.go +++ b/server/routes/simulations.go @@ -48,12 +48,15 @@ func (rt *Router) CreateSimulation(w http.ResponseWriter, r *http.Request) { if _, ok := searchMap["levy"]; ok { hasPattern = true } + if _, ok := searchMap["sar"]; ok { + hasPattern = true + } } } } if !hasPattern { - http.Error(w, "Simulation configuration must include a search pattern (spiral, lawnmower, or levy)", http.StatusBadRequest) + http.Error(w, "Simulation configuration must include a search pattern (spiral, lawnmower, levy, or sar)", http.StatusBadRequest) return } diff --git a/src/lib/SimulationSidebar.svelte b/src/lib/SimulationSidebar.svelte index 83f0709..96410d5 100644 --- a/src/lib/SimulationSidebar.svelte +++ b/src/lib/SimulationSidebar.svelte @@ -61,6 +61,7 @@ + diff --git a/src/lib/SimulationTable.svelte b/src/lib/SimulationTable.svelte index fb87a17..2da412e 100644 --- a/src/lib/SimulationTable.svelte +++ b/src/lib/SimulationTable.svelte @@ -1,57 +1,59 @@
- - - - - - - - - - - - - - {#each state.paginatedSimulations as sim} - - - - - - - - - - {/each} - -
IDSim NameSearch PatternSearch TimeTotal TimeDate RunLink
{sim.id}{sim.name}{parseConfig(sim.config).pattern || "Unknown"}{formatTime(sim.search_time || NaN)}{formatTime(sim.total_time || NaN)}{formatDate(sim.created_at)}View Details
+ + + + + + + + + + + + + + {#each state.paginatedSimulations as sim} + + + + + + + + + + {/each} + +
IDSim NameSearch PatternSearch TimeTotal TimeDate RunLink
{sim.id}{sim.name}{parseConfig(sim.config).pattern === "sar" + ? "SAR" + : parseConfig(sim.config).pattern || "Unknown"}{formatTime(sim.search_time || NaN)}{formatTime(sim.total_time || NaN)}{formatDate(sim.created_at)}View Details
- +
diff --git a/src/lib/simulationState.svelte.ts b/src/lib/simulationState.svelte.ts index 40021e0..4a4126f 100644 --- a/src/lib/simulationState.svelte.ts +++ b/src/lib/simulationState.svelte.ts @@ -29,6 +29,7 @@ export function parseConfig(config: string) { if (searchObj.spiral) pattern = "spiral"; else if (searchObj.lawnmower) pattern = "lawnmower"; else if (searchObj.levy) pattern = "levy"; + else if (searchObj.sar) pattern = "sar"; return { altitude: searchObj.altitude != null ? parseFloat(searchObj.altitude) : null, diff --git a/src/routes/simulation/[id]/+page.svelte b/src/routes/simulation/[id]/+page.svelte index 4b3c1ff..768545b 100644 --- a/src/routes/simulation/[id]/+page.svelte +++ b/src/routes/simulation/[id]/+page.svelte @@ -1,608 +1,562 @@ << Back to Index {#if error} -

Error: {error}

+

Error: {error}

{:else if !simulation} -

Loading...

+

Loading...

{:else} -
- {#if !isEditing} -

Simulation Detail: {simulation.name}

-
- - - -
- {:else} -
-

Edit Simulation

-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- {#if saveError} -

{saveError}

- {/if} - {#if isUploading} -
-
- {uploadProgress}% -
- {/if} -
- - -
-
- {/if} -
+
+ {#if !isEditing} +

Simulation Detail: {simulation.name}

+
+ + + +
+ {:else} +
+

Edit Simulation

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ {#if saveError} +

{saveError}

+ {/if} + {#if isUploading} +
+
+ {uploadProgress}% +
+ {/if} +
+ + +
+
+ {/if} +
-

- ID: - {simulation.id} -

-

- Search Pattern: - {parsedConfig?.find((c) => c.key === "search.spiral.max_legs") - ? "Spiral" - : parsedConfig?.find((c) => c.key === "search.lawnmower.width") - ? "Lawnmower" - : parsedConfig?.find((c) => c.key === "search.levy.max_steps") - ? "Levy" - : "Unknown"} -

-

Date Code: {formatDate(simulation.created_at)}

+

+ ID: + {simulation.id} +

+

+ Search Pattern: + {parsedConfig?.find((c) => c.key === "search.spiral.max_legs") + ? "Spiral" + : parsedConfig?.find((c) => c.key === "search.lawnmower.width") + ? "Lawnmower" + : parsedConfig?.find((c) => c.key === "search.levy.max_steps") + ? "Levy" + : parsedConfig?.find((c) => c.key.startsWith("search.sar")) + ? "SAR" + : "Unknown"} +

+

Date Code: {formatDate(simulation.created_at)}

- {#if simulation.search_time !== null && simulation.total_time !== null} -

- Search Time: - {formatTime(simulation.search_time)} | Total Time: - {formatTime(simulation.total_time)} -

- {/if} -

- Total Media Size: - {formatBytes(simulation.total_size_bytes || 0)} -

+ {#if simulation.search_time !== null && simulation.total_time !== null} +

+ Search Time: + {formatTime(simulation.search_time)} | Total Time: + {formatTime(simulation.total_time)} +

+ {/if} +

+ Total Media Size: + {formatBytes(simulation.total_size_bytes || 0)} +

- {#if simulation.cpu_info || simulation.gpu_info || simulation.ram_info} -
-

Hardware Spec

-

CPU: {simulation.cpu_info || "N/A"}

-

GPU: {simulation.gpu_info || "N/A"}

-

RAM: {simulation.ram_info || "N/A"}

-
- {/if} + {#if simulation.cpu_info || simulation.gpu_info || simulation.ram_info} +
+

Hardware Spec

+

CPU: {simulation.cpu_info || "N/A"}

+

GPU: {simulation.gpu_info || "N/A"}

+

RAM: {simulation.ram_info || "N/A"}

+
+ {/if} - {#if simulation.config} -
- Configuration Options: - {#if parsedConfig} - {#snippet ConfigTable( - title: string, - data: { key: string; value: string }[] | undefined, - )} - {#if data && data.length > 0} - {@const groups = groupConfig(data)} -
-

{title}

-
- {#if groups["_general"].length > 0} -
-

General

- - - - - - {#each groups["_general"] as item} - - {/each} - -
ParameterValue
{item.key}{item.value}
-
- {/if} - {#each Object.entries(groups).filter(([k]) => k !== "_general") as [groupName, items]} -
-

- {groupName} -

- - - - - - {#each items as item} - - {/each} - -
ParameterValue
{item.key}{item.value}
-
- {/each} -
-
- {/if} - {/snippet} + {#if simulation.config} +
+ Configuration Options: + {#if parsedConfig} + {#snippet ConfigTable( + title: string, + data: { key: string; value: string }[] | undefined, + )} + {#if data && data.length > 0} + {@const groups = groupConfig(data)} +
+

{title}

+
+ {#if groups["_general"].length > 0} +
+

General

+ + + + + + {#each groups["_general"] as item} + + {/each} + +
ParameterValue
{item.key}{item.value}
+
+ {/if} + {#each Object.entries(groups).filter(([k]) => k !== "_general") as [groupName, items]} +
+

+ {groupName} +

+ + + + + + {#each items as item} + + {/each} + +
ParameterValue
{item.key}{item.value}
+
+ {/each} +
+
+ {/if} + {/snippet} -
- {@render ConfigTable("Search", searchConfig)} - {@render ConfigTable("UGV", ugvConfig)} - {@render ConfigTable("UAV", uavConfig)} - {@render ConfigTable("Other", otherConfig)} -
- {:else} -
{simulation.config}
- {/if} -
- {/if} +
+ {@render ConfigTable("Search", searchConfig)} + {@render ConfigTable("UGV", ugvConfig)} + {@render ConfigTable("UAV", uavConfig)} + {@render ConfigTable("Other", otherConfig)} +
+ {:else} +
{simulation.config}
+ {/if} +
+ {/if} -
-

Simulation Logs

- {#if simulation.resources && simulation.resources.includes("log.txt")} - - {:else} -

No log.txt file found for this simulation.

- {/if} +
+

Simulation Logs

+ {#if simulation.resources && simulation.resources.includes("log.txt")} + + {:else} +

No log.txt file found for this simulation.

+ {/if} - {#if flightPathVideo || gazeboVideo} -
-

Flight Path & Gazebo

- - {/if} + {#if flightPathVideo || gazeboVideo} +
+

Flight Path & Gazebo

+ + {/if} - {#if uavCamera || ugvCamera} -
-

UAV & UGV Cameras

- - {/if} + {#if uavCamera || ugvCamera} +
+

UAV & UGV Cameras

+ + {/if} -
+
-

Media & Results

- {#if imagesList.length > 0} - - {/if} +

Media & Results

+ {#if imagesList.length > 0} + + {/if} - {#if otherResourcesList.length > 0} -
- {#each otherResourcesList as res} - - {/each} -
- {/if} + {#if otherResourcesList.length > 0} +
+ {#each otherResourcesList as res} + + {/each} +
+ {/if} - {#if imagesList.length === 0 && otherResourcesList.length === 0} -

No other media resources found for this simulation.

- {/if} + {#if imagesList.length === 0 && otherResourcesList.length === 0} +

No other media resources found for this simulation.

+ {/if} {/if} diff --git a/src/routes/simulation/[id]/print/+page.svelte b/src/routes/simulation/[id]/print/+page.svelte index fa47cf0..2fcc2af 100644 --- a/src/routes/simulation/[id]/print/+page.svelte +++ b/src/routes/simulation/[id]/print/+page.svelte @@ -1,364 +1,340 @@ {#if simulation} - {:else} -

Loading printable report...

+

Loading printable report...

{/if}