-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e992cad
Showing
56 changed files
with
7,717 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: Wails build | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'v*.*.*' | ||
|
||
env: | ||
# Necessary for most environments as build failure can occur due to OOM issues | ||
NODE_OPTIONS: "--max-old-space-size=4096" | ||
|
||
jobs: | ||
build: | ||
strategy: | ||
# Failure in one platform build won't impact the others | ||
fail-fast: false | ||
matrix: | ||
build: | ||
- name: 'moss-ui' | ||
platform: 'linux/amd64' | ||
os: 'ubuntu-latest' | ||
- name: 'moss-ui' | ||
platform: 'windows/amd64' | ||
os: 'windows-latest' | ||
- name: 'moss-ui' | ||
platform: 'darwin/universal' | ||
os: 'macos-latest' | ||
|
||
runs-on: ${{ matrix.build.os }} | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
with: | ||
submodules: recursive | ||
|
||
- name: Build wails | ||
uses: dAppServer/[email protected] | ||
id: build | ||
with: | ||
build-name: ${{ matrix.build.name }} | ||
build-platform: ${{ matrix.build.platform }} | ||
package: true | ||
go-version: '1.23' | ||
node-version: '20.x' | ||
nsis: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
build/bin | ||
node_modules | ||
frontend/dist | ||
data/ | ||
log/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# MOSS-UI | ||
|
||
A simple UI to visualize the AVRO output of the MOSS project. | ||
|
||
The project is **unstable** now and faces data reading performance challenges to handle the AVRO output data without indexing that is usually provided by a database. | ||
|
||
ATTENTION: | ||
- The car model in the project is 5m × 2m, which cannot be automatically adjusted by the vehicle attributes in the moss input person file. | ||
|
||
## How to run | ||
|
||
1. Get the output dir of the MOSS project. | ||
```python | ||
from moss import Engine, TlPolicy, Verbosity | ||
MAP_PATH = "./data/temp/map.pb" | ||
TRIP_PATH = "./data/temp/persons.pb" | ||
eng = Engine( | ||
+ name="test", | ||
map_file=MAP_PATH, | ||
person_file=TRIP_PATH, | ||
start_step=8 * 3600, | ||
+ output_dir="./output", | ||
verbose_level=Verbosity.ALL, | ||
device=0, | ||
) | ||
``` | ||
The related documentation is https://docs.fiblab.net/moss#Engine. | ||
|
||
2. Open the MOSS-UI and select the output directory. In the file dialog, please select the `moss.yml` file in the output directory of the MOSS project. | ||
|
||
![MOSS-UI](./docs/1.png) | ||
|
||
3. When you open a file, please wait for the data to be loaded. If the loading process is finished, you will see a message like below and the map will move to the center of the output data. | ||
|
||
![MOSS-UI](./docs/2.png) | ||
|
||
4. You can open/close the layer by clicking the icon on the top. You can also change the time by dragging the slider on the bottom. | ||
|
||
## For Developers | ||
|
||
This is a Wails React-TS project. | ||
|
||
You can configure the project by editing `wails.json`. More information about the project settings can be found | ||
here: https://wails.io/docs/reference/project-config | ||
|
||
#### Prequisites | ||
|
||
You will need to have the Wails development environment installed. You can find instructions here: https://wails.io/docs/gettingstarted/installation | ||
|
||
#### Live Development | ||
|
||
To run in live development mode, run `wails dev` in the project directory. This will run a Vite development | ||
server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser | ||
and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect | ||
to this in your browser, and you can call your Go code from devtools. | ||
|
||
#### Building | ||
|
||
To build a redistributable, production mode package, use `wails build`. | ||
|
||
Command to build the project for all platforms: | ||
```bash | ||
wails build -platform windows/amd64 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
"math" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"sort" | ||
|
||
"github.com/samber/lo" | ||
"github.com/wailsapp/wails/v2/pkg/runtime" | ||
) | ||
|
||
const TITLE = "MObility Simulation System UI" | ||
|
||
type Sim struct { | ||
Name string `json:"name"` | ||
Start float64 `json:"start"` | ||
Steps float64 `json:"steps"` | ||
MapBase64 string `json:"map_base64"` | ||
} | ||
|
||
// App struct | ||
type App struct { | ||
ctx context.Context | ||
|
||
tlLoader *Loader[FrontendTL, *FrontendTL] | ||
vehicleLoader *Loader[FrontendCar, *FrontendCar] | ||
pedestrianLoader *Loader[FrontendPedestrian, *FrontendPedestrian] | ||
} | ||
|
||
// NewApp creates a new App application struct | ||
func NewApp() *App { | ||
return &App{} | ||
} | ||
|
||
// startup is called when the app starts. The context is saved | ||
// so we can call the runtime methods | ||
func (a *App) startup(ctx context.Context) { | ||
a.ctx = ctx | ||
} | ||
|
||
type LoadReturn struct { | ||
Sim *Sim `json:"sim"` | ||
Err string `json:"err"` | ||
} | ||
|
||
// try to load a directory with MOSS output files | ||
func (a *App) Open() LoadReturn { | ||
file, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{ | ||
Title: "Select a MOSS output project", | ||
DefaultFilename: "moss.yml", | ||
}) | ||
if err != nil { | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
absFile, err := filepath.Abs(file) | ||
if err != nil { | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
dir := filepath.Dir(absFile) | ||
|
||
// 1. load dir / "map.pb" | ||
mapPath := path.Join(dir, "map.pb") | ||
mapBytes, err := os.ReadFile(mapPath) | ||
if err != nil { | ||
// if map.pb not found, return error | ||
if errors.Is(err, os.ErrNotExist) { | ||
return LoadReturn{nil, "`map.pb` not found in the directory"} | ||
} | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
// 2. load dir / "vehicle" / {time}.avro | ||
vehicleDir := path.Join(dir, "vehicle") | ||
vehicleScanner, err := NewScanner(vehicleDir) | ||
if err != nil { | ||
if errors.Is(err, os.ErrNotExist) { | ||
return LoadReturn{nil, "`vehicle` directory not found in the directory"} | ||
} | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
a.vehicleLoader = NewLoader(vehicleScanner, NewFrontendCar) | ||
|
||
// 3. load dir / "pedestrian" / {time}.avro | ||
pedestrianDir := path.Join(dir, "pedestrian") | ||
pedestrianScanner, err := NewScanner(pedestrianDir) | ||
if err != nil { | ||
if errors.Is(err, os.ErrNotExist) { | ||
return LoadReturn{nil, "`pedestrian` directory not found in the directory"} | ||
} | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
a.pedestrianLoader = NewLoader(pedestrianScanner, NewFrontendPedestrian) | ||
|
||
// 4. load dir / "tl" / {time}.avro | ||
tlDir := path.Join(dir, "tl") | ||
tlScanner, err := NewScanner(tlDir) | ||
if err != nil { | ||
if errors.Is(err, os.ErrNotExist) { | ||
return LoadReturn{nil, "`tl` directory not found in the directory"} | ||
} | ||
return LoadReturn{nil, err.Error()} | ||
} | ||
a.tlLoader = NewLoader(tlScanner, NewFrontendTL) | ||
|
||
// build Sim | ||
|
||
allStartT := math.Inf(1) | ||
allEndT := math.Inf(-1) | ||
for _, scanner := range []*Scanner{vehicleScanner, pedestrianScanner, tlScanner} { | ||
if startT := scanner.StartT(); startT < allStartT { | ||
allStartT = startT | ||
} | ||
if endT := scanner.EndT(); endT > allEndT { | ||
allEndT = endT | ||
} | ||
} | ||
|
||
// modify app title | ||
runtime.WindowSetTitle(a.ctx, TITLE+" - "+dir) | ||
|
||
return LoadReturn{&Sim{ | ||
Name: dir, | ||
Start: allStartT, | ||
Steps: allEndT - allStartT, | ||
MapBase64: base64.StdEncoding.EncodeToString(mapBytes), | ||
}, ""} | ||
} | ||
|
||
func (a *App) Close() { | ||
a.vehicleLoader = nil | ||
a.pedestrianLoader = nil | ||
a.tlLoader = nil | ||
runtime.WindowSetTitle(a.ctx, TITLE) | ||
} | ||
|
||
type FetchCarReturn struct { | ||
Data []*FrontendCarFrame `json:"data"` | ||
Err string `json:"err"` | ||
} | ||
|
||
func (a *App) FetchCar(startT, endT float64, xMin, xMax, yMin, yMax float32) *FetchCarReturn { | ||
frames, err := a.vehicleLoader.Load(startT, endT) | ||
if err != nil { | ||
return &FetchCarReturn{nil, err.Error()} | ||
} | ||
frontendFrames := make([]*FrontendCarFrame, len(frames)) | ||
// filter by x, y | ||
for i, frame := range frames { | ||
frontendFrames[i] = &FrontendCarFrame{ | ||
T: frame.T, | ||
Data: lo.Filter(frame.Data, func(car *FrontendCar, _ int) bool { | ||
return car.X >= xMin && car.X <= xMax && car.Y >= yMin && car.Y <= yMax | ||
}), | ||
} | ||
} | ||
// sort by t | ||
sort.Slice(frontendFrames, func(i, j int) bool { | ||
return frontendFrames[i].T < frontendFrames[j].T | ||
}) | ||
// debug string | ||
debugStr := fmt.Sprintf("len(FetchCar): %v", len(frontendFrames)) | ||
for _, frame := range frontendFrames { | ||
debugStr += fmt.Sprintf("\n t=%v, len(Data): %v", frame.T, len(frame.Data)) | ||
} | ||
runtime.LogDebug(a.ctx, debugStr) | ||
return &FetchCarReturn{frontendFrames, ""} | ||
} | ||
|
||
type FetchPedReturn struct { | ||
Data []*FrontendPedestrianFrame `json:"data"` | ||
Err string `json:"err"` | ||
} | ||
|
||
func (a *App) FetchPed(startT, endT float64, xMin, xMax, yMin, yMax float32) *FetchPedReturn { | ||
frames, err := a.pedestrianLoader.Load(startT, endT) | ||
if err != nil { | ||
return &FetchPedReturn{nil, err.Error()} | ||
} | ||
frontendFrames := make([]*FrontendPedestrianFrame, len(frames)) | ||
// filter by x, y | ||
for i, frame := range frames { | ||
frontendFrames[i] = &FrontendPedestrianFrame{ | ||
T: frame.T, | ||
Data: lo.Filter(frame.Data, func(ped *FrontendPedestrian, _ int) bool { | ||
return ped.X >= xMin && ped.X <= xMax && ped.Y >= yMin && ped.Y <= yMax | ||
}), | ||
} | ||
} | ||
return &FetchPedReturn{frontendFrames, ""} | ||
} | ||
|
||
type FetchTLReturn struct { | ||
Data []*FrontendTLFrame `json:"data"` | ||
Err string `json:"err"` | ||
} | ||
|
||
func (a *App) FetchTL(startT, endT float64) *FetchTLReturn { | ||
frames, err := a.tlLoader.Load(startT, endT) | ||
if err != nil { | ||
return &FetchTLReturn{nil, err.Error()} | ||
} | ||
frontendFrames := make([]*FrontendTLFrame, len(frames)) | ||
for i, frame := range frames { | ||
frontendFrames[i] = &FrontendTLFrame{ | ||
T: frame.T, | ||
Data: frame.Data, | ||
} | ||
} | ||
return &FetchTLReturn{frontendFrames, ""} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Build Directory | ||
|
||
The build directory is used to house all the build files and assets for your application. | ||
|
||
The structure is: | ||
|
||
* bin - Output directory | ||
* darwin - macOS specific files | ||
* windows - Windows specific files | ||
|
||
## Mac | ||
|
||
The `darwin` directory holds files specific to Mac builds. | ||
These may be customised and used as part of the build. To return these files to the default state, simply delete them | ||
and | ||
build with `wails build`. | ||
|
||
The directory contains the following files: | ||
|
||
- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. | ||
- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. | ||
|
||
## Windows | ||
|
||
The `windows` directory contains the manifest and rc files used when building with `wails build`. | ||
These may be customised for your application. To return these files to the default state, simply delete them and | ||
build with `wails build`. | ||
|
||
- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to | ||
use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file | ||
will be created using the `appicon.png` file in the build directory. | ||
- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. | ||
- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, | ||
as well as the application itself (right click the exe -> properties -> details) | ||
- `wails.exe.manifest` - The main application manifest file. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.