├── .gitattributes ├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── README.md ├── app ├── build.gradle.kts └── src │ └── main │ ├── java │ └── org │ │ └── team2363 │ │ ├── helixnavigator │ │ ├── App.java │ │ ├── Main.java │ │ ├── Test.java │ │ ├── document │ │ │ ├── DocumentActions.java │ │ │ ├── DocumentManager.java │ │ │ ├── HDocument.java │ │ │ ├── HFieldTarget.java │ │ │ ├── HPath.java │ │ │ ├── HPathElement.java │ │ │ ├── HRobotConfiguration.java │ │ │ ├── HSelectableElement.java │ │ │ ├── HSelectionModel.java │ │ │ ├── HTrajectory.java │ │ │ ├── HTrajectorySample.java │ │ │ ├── HUnitPreferences.java │ │ │ ├── HWaypointBundle.java │ │ │ ├── field │ │ │ │ └── image │ │ │ │ │ ├── HDefaultFieldImage.java │ │ │ │ │ ├── HFieldCorner.java │ │ │ │ │ ├── HFieldCorners.java │ │ │ │ │ ├── HFieldImage.java │ │ │ │ │ ├── HFieldSize.java │ │ │ │ │ ├── HFieldUnit.java │ │ │ │ │ └── HReferenceFieldImage.java │ │ │ ├── obstacle │ │ │ │ ├── HCircleObstacle.java │ │ │ │ ├── HObstacle.java │ │ │ │ ├── HPolygonObstacle.java │ │ │ │ ├── HPolygonPoint.java │ │ │ │ └── HRectangleObstacle.java │ │ │ └── timeline │ │ │ │ ├── HCustomWaypoint.java │ │ │ │ ├── HHardWaypoint.java │ │ │ │ ├── HInitialGuessWaypoint.java │ │ │ │ ├── HSoftWaypoint.java │ │ │ │ └── HWaypoint.java │ │ ├── global │ │ │ ├── DefaultFieldImages.java │ │ │ ├── DefaultResourceUnavailableException.java │ │ │ ├── DefaultResources.java │ │ │ ├── Logs.java │ │ │ └── Standards.java │ │ ├── testcode │ │ │ ├── EditorTest.java │ │ │ ├── FilePromptTest.java │ │ │ ├── JavaFxListView.java │ │ │ ├── ListOrganizer.java │ │ │ ├── ObstacleTest.java │ │ │ ├── SelectionModelTest.java │ │ │ ├── TableViewSample.java │ │ │ ├── ToolbarTest.java │ │ │ ├── WapyointTest.java │ │ │ ├── WaypointListCellOld.java │ │ │ └── jenkov │ │ │ │ ├── Point.java │ │ │ │ └── TableViewExample.java │ │ └── ui │ │ │ ├── MainPane.java │ │ │ ├── MainScene.java │ │ │ ├── MainStage.java │ │ │ ├── document │ │ │ ├── DocumentPane.java │ │ │ ├── ObstacleListCell.java │ │ │ ├── ObstacleListView.java │ │ │ ├── PathChooserBox.java │ │ │ ├── PathListCell.java │ │ │ ├── SelectableElementListView.java │ │ │ ├── WaypointListCell.java │ │ │ └── WaypointListView.java │ │ │ ├── editor │ │ │ ├── BackgroundRectangle.java │ │ │ ├── EditorPane.java │ │ │ ├── InfoText.java │ │ │ ├── PathElementsPane.java │ │ │ ├── PathPane.java │ │ │ ├── field │ │ │ │ ├── FieldImagePane.java │ │ │ │ └── OriginView.java │ │ │ ├── line │ │ │ │ ├── LineView.java │ │ │ │ └── LinesPane.java │ │ │ ├── obstacle │ │ │ │ ├── CircleObstacleView.java │ │ │ │ ├── ObstacleView.java │ │ │ │ ├── ObstaclesPane.java │ │ │ │ ├── PolygonObstacleView.java │ │ │ │ ├── PolygonPointView.java │ │ │ │ ├── PolygonPointsPane.java │ │ │ │ ├── PolygonWrapper.java │ │ │ │ └── RectangleObstacleView.java │ │ │ ├── toolbar │ │ │ │ ├── PathToolBar.java │ │ │ │ └── TrajectoryToolBar.java │ │ │ ├── trajectory │ │ │ │ ├── AnimationPane.java │ │ │ │ ├── SegmentView.java │ │ │ │ ├── SegmentsPane.java │ │ │ │ └── TrajectoryPane.java │ │ │ └── waypoint │ │ │ │ ├── CustomWaypointView.java │ │ │ │ ├── HardWaypointView.java │ │ │ │ ├── InitialGuessWaypointView.java │ │ │ │ ├── RobotView.java │ │ │ │ ├── SoftWaypointView.java │ │ │ │ ├── WaypointView.java │ │ │ │ └── WaypointsPane.java │ │ │ ├── menu │ │ │ ├── MainMenuBar.java │ │ │ ├── edit │ │ │ │ ├── CopyMenuItem.java │ │ │ │ ├── CutMenuItem.java │ │ │ │ ├── DeleteMenuItem.java │ │ │ │ ├── DeselectAllMenuItem.java │ │ │ │ ├── EditMenu.java │ │ │ │ ├── FlipToOppositeSideMenuItem.java │ │ │ │ ├── PasteMenuItem.java │ │ │ │ ├── RedoMenuItem.java │ │ │ │ ├── Rotate180MenuItem.java │ │ │ │ ├── Rotate90ClockwiseMenuItem.java │ │ │ │ ├── Rotate90CounterclockwiseMenuItem.java │ │ │ │ ├── SelectAllMenuItem.java │ │ │ │ ├── TransformMenuItem.java │ │ │ │ └── UndoMenuItem.java │ │ │ ├── file │ │ │ │ ├── CloseDocumentMenuItem.java │ │ │ │ ├── ExportMenu.java │ │ │ │ ├── ExportWaypointBundleMenuItem.java │ │ │ │ ├── FileMenu.java │ │ │ │ ├── ImportMenuItem.java │ │ │ │ ├── NewDocumentMenuItem.java │ │ │ │ ├── OpenDocumentMenuItem.java │ │ │ │ ├── SaveAsMenuItem.java │ │ │ │ └── SaveMenuItem.java │ │ │ ├── help │ │ │ │ ├── AboutMenuItem.java │ │ │ │ ├── AboutStage.java │ │ │ │ └── HelpMenu.java │ │ │ ├── tools │ │ │ │ ├── EditDocumentConfigurationMenuItem.java │ │ │ │ ├── EditRobotConfigurationMenuItem.java │ │ │ │ └── ToolsMenu.java │ │ │ └── view │ │ │ │ ├── ViewMenu.java │ │ │ │ └── ZoomToFitMenuItem.java │ │ │ ├── metadata │ │ │ ├── MetadataPane.java │ │ │ ├── MultiSelectionMetaPane.java │ │ │ └── WaypointSelectionMetaPane.java │ │ │ └── prompts │ │ │ ├── RobotConfigDialog.java │ │ │ ├── TransformDialog.java │ │ │ ├── documentconfig │ │ │ ├── DocumentConfigDialog.java │ │ │ ├── GeneralTab.java │ │ │ └── RobotTab.java │ │ │ ├── obstacle │ │ │ ├── CircleObstacleEditDialog.java │ │ │ ├── ObstacleEditDialog.java │ │ │ ├── PolygonObstacleEditDialog.java │ │ │ ├── PolygonPointsTableView.java │ │ │ └── RectangleObstacleEditDialog.java │ │ │ └── waypoint │ │ │ ├── CustomWaypointEditDialog.java │ │ │ ├── HardWaypointEditDialog.java │ │ │ ├── HeadingTextField.java │ │ │ ├── InitialGuessWaypointEditDialog.java │ │ │ ├── SoftWaypointEditDialog.java │ │ │ └── WaypointEditDialog.java │ │ └── lib │ │ ├── base64 │ │ ├── Base64Decoder.java │ │ ├── Base64Encoder.java │ │ ├── Base64Test.java │ │ └── FileEncodeTest.java │ │ ├── math │ │ └── ExpressionParser.java │ │ ├── ui │ │ ├── MouseEventWrapper.java │ │ ├── OrderableListCell.java │ │ ├── prompts │ │ │ ├── SavePrompt.java │ │ │ └── legacy │ │ │ │ ├── DecimalTextInputDialog.java │ │ │ │ └── IntegerTextInputDialog.java │ │ └── validation │ │ │ ├── DecimalTextField.java │ │ │ ├── DecimalValidator.java │ │ │ ├── FilteredTextField.java │ │ │ ├── FilteredTextInputDialog.java │ │ │ ├── IntegerTextField.java │ │ │ ├── IntegerValidator.java │ │ │ ├── MathExpressionTextField.java │ │ │ └── UnitTextField.java │ │ └── unit │ │ ├── CustomUnits.java │ │ └── MomentOfInertia.java │ └── resources │ ├── icon.icns │ ├── icon.png │ ├── org │ └── team2363 │ │ └── helixnavigator │ │ └── global │ │ ├── extrafieldimages │ │ ├── 2021-infiniterechargeathome.json │ │ ├── 2021-infiniterechargeathome.png │ │ ├── blankfield.json │ │ └── blankfield.png │ │ └── wpifieldimages │ │ ├── 2018-field.jpg │ │ ├── 2018-powerup.json │ │ ├── 2019-deepspace.json │ │ ├── 2019-field.jpg │ │ ├── 2020-field.png │ │ ├── 2020-infiniterecharge.json │ │ ├── 2021-barrel.png │ │ ├── 2021-barrelracingpath.json │ │ ├── 2021-bounce.png │ │ ├── 2021-bouncepath.json │ │ ├── 2021-field.png │ │ ├── 2021-galacticsearcha.json │ │ ├── 2021-galacticsearcha.png │ │ ├── 2021-galacticsearchb.json │ │ ├── 2021-galacticsearchb.png │ │ ├── 2021-infiniterecharge.json │ │ ├── 2021-slalom.png │ │ ├── 2021-slalompath.json │ │ ├── 2022-field.png │ │ ├── 2022-rapidreact.json │ │ ├── 2023-chargedup.json │ │ └── 2023-field.png │ ├── script.py │ └── waypoint_images │ ├── hard_waypoint_100px.png │ ├── hard_waypoint_20px.png │ ├── soft_waypoint_100px.png │ ├── soft_waypoint_20px.png │ ├── waypoints_dragged_1.png │ ├── waypoints_dragged_2.png │ ├── waypoints_dragged_3.png │ └── waypoints_dragged_4.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | include: 11 | - job-name: Build - Ubuntu x64 12 | os: ubuntu-22.04 13 | artifact-name: linux-x64.deb 14 | - job-name: Build - macOS x64 15 | os: macOS-12 16 | artifact-name: macOS-x64.dmg 17 | - job-name: Build - Windows x64 18 | os: windows-2022 19 | artifact-name: windows-x64.msi 20 | 21 | name: ${{ matrix.job-name }} 22 | runs-on: ${{ matrix.os }} 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: actions/setup-java@v3 28 | with: 29 | distribution: temurin 30 | java-version: 17 31 | 32 | - name: Build with Gradle 33 | uses: gradle/gradle-build-action@v2 34 | with: 35 | arguments: | 36 | build 37 | -PmvnUsername=${{ secrets.TRAJOPT_MAVEN_USERNAME }} 38 | -PmvnPassword=${{ secrets.TRAJOPT_MAVEN_PASSWORD }} 39 | 40 | - name: Generate jpackage 41 | uses: gradle/gradle-build-action@v2 42 | with: 43 | arguments: jpackage 44 | 45 | - name: Upload jpackage 46 | uses: actions/upload-artifact@v3.1.1 47 | with: 48 | name: HelixNavigator-1.0.0-${{ matrix.artifact-name }} 49 | path: app/build/package 50 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Version: `X.X.X`" 8 | required: true 9 | default: '1.0.0' 10 | type: string 11 | tag: 12 | description: "Tag" 13 | required: true 14 | default: 'v1.0.0' 15 | type: string 16 | 17 | jobs: 18 | build: 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | include: 23 | - job-name: Build - Ubuntu x64 24 | os: ubuntu-22.04 25 | artifact-name: linux-x64.deb 26 | - job-name: Build - macOS x64 27 | os: macOS-12 28 | artifact-name: macOS-x64.dmg 29 | - job-name: Build - Windows x64 30 | os: windows-2022 31 | artifact-name: windows-x64.msi 32 | 33 | name: ${{ matrix.job-name }} 34 | runs-on: ${{ matrix.os }} 35 | 36 | steps: 37 | - uses: actions/checkout@v3 38 | with: 39 | ref: ${{ inputs.tag }} 40 | 41 | - uses: actions/setup-java@v3 42 | with: 43 | distribution: temurin 44 | java-version: 17 45 | 46 | - name: Build with Gradle 47 | uses: gradle/gradle-build-action@v2 48 | with: 49 | arguments: | 50 | build 51 | -PmvnUsername=${{ secrets.TRAJOPT_MAVEN_USERNAME }} 52 | -PmvnPassword=${{ secrets.TRAJOPT_MAVEN_PASSWORD }} 53 | 54 | - name: Generate jpackage 55 | uses: gradle/gradle-build-action@v2 56 | with: 57 | arguments: jpackage 58 | 59 | - name: Upload jpackage 60 | uses: actions/upload-artifact@v3.1.1 61 | with: 62 | name: HelixNavigator-${{ inputs.version }}-${{ matrix.artifact-name }} 63 | path: app/build/package/* 64 | 65 | release: 66 | needs: build 67 | name: Release 68 | runs-on: ubuntu-22.04 69 | 70 | steps: 71 | - uses: actions/checkout@v2 72 | 73 | - uses: actions/download-artifact@v3 74 | with: 75 | path: 'pkgs/' 76 | 77 | - name: Display structure of downloaded files 78 | run: ls -R 79 | 80 | - uses: ncipollo/release-action@v1 81 | with: 82 | name: v${{ inputs.version }} 83 | tag: ${{ inputs.tag }} 84 | artifacts: pkgs/HelixNavigator-${{ inputs.version }}-linux-x64.deb/helixnavigator_${{ inputs.version }}-1_amd64.deb,pkgs/HelixNavigator-${{ inputs.version }}-macOS-x64.dmg/HelixNavigator-${{ inputs.version }}.dmg,pkgs/HelixNavigator-${{ inputs.version }}-windows-x64.msi/HelixNavigator-${{ inputs.version }}.msi 85 | draft: true 86 | prerelease: true 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | bin 7 | 8 | # Ignore vscode stuff 9 | .vscode 10 | .settings 11 | 12 | # Ignore mac stuff 13 | .DS_Store 14 | 15 | # Ignore local libraries for testing 16 | libs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HelixNavigator 2 | 3 | A trajectory optimization-based path planning app for FRC. 4 | 5 | ![Build](https://github.com/TripleHelixProgramming/HelixNavigator/actions/workflows/build.yml/badge.svg) 6 | [![Discord](https://img.shields.io/discord/975739302933856277?color=%23738ADB&label=Join%20our%20Discord&logo=discord&logoColor=white)](https://discord.gg/ad2EEZZwsS) 7 | 8 | ## Compatibility 9 | 10 | HelixNavigator is compatible with FRC swerve drive robots only. The app generates json trajectories which can be followed by the a trajectory follower in the robot code. 11 | 12 | ## TrajoptLib 13 | 14 | HelixNavigator is backed by the [TrajoptLib](https://github.com/SleipnirGroup/TrajoptLib), a C++ library for generating time-optimal trajectories. 15 | 16 | ## Binary Installation 17 | 18 | You can download the latest binaries on [Releases](https://github.com/TripleHelixProgramming/HelixNavigator/releases). 19 | 20 | ### Linux 21 | 22 | Use your system's package manager to install the `HelixNavigator-X.X.X-linux-x64.deb` artifact. 23 | 24 | ### macOS 25 | 26 | Download the `HelixNavigator-X.X.X-macOS-x64.zip` artifact. Extract it and place in the `/Applications` directory. 27 | 28 | ### Windows WSL 29 | 30 | Since the app doesn't allow trajectory generation in windows, you should run it in WSL instead. 31 | 32 | [Install Ubuntu WSL](https://ubuntu.com/tutorials/install-ubuntu-on-wsl2-on-windows-10) on your Windows machine. 33 | 34 | Next, ensure you have GUI support enabled, following [this tutorial](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps). 35 | 36 | Open an Ubuntu WSL terminal and install HelixNavigator (this is using `v1.0.1`, but you can replace with any version): 37 | 38 | ``` 39 | wget https://github.com/TripleHelixProgramming/HelixNavigator/releases/download/v1.0.1/helixnavigator_1.0.1-1_amd64.deb 40 | sudo dpkg -i helixnavigator_1.0.1-1_amd64.deb 41 | ``` 42 | 43 | After it installs, you can run `/opt/helixnavigator/bin/HelixNavigator` to open the app. 44 | 45 | ------ 46 | 47 | ### Windows (native, not working) 48 | 49 | **DISCLAIMER:** The Windows distribution does not support generation of trajectories. This is an ongoing issue which will be fixed in the future. For now, you can run the app in WSL, see above. 50 | 51 | Download the `HelixNavigator-X.X.X-windows-x64.msi` artifact and install it. 52 | 53 | ## Building from source 54 | 55 | First, clone the repo in your working directory: 56 | ``` 57 | git clone https://github.com/TripleHelixProgramming/HelixNavigator.git 58 | ``` 59 | 60 | If on Windows, replace `./gradlew` with `.\gradlew.bat`. 61 | 62 | To build: 63 | ``` 64 | ./gradlew build -PmvnUsername=YOUR_USERNAME -PmvnPassword=YOUR_GITHUB_TOKEN 65 | ``` 66 | 67 | To run: 68 | ``` 69 | ./gradlew run 70 | ``` 71 | 72 | ## Build packaged distribution 73 | 74 | Run the following to build a `.deb`, `.dmg`, or `.msi` package: 75 | 76 | ``` 77 | ./gradlew jpackage 78 | ``` 79 | -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * The build configuration of HelixNavigator. This includes options to build 3 | * excecutables with launch4j and jpackage. 4 | */ 5 | 6 | plugins { 7 | `application` 8 | id("org.openjfx.javafxplugin") version "0.0.13" 9 | id("com.github.johnrengelman.shadow") version "7.1.2" 10 | id("edu.sc.seis.launch4j") version "2.5.1" 11 | } 12 | 13 | version = "1.0.1" 14 | 15 | val packageName = "${name}-${version}" 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { 20 | url = uri("https://jitpack.io") 21 | } 22 | maven { 23 | url = uri("https://maven.pkg.github.com/SleipnirGroup/TrajoptLib") 24 | credentials { 25 | username = project.properties["mvnUsername"].toString() 26 | password = project.properties["mvnPassword"].toString() 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | implementation("com.github.jlbabilino:json:master-SNAPSHOT") 33 | // implementation "javax.measure:unit-api:2.1.3" 34 | // implementation "tec.units:unit-ri:1.0.3" 35 | // implementation "tech.units:indriya:2.1.3" 36 | implementation("systems.uom:systems-unicode:2.1") 37 | implementation("systems.uom:systems-common:2.1") 38 | implementation("systems.uom:systems-quantity:2.1") 39 | // implementation "org.djunits:djunits:4.01.07" 40 | 41 | implementation("org.team2363:helixtrajectory:0.0.0-pre5") 42 | } 43 | 44 | application { 45 | // mainModule = "org.team2363.helixnavigator" 46 | mainClass.set("org.team2363.helixnavigator.Main") 47 | } 48 | 49 | javafx { 50 | version = "18" 51 | modules = listOf("javafx.controls") 52 | } 53 | 54 | tasks.register("jpackage") { 55 | dependsOn("shadowJar") 56 | 57 | val os = System.getProperty("os.name").toLowerCase(); 58 | 59 | var packType = ""; 60 | 61 | if (os.startsWith("linux")) { 62 | packType = "deb"; 63 | } else if (os.startsWith("mac")) { 64 | packType = "dmg" 65 | } else { // windows 66 | packType = "msi" 67 | } 68 | 69 | doLast { 70 | project.exec { 71 | 72 | if (os.startsWith("linux")) { 73 | commandLine("jpackage", 74 | "--input", "${buildDir}/libs", 75 | "--main-jar", "${packageName}-all.jar", 76 | "--main-class", "org.team2363.helixnavigator.Main", 77 | "--type", packType, 78 | "--dest", "${buildDir}/package", 79 | "--name", rootProject.name, 80 | "--app-version", version, 81 | "--icon", "${buildDir}/resources/main/icon.icns", 82 | "--linux-shortcut", 83 | ) 84 | } else { 85 | commandLine("jpackage", 86 | "--input", "${buildDir}/libs", 87 | "--main-jar", "${packageName}-all.jar", 88 | "--main-class", "org.team2363.helixnavigator.Main", 89 | "--type", packType, 90 | "--dest", "${buildDir}/package", 91 | "--name", rootProject.name, 92 | "--app-version", version, 93 | "--icon", "${buildDir}/resources/main/icon.icns", 94 | ) 95 | } 96 | } 97 | } 98 | } 99 | 100 | tasks.register("printVersion") { 101 | println(project.version) 102 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/App.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator; 2 | 3 | import org.team2363.helixnavigator.global.DefaultResources; 4 | import org.team2363.helixnavigator.global.Logs; 5 | import org.team2363.helixnavigator.ui.MainStage; 6 | 7 | import javafx.application.Application; 8 | import javafx.stage.Stage; 9 | 10 | public class App extends Application { 11 | 12 | public static void main(String[] args) { 13 | launch(args); 14 | } 15 | 16 | private MainStage mainStage; 17 | 18 | @Override 19 | public void start(Stage primaryStage) { 20 | DefaultResources.loadAllResources(); 21 | Logs.initialize(); 22 | mainStage = new MainStage(primaryStage); 23 | mainStage.show(); 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/Main.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator; 2 | 3 | public class Main { 4 | public static void main(String[] args) throws Exception { 5 | App.main(args); 6 | // Test.main(args); 7 | 8 | // org.team2363.helixnavigator.testcode.jenkov.TableViewExample.main(args); 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/Test.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator; 2 | 3 | import javafx.application.Application; 4 | import javafx.scene.Scene; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.SplitPane; 7 | import javafx.scene.layout.StackPane; 8 | import javafx.stage.Stage; 9 | 10 | public class Test extends Application { 11 | 12 | public static void main(String[] args) { 13 | launch(args); 14 | } 15 | 16 | @Override 17 | public void start(Stage primaryStage) { 18 | SplitPane sp = new SplitPane(); 19 | final StackPane sp1 = new StackPane(); 20 | sp1.getChildren().add(new Button("Button One")); 21 | final StackPane sp2 = new StackPane(); 22 | sp2.getChildren().add(new Button("Button Two")); 23 | final StackPane sp3 = new StackPane(); 24 | sp3.getChildren().add(new Button("Button Three")); 25 | sp.getItems().addAll(sp1, sp2, sp3); 26 | sp.setDividerPositions(0.3f, 0.6f, 0.9f); 27 | primaryStage.setScene(new Scene(sp)); 28 | primaryStage.show(); 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/HFieldTarget.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document; 2 | 3 | import com.jlbabilino.json.DeserializedJSONConstructor; 4 | import com.jlbabilino.json.DeserializedJSONObjectValue; 5 | import com.jlbabilino.json.DeserializedJSONTarget; 6 | import com.jlbabilino.json.JSONDeserializable; 7 | import com.jlbabilino.json.JSONSerializable; 8 | import com.jlbabilino.json.SerializedJSONObjectValue; 9 | import com.jlbabilino.json.JSONEntry.JSONType; 10 | 11 | import javafx.beans.property.DoubleProperty; 12 | import javafx.beans.property.SimpleDoubleProperty; 13 | 14 | @JSONSerializable(JSONType.OBJECT) 15 | @JSONDeserializable({JSONType.OBJECT}) 16 | public class HFieldTarget { 17 | 18 | private final DoubleProperty x = new SimpleDoubleProperty(this, "x", 0.0); 19 | private final DoubleProperty y = new SimpleDoubleProperty(this, "y", 0.0); 20 | 21 | @DeserializedJSONConstructor 22 | public HFieldTarget() { 23 | } 24 | 25 | public final DoubleProperty xProperty() { 26 | return x; 27 | } 28 | 29 | @DeserializedJSONTarget 30 | public final void setX(@DeserializedJSONObjectValue(key = "x") double value) { 31 | x.set(value); 32 | } 33 | 34 | @SerializedJSONObjectValue(key = "x") 35 | public final double getX() { 36 | return x.get(); 37 | } 38 | 39 | public final DoubleProperty yProperty() { 40 | return y; 41 | } 42 | 43 | @DeserializedJSONTarget 44 | public final void setY(@DeserializedJSONObjectValue(key = "y") double value) { 45 | y.set(value); 46 | } 47 | 48 | @SerializedJSONObjectValue(key = "y") 49 | public final double getY() { 50 | return y.get(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/HPathElement.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document; 2 | 3 | import com.jlbabilino.json.DeserializedJSONObjectValue; 4 | import com.jlbabilino.json.DeserializedJSONTarget; 5 | import com.jlbabilino.json.InvalidJSONTranslationConfiguration; 6 | import com.jlbabilino.json.JSONDeserializable; 7 | import com.jlbabilino.json.JSONSerializable; 8 | import com.jlbabilino.json.JSONSerializer; 9 | import com.jlbabilino.json.JSONSerializerException; 10 | import com.jlbabilino.json.SerializedJSONObjectValue; 11 | import com.jlbabilino.json.JSONEntry.JSONType; 12 | 13 | import javafx.beans.property.SimpleStringProperty; 14 | import javafx.beans.property.StringProperty; 15 | 16 | @JSONSerializable(JSONType.OBJECT) 17 | @JSONDeserializable({JSONType.OBJECT}) 18 | public abstract class HPathElement extends HSelectableElement { 19 | 20 | private final StringProperty name = new SimpleStringProperty(this, "name", ""); 21 | 22 | protected HPathElement() { 23 | } 24 | 25 | public final StringProperty nameProperty() { 26 | return name; 27 | } 28 | 29 | @DeserializedJSONTarget 30 | public final void setName(@DeserializedJSONObjectValue(key = "name") String value) { 31 | name.set(value); 32 | } 33 | 34 | @SerializedJSONObjectValue(key = "name") 35 | public final String getName() { 36 | return name.get(); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | try { 42 | return JSONSerializer.serializeString(this); 43 | } catch (InvalidJSONTranslationConfiguration | JSONSerializerException e) { 44 | return ""; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/HSelectableElement.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document; 2 | 3 | import javafx.beans.property.ReadOnlyBooleanProperty; 4 | import javafx.beans.property.ReadOnlyBooleanWrapper; 5 | import javafx.scene.transform.Transform; 6 | 7 | public abstract class HSelectableElement { 8 | 9 | private final ReadOnlyBooleanWrapper selected = new ReadOnlyBooleanWrapper(this, "selected", false); 10 | 11 | protected HSelectableElement() { 12 | } 13 | 14 | public abstract void transformRelative(Transform transform); 15 | 16 | public abstract void translateRelativeX(double x); 17 | 18 | public abstract void translateRelativeY(double y); 19 | 20 | public void translateRelative(double x, double y) { 21 | translateRelativeX(x); 22 | translateRelativeY(y); 23 | } 24 | 25 | public final ReadOnlyBooleanProperty selectedProperty() { 26 | return selected.getReadOnlyProperty(); 27 | } 28 | 29 | final void setSelected(boolean value) { 30 | selected.set(value); 31 | } 32 | 33 | public final boolean isSelected() { 34 | return selected.get(); 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/HTrajectorySample.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document; 2 | 3 | import org.team2363.helixtrajectory.HolonomicTrajectorySample; 4 | 5 | import com.jlbabilino.json.DeserializedJSONConstructor; 6 | import com.jlbabilino.json.DeserializedJSONObjectValue; 7 | import com.jlbabilino.json.JSONDeserializable; 8 | import com.jlbabilino.json.JSONEntry.JSONType; 9 | import com.jlbabilino.json.JSONSerializable; 10 | import com.jlbabilino.json.SerializedJSONObjectValue; 11 | 12 | @JSONSerializable(JSONType.OBJECT) 13 | @JSONDeserializable({JSONType.OBJECT}) 14 | public class HTrajectorySample { 15 | 16 | @SerializedJSONObjectValue(key = "timestamp") 17 | public final double ts; 18 | @SerializedJSONObjectValue(key = "x") 19 | public final double x; 20 | @SerializedJSONObjectValue(key = "y") 21 | public final double y; 22 | @SerializedJSONObjectValue(key = "heading") 23 | public final double heading; 24 | @SerializedJSONObjectValue(key = "velocityX") 25 | public final double vx; 26 | @SerializedJSONObjectValue(key = "velocityY") 27 | public final double vy; 28 | @SerializedJSONObjectValue(key = "angularVelocity") 29 | public final double omega; 30 | 31 | @DeserializedJSONConstructor 32 | public HTrajectorySample( 33 | @DeserializedJSONObjectValue(key = "timestamp") double ts, 34 | @DeserializedJSONObjectValue(key = "x") double x, 35 | @DeserializedJSONObjectValue(key = "y") double y, 36 | @DeserializedJSONObjectValue(key = "heading") double heading, 37 | @DeserializedJSONObjectValue(key = "velocityX") double vx, 38 | @DeserializedJSONObjectValue(key = "velocityY") double vy, 39 | @DeserializedJSONObjectValue(key = "angularVelocity") double omega) { 40 | this.ts = ts; 41 | this.x = x; 42 | this.y = y; 43 | this.heading = heading; 44 | this.vx = vx; 45 | this.vy = vy; 46 | this.omega = omega; 47 | } 48 | 49 | public static HTrajectorySample interpolate(HTrajectorySample a, HTrajectorySample b, double ts) { 50 | double ratioA = (b.ts - ts) / (b.ts - a.ts); 51 | double ratioB = 1.0 - ratioA; 52 | double x = ratioA * a.x + ratioB * b.x; 53 | double y = ratioA * a.y + ratioB * b.y; 54 | double heading = ratioA * a.heading + ratioB * b.heading; 55 | double vx = ratioA * a.vx + ratioB * b.vx; 56 | double vy = ratioA * a.vy + ratioB * b.vy; 57 | double omega = ratioA * a.omega + ratioB * b.omega; 58 | return new HTrajectorySample(ts, x, y, heading, vx, vy, omega); 59 | } 60 | 61 | public static HTrajectorySample fromTrajectorySample(HolonomicTrajectorySample sample, double timestamp) { 62 | return new HTrajectorySample(timestamp, sample.x, sample.y, sample.heading, 63 | sample.velocityX, sample.velocityY, sample.angularVelocity); 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/HWaypointBundle.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.jlbabilino.json.JSONEntry.JSONType; 7 | import com.jlbabilino.json.JSONDeserializable; 8 | import com.jlbabilino.json.JSONSerializable; 9 | import com.jlbabilino.json.SerializedJSONEntry; 10 | 11 | import org.team2363.helixnavigator.document.timeline.HHardWaypoint; 12 | import org.team2363.helixnavigator.document.timeline.HWaypoint; 13 | 14 | @JSONSerializable(JSONType.ARRAY) 15 | @JSONDeserializable({JSONType.ARRAY}) 16 | public class HWaypointBundle { 17 | 18 | private List bundleWaypoints = new ArrayList<>(); 19 | 20 | public HWaypointBundle(HPath path) { 21 | for (HWaypoint waypoint : path.getWaypoints()) { 22 | if (waypoint.isHard()) { 23 | HHardWaypoint hardWaypoint = (HHardWaypoint) waypoint; 24 | double convertedX = hardWaypoint.getX() * 0.0254; 25 | double convertedY = hardWaypoint.getY() * 0.0254; 26 | double convertedHeading = Math.toRadians(hardWaypoint.getHeading()); 27 | double[] bundleWaypoint = {convertedX, convertedY, convertedHeading}; 28 | bundleWaypoints.add(bundleWaypoint); 29 | } 30 | } 31 | } 32 | 33 | @SerializedJSONEntry 34 | public List getWaypointBundle() { 35 | return bundleWaypoints; 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HFieldCorner.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import com.jlbabilino.json.DeserializedJSONArrayItem; 4 | import com.jlbabilino.json.DeserializedJSONConstructor; 5 | import com.jlbabilino.json.JSONDeserializable; 6 | import com.jlbabilino.json.JSONSerializable; 7 | import com.jlbabilino.json.SerializedJSONArrayItem; 8 | import com.jlbabilino.json.JSONEntry.JSONType; 9 | 10 | @JSONSerializable(JSONType.ARRAY) 11 | @JSONDeserializable({JSONType.ARRAY}) 12 | public class HFieldCorner { 13 | 14 | @SerializedJSONArrayItem(index = 0) 15 | public final double x; 16 | @SerializedJSONArrayItem(index = 1) 17 | public final double y; 18 | 19 | @DeserializedJSONConstructor 20 | public HFieldCorner( 21 | @DeserializedJSONArrayItem(index = 0) double x, 22 | @DeserializedJSONArrayItem(index = 1) double y) { 23 | this.x = x; 24 | this.y = y; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HFieldCorners.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import com.jlbabilino.json.DeserializedJSONConstructor; 4 | import com.jlbabilino.json.DeserializedJSONObjectValue; 5 | import com.jlbabilino.json.JSONDeserializable; 6 | import com.jlbabilino.json.JSONSerializable; 7 | import com.jlbabilino.json.SerializedJSONObjectValue; 8 | import com.jlbabilino.json.JSONEntry.JSONType; 9 | 10 | @JSONSerializable(JSONType.OBJECT) 11 | @JSONDeserializable({JSONType.OBJECT}) 12 | public class HFieldCorners { 13 | 14 | @SerializedJSONObjectValue(key = "top-left") 15 | public final HFieldCorner topLeftCorner; 16 | @SerializedJSONObjectValue(key = "bottom-right") 17 | public final HFieldCorner bottomRightCorner; 18 | 19 | @DeserializedJSONConstructor 20 | public HFieldCorners( 21 | @DeserializedJSONObjectValue(key = "top-left") HFieldCorner topLeftCorner, 22 | @DeserializedJSONObjectValue(key = "bottom-right") HFieldCorner bottomRightCorner) { 23 | this.topLeftCorner = topLeftCorner; 24 | this.bottomRightCorner = bottomRightCorner; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HFieldImage.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import com.jlbabilino.json.DeserializedJSONDeterminer; 4 | import com.jlbabilino.json.JSONDeserializable; 5 | import com.jlbabilino.json.JSONDeserializerException; 6 | import com.jlbabilino.json.JSONEntry.JSONType; 7 | import com.jlbabilino.json.JSONSerializable; 8 | 9 | import javafx.scene.image.Image; 10 | 11 | @JSONSerializable(JSONType.OBJECT) 12 | @JSONDeserializable({JSONType.OBJECT}) 13 | public interface HFieldImage { 14 | 15 | /** 16 | * @return the name of the field image 17 | */ 18 | public String getName(); 19 | 20 | public double getFieldAreaWidth(); 21 | public double getFieldAreaHeight(); 22 | 23 | /** 24 | * @return the resolution of image, in meters per pixel 25 | */ 26 | public double getImageRes(); 27 | /** 28 | * @return the center x-coordinate of the image, in meters 29 | */ 30 | public double getImageCenterX(); 31 | /** 32 | * @return the center y-coordinate of 33 | */ 34 | public double getImageCenterY(); 35 | /** 36 | * @return the processed javafx image of the field 37 | */ 38 | public Image getImage(); 39 | 40 | @DeserializedJSONDeterminer 41 | public static Class determiner() throws JSONDeserializerException { 42 | return HReferenceFieldImage.class; 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HFieldSize.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import com.jlbabilino.json.DeserializedJSONArrayItem; 4 | import com.jlbabilino.json.DeserializedJSONConstructor; 5 | import com.jlbabilino.json.JSONDeserializable; 6 | import com.jlbabilino.json.JSONSerializable; 7 | import com.jlbabilino.json.SerializedJSONArrayItem; 8 | import com.jlbabilino.json.JSONEntry.JSONType; 9 | 10 | @JSONSerializable(JSONType.ARRAY) 11 | @JSONDeserializable({JSONType.ARRAY}) 12 | public class HFieldSize { 13 | 14 | @SerializedJSONArrayItem(index = 0) 15 | public final double width; 16 | @SerializedJSONArrayItem(index = 1) 17 | public final double height; 18 | 19 | @DeserializedJSONConstructor 20 | public HFieldSize( 21 | @DeserializedJSONArrayItem(index = 0) double width, 22 | @DeserializedJSONArrayItem(index = 1) double height) { 23 | this.width = width; 24 | this.height = height; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HFieldUnit.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import javax.measure.MetricPrefix; 4 | import javax.measure.Unit; 5 | import javax.measure.quantity.Length; 6 | 7 | import com.jlbabilino.json.DeserializedJSONConstructor; 8 | import com.jlbabilino.json.DeserializedJSONEntry; 9 | import com.jlbabilino.json.JSONDeserializable; 10 | import com.jlbabilino.json.JSONEntry.JSONType; 11 | 12 | import si.uom.SI; 13 | import systems.uom.common.USCustomary; 14 | 15 | import com.jlbabilino.json.JSONSerializable; 16 | import com.jlbabilino.json.SerializedJSONEntry; 17 | 18 | @JSONSerializable(JSONType.STRING) 19 | @JSONDeserializable({JSONType.STRING}) 20 | public class HFieldUnit { 21 | 22 | @SerializedJSONEntry 23 | public final String unitName; 24 | 25 | public final Unit unit; 26 | 27 | @DeserializedJSONConstructor 28 | public HFieldUnit(@DeserializedJSONEntry String unitName) { 29 | this.unitName = unitName; 30 | 31 | // WPILib docs: 32 | // "The field units are case-insensitive and can be in meters, cm, 33 | // mm, inches, feet, yards, or miles. Singular, plural, and 34 | // abbreviations are supported (e.g. “meter”,”meters”, and ”m” are 35 | // all valid for specifying meters)" 36 | switch (unitName.trim().toLowerCase()) { 37 | default: 38 | case "meter": 39 | case "m": 40 | case "meters": 41 | this.unit = SI.METRE; 42 | break; 43 | case "centimeter": 44 | case "cm": 45 | case "centimeters": 46 | this.unit = MetricPrefix.CENTI(SI.METRE); 47 | break; 48 | case "millimeter": 49 | case "mm": 50 | case "millimeters": 51 | this.unit = MetricPrefix.MILLI(SI.METRE); 52 | break; 53 | case "inch": 54 | case "in": 55 | case "inches": 56 | this.unit = USCustomary.INCH; 57 | break; 58 | case "foot": 59 | case "ft": 60 | case "feet": 61 | this.unit = USCustomary.FOOT; 62 | break; 63 | case "yard": 64 | case "yd": 65 | case "yards": 66 | this.unit = USCustomary.YARD; 67 | break; 68 | case "mile": 69 | case "mi": 70 | case "miles": 71 | this.unit = USCustomary.MILE; 72 | break; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/field/image/HReferenceFieldImage.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.field.image; 2 | 3 | import com.jlbabilino.json.DeserializedJSONConstructor; 4 | import com.jlbabilino.json.DeserializedJSONObjectValue; 5 | import com.jlbabilino.json.JSONDeserializable; 6 | import com.jlbabilino.json.JSONSerializable; 7 | import com.jlbabilino.json.SerializedJSONObjectValue; 8 | import com.jlbabilino.json.JSONEntry.JSONType; 9 | 10 | import org.team2363.helixnavigator.global.DefaultFieldImages; 11 | import org.team2363.helixnavigator.global.DefaultResourceUnavailableException; 12 | 13 | import javafx.scene.image.Image; 14 | 15 | @JSONSerializable(JSONType.OBJECT) 16 | @JSONDeserializable({JSONType.OBJECT}) 17 | public class HReferenceFieldImage implements HFieldImage { 18 | 19 | private final HDefaultFieldImage fieldImage; 20 | 21 | @DeserializedJSONConstructor 22 | public HReferenceFieldImage( 23 | @DeserializedJSONObjectValue(key = "default") String name) throws DefaultResourceUnavailableException { 24 | fieldImage = DefaultFieldImages.forName(name); 25 | } 26 | 27 | @SerializedJSONObjectValue(key = "default") 28 | @Override 29 | public String getName() { 30 | return fieldImage.getName(); 31 | } 32 | 33 | @Override 34 | public double getFieldAreaWidth() { 35 | return fieldImage.getFieldAreaWidth(); 36 | } 37 | 38 | @Override 39 | public double getFieldAreaHeight() { 40 | return fieldImage.getFieldAreaHeight(); 41 | } 42 | 43 | @Override 44 | public double getImageRes() { 45 | return fieldImage.getImageRes(); 46 | } 47 | 48 | @Override 49 | public double getImageCenterX() { 50 | return fieldImage.getImageCenterX(); 51 | } 52 | 53 | @Override 54 | public double getImageCenterY() { 55 | return fieldImage.getImageCenterY(); 56 | } 57 | 58 | @Override 59 | public Image getImage() { 60 | return fieldImage.getImage(); 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/obstacle/HCircleObstacle.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.obstacle; 2 | 3 | import java.util.List; 4 | 5 | import org.team2363.helixtrajectory.Obstacle; 6 | import org.team2363.helixtrajectory.ObstaclePoint; 7 | 8 | import com.jlbabilino.json.DeserializedJSONConstructor; 9 | import com.jlbabilino.json.DeserializedJSONObjectValue; 10 | import com.jlbabilino.json.DeserializedJSONTarget; 11 | import com.jlbabilino.json.SerializedJSONObjectValue; 12 | 13 | import javafx.beans.property.DoubleProperty; 14 | import javafx.beans.property.SimpleDoubleProperty; 15 | import javafx.geometry.Point2D; 16 | import javafx.scene.transform.Transform; 17 | 18 | public class HCircleObstacle extends HObstacle { 19 | 20 | private final DoubleProperty centerX = new SimpleDoubleProperty(this, "centerX", 0.0); 21 | private final DoubleProperty centerY = new SimpleDoubleProperty(this, "centerY", 0.0); 22 | private final DoubleProperty radius = new SimpleDoubleProperty(this, "radius", 10.0); 23 | 24 | @DeserializedJSONConstructor 25 | public HCircleObstacle() { 26 | } 27 | 28 | @Override 29 | public Obstacle toObstacle() { 30 | return new Obstacle(getSafetyDistance() + getRadius(), true, List.of(new ObstaclePoint(getCenterX(), getCenterY()))); 31 | } 32 | 33 | @Override 34 | public void transformRelative(Transform transform) { 35 | Point2D newCenter = transform.transform(getCenterX(), getCenterY()); 36 | setCenterX(newCenter.getX()); 37 | setCenterY(newCenter.getY()); 38 | } 39 | 40 | @Override 41 | public void translateRelativeX(double dx) { 42 | setCenterX(getCenterX() + dx); 43 | } 44 | 45 | @Override 46 | public void translateRelativeY(double dy) { 47 | setCenterY(getCenterY() + dy); 48 | } 49 | 50 | public final DoubleProperty centerXProperty() { 51 | return centerX; 52 | } 53 | 54 | @DeserializedJSONTarget 55 | public final void setCenterX(@DeserializedJSONObjectValue(key = "center_x") double value) { 56 | centerX.set(value); 57 | } 58 | 59 | @SerializedJSONObjectValue(key = "center_x") 60 | public final double getCenterX() { 61 | return centerX.get(); 62 | } 63 | 64 | public final DoubleProperty centerYProperty() { 65 | return centerY; 66 | } 67 | 68 | @DeserializedJSONTarget 69 | public final void setCenterY(@DeserializedJSONObjectValue(key = "center_y") double value) { 70 | centerY.set(value); 71 | } 72 | 73 | @SerializedJSONObjectValue(key = "center_y") 74 | public final double getCenterY() { 75 | return centerY.get(); 76 | } 77 | 78 | public final DoubleProperty radiusProperty() { 79 | return radius; 80 | } 81 | 82 | @DeserializedJSONTarget 83 | public final void setRadius(@DeserializedJSONObjectValue(key = "radius") double value) { 84 | radius.set(value); 85 | } 86 | 87 | @SerializedJSONObjectValue(key = "radius") 88 | public final double getRadius() { 89 | return radius.get(); 90 | } 91 | 92 | @Override 93 | public ObstacleType getObstacleType() { 94 | return ObstacleType.CIRCLE; 95 | } 96 | 97 | @Override 98 | public boolean isCircle() { 99 | return true; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/obstacle/HPolygonObstacle.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.obstacle; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.team2363.helixtrajectory.Obstacle; 7 | import org.team2363.helixtrajectory.ObstaclePoint; 8 | 9 | import com.jlbabilino.json.DeserializedJSONConstructor; 10 | import com.jlbabilino.json.DeserializedJSONObjectValue; 11 | import com.jlbabilino.json.SerializedJSONObjectValue; 12 | 13 | import javafx.collections.FXCollections; 14 | import javafx.collections.ObservableList; 15 | import javafx.scene.transform.Transform; 16 | 17 | public class HPolygonObstacle extends HObstacle { 18 | 19 | private final ObservableList points = FXCollections.observableArrayList(); 20 | 21 | public HPolygonObstacle() { 22 | HPolygonPoint[] initialPoints = new HPolygonPoint[3]; 23 | for (int i = 0; i < initialPoints.length; i++) { 24 | initialPoints[i] = new HPolygonPoint(); 25 | } 26 | initialPoints[0].setX(0.0); 27 | initialPoints[0].setY(0.0); 28 | initialPoints[1].setX(2.0); 29 | initialPoints[1].setY(0.0); 30 | initialPoints[2].setX(1.0); 31 | initialPoints[2].setY(2.0); 32 | points.addAll(initialPoints[0], initialPoints[1], initialPoints[2]); 33 | } 34 | 35 | @DeserializedJSONConstructor 36 | public HPolygonObstacle(@DeserializedJSONObjectValue(key = "points") List initialPoints) { 37 | points.setAll(initialPoints); 38 | } 39 | 40 | @Override 41 | public Obstacle toObstacle() { 42 | List obstaclePoints = new ArrayList<>(points.size()); 43 | for (int i = 0; i < points.size(); i++) { 44 | obstaclePoints.add(points.get(i).toObstaclePoint()); 45 | } 46 | return new Obstacle(getSafetyDistance(), true, obstaclePoints); 47 | } 48 | 49 | @Override 50 | public void transformRelative(Transform transform) { 51 | points.forEach(point -> point.transformRelative(transform)); 52 | } 53 | 54 | @Override 55 | public void translateRelativeX(double dx) { 56 | points.forEach(point -> point.translateRelativeX(dx)); 57 | } 58 | 59 | @Override 60 | public void translateRelativeY(double dy) { 61 | points.forEach(point -> point.translateRelativeY(dy)); 62 | } 63 | 64 | @SerializedJSONObjectValue(key = "points") 65 | public ObservableList getPoints() { 66 | return points; 67 | } 68 | 69 | public ObstacleType getObstacleType() { 70 | return ObstacleType.POLYGON; 71 | } 72 | 73 | @Override 74 | public boolean isPolygon() { 75 | return true; 76 | } 77 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/obstacle/HPolygonPoint.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.HSelectableElement; 4 | import org.team2363.helixtrajectory.ObstaclePoint; 5 | 6 | import com.jlbabilino.json.DeserializedJSONConstructor; 7 | import com.jlbabilino.json.DeserializedJSONObjectValue; 8 | import com.jlbabilino.json.DeserializedJSONTarget; 9 | import com.jlbabilino.json.JSONDeserializable; 10 | import com.jlbabilino.json.JSONSerializable; 11 | import com.jlbabilino.json.SerializedJSONObjectValue; 12 | import com.jlbabilino.json.JSONEntry.JSONType; 13 | 14 | import javafx.beans.property.DoubleProperty; 15 | import javafx.beans.property.SimpleDoubleProperty; 16 | import javafx.geometry.Point2D; 17 | import javafx.scene.transform.Transform; 18 | 19 | @JSONSerializable(JSONType.OBJECT) 20 | @JSONDeserializable({JSONType.OBJECT}) 21 | public class HPolygonPoint extends HSelectableElement { 22 | 23 | private final DoubleProperty x = new SimpleDoubleProperty(this, "x", 0.0); 24 | private final DoubleProperty y = new SimpleDoubleProperty(this, "y", 0.0); 25 | 26 | @DeserializedJSONConstructor 27 | public HPolygonPoint() { 28 | } 29 | 30 | @Override 31 | public void transformRelative(Transform transform) { 32 | Point2D newPoint = transform.transform(getX(), getY()); 33 | setX(newPoint.getX()); 34 | setY(newPoint.getY()); 35 | } 36 | 37 | @Override 38 | public void translateRelativeX(double dx) { 39 | setX(getX() + dx); 40 | } 41 | 42 | @Override 43 | public void translateRelativeY(double dy) { 44 | setY(getY() + dy); 45 | } 46 | 47 | public ObstaclePoint toObstaclePoint() { 48 | return new ObstaclePoint(getX(), getY()); 49 | } 50 | 51 | public final DoubleProperty xProperty() { 52 | return x; 53 | } 54 | 55 | @DeserializedJSONTarget 56 | public final void setX(@DeserializedJSONObjectValue(key = "x") double value) { 57 | x.set(value); 58 | } 59 | 60 | @SerializedJSONObjectValue(key = "x") 61 | public final double getX() { 62 | return x.get(); 63 | } 64 | 65 | public final DoubleProperty yProperty() { 66 | return y; 67 | } 68 | 69 | @DeserializedJSONTarget 70 | public final void setY(@DeserializedJSONObjectValue(key = "y") double value) { 71 | y.set(value); 72 | } 73 | 74 | @SerializedJSONObjectValue(key = "y") 75 | public final double getY() { 76 | return y.get(); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/timeline/HHardWaypoint.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.timeline; 2 | 3 | import java.util.List; 4 | 5 | import org.team2363.helixtrajectory.HolonomicWaypoint; 6 | import org.team2363.helixtrajectory.InitialGuessPoint; 7 | import org.team2363.helixtrajectory.Obstacle; 8 | 9 | import com.jlbabilino.json.DeserializedJSONConstructor; 10 | import com.jlbabilino.json.DeserializedJSONObjectValue; 11 | import com.jlbabilino.json.DeserializedJSONTarget; 12 | import com.jlbabilino.json.SerializedJSONObjectValue; 13 | 14 | import javafx.beans.property.DoubleProperty; 15 | import javafx.beans.property.SimpleDoubleProperty; 16 | import javafx.scene.transform.Transform; 17 | 18 | public class HHardWaypoint extends HWaypoint { 19 | 20 | private final DoubleProperty heading = new SimpleDoubleProperty(this, "heading", 0.0); 21 | 22 | @DeserializedJSONConstructor 23 | public HHardWaypoint() { 24 | } 25 | 26 | @Override 27 | public void transformRelative(Transform transform) { 28 | super.transformRelative(transform); 29 | double deltaAngle = Math.atan2(transform.getMyx(), transform.getMxx()); 30 | setHeading(getHeading() + deltaAngle); 31 | } 32 | 33 | @Override 34 | public WaypointType getWaypointType() { 35 | return WaypointType.HARD; 36 | } 37 | 38 | @Override 39 | public boolean isHard() { 40 | return true; 41 | } 42 | 43 | public final DoubleProperty headingProperty() { 44 | return heading; 45 | } 46 | 47 | @DeserializedJSONTarget 48 | public final void setHeading(@DeserializedJSONObjectValue(key = "heading") double value) { 49 | heading.set(value); 50 | } 51 | 52 | @SerializedJSONObjectValue(key = "heading") 53 | public final double getHeading() { 54 | return heading.get(); 55 | } 56 | 57 | public HolonomicWaypoint toWaypoint(List initialGuessPoints, List obstacles) { 58 | return new HolonomicWaypoint(getX(), getY(), getHeading(), 0.0, 0.0, 0.0, true, true, true, false, false, false, false, 100, initialGuessPoints, obstacles); 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/timeline/HInitialGuessWaypoint.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.timeline; 2 | 3 | import org.team2363.helixtrajectory.InitialGuessPoint; 4 | 5 | import com.jlbabilino.json.DeserializedJSONConstructor; 6 | import com.jlbabilino.json.DeserializedJSONObjectValue; 7 | import com.jlbabilino.json.DeserializedJSONTarget; 8 | import com.jlbabilino.json.SerializedJSONObjectValue; 9 | 10 | import javafx.beans.property.DoubleProperty; 11 | import javafx.beans.property.SimpleDoubleProperty; 12 | import javafx.scene.transform.Transform; 13 | 14 | public class HInitialGuessWaypoint extends HWaypoint { 15 | 16 | private final DoubleProperty heading = new SimpleDoubleProperty(this, "heading", 0.0); 17 | 18 | @DeserializedJSONConstructor 19 | public HInitialGuessWaypoint() { 20 | } 21 | 22 | @Override 23 | public void transformRelative(Transform transform) { 24 | super.transformRelative(transform); 25 | double deltaAngle = Math.atan2(transform.getMyx(), transform.getMxx()); 26 | setHeading(getHeading() + deltaAngle); 27 | } 28 | 29 | @Override 30 | public WaypointType getWaypointType() { 31 | return WaypointType.INITIAL_GUESS; 32 | } 33 | 34 | @Override 35 | public boolean isInitialGuess() { 36 | return true; 37 | } 38 | 39 | public final DoubleProperty headingProperty() { 40 | return heading; 41 | } 42 | @DeserializedJSONTarget 43 | public final void setHeading(@DeserializedJSONObjectValue(key = "heading") double value) { 44 | heading.set(value); 45 | } 46 | @SerializedJSONObjectValue(key = "heading") 47 | public final double getHeading() { 48 | return heading.get(); 49 | } 50 | 51 | public InitialGuessPoint toInitialGuessPoint() { 52 | return new InitialGuessPoint(getX(), getY(), getHeading()); 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/document/timeline/HSoftWaypoint.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.document.timeline; 2 | 3 | import java.util.List; 4 | 5 | import org.team2363.helixtrajectory.HolonomicWaypoint; 6 | import org.team2363.helixtrajectory.InitialGuessPoint; 7 | import org.team2363.helixtrajectory.Obstacle; 8 | 9 | import com.jlbabilino.json.DeserializedJSONConstructor; 10 | 11 | public class HSoftWaypoint extends HWaypoint { 12 | 13 | @DeserializedJSONConstructor 14 | public HSoftWaypoint() { 15 | } 16 | 17 | @Override 18 | public WaypointType getWaypointType() { 19 | return WaypointType.SOFT; 20 | } 21 | 22 | @Override 23 | public boolean isSoft() { 24 | return true; 25 | } 26 | 27 | public HolonomicWaypoint toWaypoint(List initialGuessPoints, List obstacles) { 28 | return new HolonomicWaypoint(getX(), getY(), 0.0, 0.0, 0.0, 0.0, true, true, false, false, false, false, false, 100, initialGuessPoints, obstacles); 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/global/DefaultResourceUnavailableException.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.global; 2 | 3 | public class DefaultResourceUnavailableException extends RuntimeException { 4 | public DefaultResourceUnavailableException(String message) { 5 | super(message); 6 | } 7 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/global/DefaultResources.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.global; 2 | 3 | public final class DefaultResources { 4 | private DefaultResources() { 5 | } 6 | 7 | public static void loadAllResources() { 8 | DefaultFieldImages.loadDefaultFieldImages(); 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/global/Logs.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.global; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.util.logging.Logger; 7 | import java.util.logging.SimpleFormatter; 8 | import java.util.logging.StreamHandler; 9 | 10 | public final class Logs { 11 | 12 | private static final Logger GLOBAL_LOGGER = Logger.getLogger("org.team2363.helixnavigator"); 13 | private static final File LOG_FILE = new File(Standards.USER_DOCUMENTS_DIR, "HelixNavigator/helixnavigator.log"); 14 | private static FileOutputStream fileOut = null; 15 | 16 | private Logs() { 17 | } 18 | 19 | public static void initialize() { 20 | try { 21 | if (!LOG_FILE.exists()) { 22 | LOG_FILE.getParentFile().mkdirs(); 23 | LOG_FILE.createNewFile(); 24 | } 25 | fileOut = new FileOutputStream(LOG_FILE); 26 | if (LOG_FILE.canWrite() && LOG_FILE.canRead()) { 27 | GLOBAL_LOGGER.addHandler(new StreamHandler(fileOut, new SimpleFormatter())); 28 | } else { 29 | GLOBAL_LOGGER.warning("Could not log to file \"" + LOG_FILE.getAbsolutePath() + "\""); 30 | } 31 | } catch (IOException e) { 32 | GLOBAL_LOGGER.warning("Could not log to file \"" + LOG_FILE.getAbsolutePath() + "\" -- IO exception."); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/EditorTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | // package com.team2363.helixnavigator.ui.editor; 3 | 4 | // import javafx.application.Application; 5 | // import javafx.scene.Scene; 6 | // import javafx.scene.canvas.GraphicsContext; 7 | // import javafx.scene.layout.StackPane; 8 | // import javafx.scene.paint.Color; 9 | // import javafx.stage.Stage; 10 | 11 | // public class EditorTest extends Application { 12 | // public static void main(String[] args) { 13 | // launch(args); 14 | // } 15 | 16 | // @Override 17 | // public void start(Stage primaryStage) throws Exception { 18 | // primaryStage.setWidth(1500); 19 | // primaryStage.setHeight(1000); 20 | // TrajectoryPane pane = new TrajectoryPane(primaryStage.widthProperty(), primaryStage.heightProperty()); 21 | // Scene scene = new Scene(pane, 1800, 900); 22 | 23 | // primaryStage.setScene(scene); 24 | // primaryStage.show(); 25 | 26 | // // Canvas canvas = new Canvas(800, 500); 27 | // // StackPane pane = new StackPane(); 28 | // // Scene scene = new Scene(pane, 800, 500); 29 | // // GraphicsContext gc = canvas.getGraphicsContext2D(); 30 | // // gc.setStroke(Color.BLACK); 31 | // // gc.setLineWidth(10); 32 | // // scene.setOnMousePressed(e -> { 33 | // // gc.beginPath(); 34 | // // gc.lineTo(e.getSceneX(), e.getSceneY()); 35 | // // gc.stroke(); 36 | // // }); 37 | // // scene.setOnMouseDragged(e -> { 38 | // // gc.lineTo(e.getSceneX(), e.getSceneY()); 39 | // // gc.stroke(); 40 | // // }); 41 | 42 | // // pane.getChildren().add(canvas); 43 | // // primaryStage.setScene(scene); 44 | // // primaryStage.show(); 45 | 46 | // } 47 | 48 | // } 49 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/FilePromptTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | 3 | import java.io.File; 4 | 5 | import javafx.application.Application; 6 | import javafx.event.ActionEvent; 7 | import javafx.event.EventHandler; 8 | import javafx.scene.Scene; 9 | import javafx.scene.control.Button; 10 | import javafx.scene.layout.StackPane; 11 | import javafx.stage.FileChooser; 12 | import javafx.stage.Stage; 13 | 14 | public class FilePromptTest extends Application { 15 | 16 | public static void main(String[] args) { 17 | launch(args); 18 | } 19 | 20 | @Override 21 | public void start(Stage primaryStage) { 22 | primaryStage.setTitle("File Chooser Test"); 23 | Button btn = new Button(); 24 | btn.setText("Open File Chooser"); 25 | btn.setOnAction(new EventHandler() { 26 | @Override 27 | public void handle(ActionEvent event) { 28 | FileChooser fileChooser = new FileChooser(); 29 | File file = fileChooser.showOpenDialog(primaryStage); 30 | System.out.println("file path:"); 31 | System.out.println(file.getAbsolutePath()); 32 | } 33 | }); 34 | 35 | StackPane root = new StackPane(); 36 | root.getChildren().add(btn); 37 | primaryStage.setScene(new Scene(root, 300, 250)); 38 | primaryStage.show(); 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/JavaFxListView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | // this was downloaded from https://newbedev.com/listview-using-custom-cell-factory-doesn-t-update-after-items-deleted 3 | // thanks! 4 | import javafx.application.Application; 5 | import javafx.collections.FXCollections; 6 | import javafx.collections.ObservableList; 7 | import javafx.scene.Scene; 8 | import javafx.scene.control.Button; 9 | import javafx.scene.control.ListCell; 10 | import javafx.scene.control.ListView; 11 | import javafx.scene.layout.VBox; 12 | import javafx.stage.Stage; 13 | import javafx.util.Callback; 14 | 15 | public class JavaFxListView extends Application { 16 | 17 | private static class Car { 18 | private String plate; 19 | 20 | public Car(String plate, String string2, String string3, double d) { 21 | this.plate = plate; 22 | } 23 | 24 | public String getPlate() { 25 | return plate; 26 | } 27 | 28 | } 29 | 30 | public static void main(String[] args) { 31 | launch(args); 32 | } 33 | 34 | @Override 35 | public void start(Stage arg0) throws Exception { 36 | ListView plateList = new ListView(); 37 | plateList.setCellFactory(new Callback, ListCell>() { 38 | 39 | @Override 40 | public ListCell call(ListView param) { 41 | ListCell cell = new ListCell() { 42 | 43 | @Override 44 | protected void updateItem(Car item, boolean empty) { 45 | super.updateItem(item, empty); 46 | if (item != null) { 47 | setText(item.getPlate()); 48 | } else { 49 | setText(""); 50 | } 51 | } 52 | }; 53 | return cell; 54 | } 55 | }); 56 | Button delete = new Button("Delete"); 57 | ObservableList sample = FXCollections.observableArrayList(); 58 | sample.add(new Car("123-abc", "opel", "corsa", 5.5)); 59 | sample.add(new Car("123-cba", "vw", "passat", 7.5)); 60 | 61 | delete.setOnAction((e) -> { 62 | plateList.getItems().remove(plateList.getSelectionModel().getSelectedItem()); 63 | ObservableList t = plateList.getItems(); 64 | plateList.setItems(t); 65 | }); 66 | 67 | plateList.setItems(sample); 68 | arg0.setScene(new Scene(new VBox(plateList, delete))); 69 | arg0.show(); 70 | } 71 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/ObstacleTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | 3 | import com.jlbabilino.json.JSON; 4 | import com.jlbabilino.json.JSONDeserializer; 5 | import com.jlbabilino.json.JSONSerializer; 6 | 7 | import org.team2363.helixnavigator.document.obstacle.HCircleObstacle; 8 | import org.team2363.helixnavigator.document.obstacle.HObstacle; 9 | 10 | public class ObstacleTest { 11 | public static void main(String[] args) throws Exception { 12 | 13 | HObstacle obstacle = new HCircleObstacle(); 14 | JSON json = JSONSerializer.serializeJSON(obstacle); 15 | System.out.println("original:"); 16 | System.out.println(json); 17 | HObstacle newObstacle = JSONDeserializer.deserialize(json, HObstacle.class); 18 | JSON newJSON = JSONSerializer.serializeJSON(newObstacle); 19 | System.out.println("new:"); 20 | System.out.println(newJSON); 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/SelectionModelTest.java: -------------------------------------------------------------------------------- 1 | // package org.team2363.helixnavigator.testcode; 2 | 3 | // import org.team2363.helixnavigator.document.HPathElement; 4 | // import org.team2363.helixnavigator.document.HSelectionModel; 5 | // import org.team2363.helixnavigator.document.obstacle.HPolygonPoint; 6 | 7 | // import javafx.collections.FXCollections; 8 | // import javafx.collections.ObservableList; 9 | 10 | // public class SelectionModelTest { 11 | // public static void main(String[] args) { 12 | // HPolygonPoint[] points = new HPolygonPoint[10]; 13 | // for (int i = 0; i < points.length; i++) { 14 | // points[i] = new HPolygonPoint(); 15 | // points[i].setName("point_" + i); 16 | // } 17 | // ObservableList items = FXCollections.observableArrayList(points[0], points[1]); 18 | // HSelectionModel selectionModel = new HSelectionModel<>(items); 19 | // selectionModel.select(0); 20 | // printStuff(items, selectionModel); 21 | // items.add(0, points[2]); 22 | // printStuff(items, selectionModel); 23 | // items.remove(0); 24 | // printStuff(items, selectionModel); 25 | // } 26 | 27 | // private static void printStuff(ObservableList items, HSelectionModel selectionModel) { 28 | // System.out.println(); 29 | // System.out.println("Items: " + items); 30 | // System.out.println("Selected Indicies: " + selectionModel.getSelectedIndices()); 31 | // System.out.println("Selected Items: " + selectionModel.getSelectedItems()); 32 | // } 33 | // } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/ToolbarTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | // package com.team2363.helixnavigator.ui.editor; 3 | 4 | // import com.team2363.helixnavigator.ui.toolbar.Toolbar; 5 | 6 | // import javafx.application.Application; 7 | // import javafx.beans.property.DoubleProperty; 8 | // import javafx.beans.property.SimpleDoubleProperty; 9 | // import javafx.scene.Scene; 10 | // import javafx.scene.control.ScrollPane; 11 | // import javafx.stage.Stage; 12 | 13 | // public class ToolbarTest extends Application { 14 | // public static void main(String[] args) { 15 | // launch(args); 16 | // } 17 | // @Override 18 | // public void start(Stage stage) throws Exception { 19 | // // Toolbar topToolbar = new TopToolbar(); 20 | // // Scene scene = new Scene(topToolbar); 21 | // // stage.setScene(scene); 22 | // DoubleProperty num = new SimpleDoubleProperty(); 23 | // num.addListener((currentVal, oldVal, newVal) -> System.out.println(newVal)); 24 | // num.set(0.1); 25 | // num.set(123.231); 26 | // num.set(-12); 27 | // num.set(656); 28 | // } 29 | 30 | // } 31 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/WapyointTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode; 2 | 3 | import javafx.application.Application; 4 | import javafx.scene.Scene; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Circle; 8 | import javafx.stage.Stage; 9 | 10 | public class WapyointTest extends Application { 11 | public static void main(String[] args) { 12 | launch(args); 13 | } 14 | 15 | @Override 16 | public void start(Stage primaryStage) throws Exception { 17 | Circle circle = new Circle(); 18 | circle.setFill(Color.BLUE); 19 | circle.setRadius(10); 20 | circle.setStroke(Color.ORANGE); 21 | circle.setOnMouseDragged(event -> { 22 | System.out.print("dragging: x: "); 23 | System.out.print(event.getX() + " y: "); 24 | System.out.println(event.getY()); 25 | circle.setCenterX(event.getX()); 26 | circle.setCenterY(event.getY()); 27 | }); 28 | circle.setOnMousePressed(event -> { 29 | System.out.println("into drag"); 30 | circle.setStrokeWidth(6); 31 | }); 32 | circle.setOnMouseReleased(event -> { 33 | System.out.println("out of drag"); 34 | circle.setStrokeWidth(0); 35 | }); 36 | Pane stack = new Pane(); 37 | stack.getChildren().add(circle); 38 | Scene scene = new Scene(stack); 39 | primaryStage.setScene(scene); 40 | primaryStage.show(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/jenkov/Point.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode.jenkov; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.beans.property.SimpleDoubleProperty; 5 | 6 | public class Point { 7 | 8 | private DoubleProperty x = new SimpleDoubleProperty(this, "x", 0.0); 9 | private DoubleProperty y = new SimpleDoubleProperty(this, "y", 0.0); 10 | 11 | public Point() { 12 | } 13 | 14 | public DoubleProperty xProperty() { 15 | return x; 16 | } 17 | 18 | public void setX(double value) { 19 | x.set(value); 20 | } 21 | 22 | public double getX() { 23 | return x.get(); 24 | } 25 | 26 | public DoubleProperty yProperty() { 27 | return y; 28 | } 29 | 30 | public void setY(double value) { 31 | y.set(value); 32 | } 33 | 34 | public double getY() { 35 | return y.get(); 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/testcode/jenkov/TableViewExample.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.testcode.jenkov; 2 | 3 | import javafx.application.Application; 4 | import javafx.scene.Scene; 5 | import javafx.scene.control.TableCell; 6 | import javafx.scene.control.TableColumn; 7 | import javafx.scene.control.TableView; 8 | import javafx.scene.control.cell.PropertyValueFactory; 9 | import javafx.scene.control.cell.TextFieldTableCell; 10 | import javafx.scene.layout.VBox; 11 | import javafx.stage.Stage; 12 | import javafx.util.StringConverter; 13 | 14 | public class TableViewExample extends Application { 15 | 16 | private final StringConverter decimalConverter = new StringConverter() { 17 | 18 | @Override 19 | public String toString(Double object) { 20 | if (object != null) { 21 | return Double.toString(object); 22 | } else { 23 | return ""; 24 | } 25 | } 26 | 27 | @Override 28 | public Double fromString(String string) { 29 | double rawValue; 30 | try { 31 | rawValue = Double.parseDouble(string); 32 | } catch (NumberFormatException e) { 33 | rawValue = 0.0; 34 | } 35 | return rawValue; 36 | } 37 | }; 38 | 39 | public static void main(String[] args) { 40 | launch(args); 41 | } 42 | 43 | @Override 44 | public void start(Stage primaryStage) { 45 | 46 | TableView tableView = new TableView<>(); 47 | 48 | TableColumn indexColumn = new TableColumn<>("Index"); 49 | indexColumn.setCellFactory(column -> new TableCell() { 50 | @Override 51 | public void updateIndex(int index) { 52 | super.updateIndex(index); 53 | if (isEmpty() || index < 0) { 54 | setText(null); 55 | } else { 56 | setText(Integer.toString(index + 1)); 57 | } 58 | } 59 | }); 60 | indexColumn.setSortable(false); 61 | indexColumn.setReorderable(false); 62 | 63 | TableColumn xColumn = new TableColumn<>("X Value"); 64 | 65 | xColumn.setCellFactory(TextFieldTableCell.forTableColumn(decimalConverter)); 66 | xColumn.setCellValueFactory(new PropertyValueFactory<>("x")); 67 | xColumn.setSortable(false); 68 | xColumn.setReorderable(false); 69 | 70 | TableColumn yColumn = new TableColumn<>("Y Value"); 71 | 72 | yColumn.setCellValueFactory(new PropertyValueFactory<>("y")); 73 | yColumn.setSortable(false); 74 | yColumn.setReorderable(false); 75 | 76 | tableView.getColumns().add(indexColumn); 77 | tableView.getColumns().add(xColumn); 78 | tableView.getColumns().add(yColumn); 79 | 80 | tableView.setEditable(true); 81 | 82 | tableView.getItems().add(new Point()); 83 | tableView.getItems().add(new Point()); 84 | 85 | VBox vbox = new VBox(tableView); 86 | 87 | Scene scene = new Scene(vbox); 88 | 89 | primaryStage.setScene(scene); 90 | 91 | primaryStage.show(); 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/MainPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.ui.document.DocumentPane; 5 | import org.team2363.helixnavigator.ui.editor.EditorPane; 6 | import org.team2363.helixnavigator.ui.menu.MainMenuBar; 7 | 8 | import javafx.scene.control.SplitPane; 9 | import javafx.scene.layout.VBox; 10 | 11 | public class MainPane extends VBox { 12 | 13 | private final DocumentManager documentManager; 14 | 15 | private final MainMenuBar mainMenuBar; 16 | 17 | private final DocumentPane documentPane; 18 | private final EditorPane editorPane; 19 | private final SplitPane middleRow; 20 | 21 | public MainPane(DocumentManager documentManager) { 22 | this.documentManager = documentManager; 23 | 24 | mainMenuBar = new MainMenuBar(this.documentManager); 25 | 26 | documentPane = new DocumentPane(this.documentManager); 27 | editorPane = new EditorPane(this.documentManager); 28 | middleRow = new SplitPane(documentPane, editorPane); 29 | 30 | getChildren().addAll(mainMenuBar, middleRow); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/MainScene.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.Scene; 6 | 7 | public class MainScene { 8 | 9 | private final Scene scene; 10 | private final MainPane mainPane; 11 | 12 | public MainScene(DocumentManager documentManager) { 13 | mainPane = new MainPane(documentManager); 14 | scene = new Scene(mainPane); 15 | } 16 | 17 | public Scene getScene() { 18 | return scene; 19 | } 20 | 21 | public MainPane getMainPane() { 22 | return mainPane; 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/MainStage.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.stage.Stage; 7 | import javafx.stage.WindowEvent; 8 | 9 | public class MainStage { 10 | 11 | private final Stage stage; 12 | private final DocumentManager documentManager; 13 | private final MainScene mainScene; 14 | 15 | public MainStage(Stage stage) { 16 | this.stage = stage; 17 | documentManager = new DocumentManager(this.stage); 18 | mainScene = new MainScene(documentManager); 19 | this.stage.setTitle(Standards.APPLICATION_NAME); 20 | this.stage.setHeight(700); 21 | this.stage.setWidth(1200); 22 | this.stage.setMinWidth(400); 23 | this.stage.setMinHeight(100); 24 | this.stage.setOnCloseRequest(this::onWindowCloseRequest); 25 | this.stage.setScene(mainScene.getScene()); 26 | } 27 | 28 | public void show() { 29 | stage.show(); 30 | } 31 | 32 | private void onWindowCloseRequest(WindowEvent event) { 33 | if (!documentManager.requestCloseDocument()) { // if document NOT closed, don't close window 34 | event.consume(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/document/DocumentPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.document; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.geometry.Insets; 6 | import javafx.scene.layout.Priority; 7 | import javafx.scene.layout.VBox; 8 | 9 | public class DocumentPane extends VBox { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | private final PathChooserBox pathChooserBox; 14 | private final WaypointListView waypointListView; 15 | private final ObstacleListView obstacleListView; 16 | 17 | public DocumentPane(DocumentManager documentManager) { 18 | this.documentManager = documentManager; 19 | 20 | pathChooserBox = new PathChooserBox(this.documentManager); 21 | waypointListView = new WaypointListView(this.documentManager); 22 | obstacleListView = new ObstacleListView(this.documentManager); 23 | 24 | setPadding(new Insets(10, 5, 10, 10)); 25 | setSpacing(10.0); 26 | VBox.setVgrow(waypointListView, Priority.ALWAYS); 27 | VBox.setVgrow(obstacleListView, Priority.ALWAYS); 28 | 29 | getChildren().addAll(pathChooserBox, waypointListView, obstacleListView); 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/document/PathListCell.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.document; 2 | 3 | import org.team2363.helixnavigator.document.HPath; 4 | 5 | import javafx.scene.control.ListCell; 6 | import javafx.scene.control.ListView; 7 | import javafx.util.Callback; 8 | 9 | public class PathListCell extends ListCell { 10 | 11 | public static final Callback, ListCell> PATH_CELL_FACTORY = 12 | new Callback, ListCell>() { 13 | @Override 14 | public ListCell call(ListView listView) { 15 | return new PathListCell(); 16 | } 17 | }; 18 | 19 | public PathListCell() { 20 | } 21 | 22 | @Override 23 | public void updateItem(HPath item, boolean empty) { 24 | super.updateItem(item, empty); 25 | textProperty().unbind(); 26 | if (empty || item == null) { 27 | setText(""); 28 | } else { 29 | textProperty().bind(item.nameProperty()); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/EditorPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.document.HDocument; 5 | import org.team2363.helixnavigator.ui.editor.toolbar.PathToolBar; 6 | import org.team2363.helixnavigator.ui.editor.toolbar.TrajectoryToolBar; 7 | 8 | import javafx.beans.value.ObservableValue; 9 | import javafx.geometry.Insets; 10 | import javafx.geometry.Pos; 11 | import javafx.scene.layout.Priority; 12 | import javafx.scene.layout.StackPane; 13 | import javafx.scene.layout.VBox; 14 | 15 | public class EditorPane extends VBox { 16 | 17 | private final DocumentManager documentManager; 18 | 19 | private final PathToolBar pathToolBar; 20 | private final PathPane pathPane; 21 | private final InfoText infoText; 22 | private final StackPane middleStack; 23 | private final TrajectoryToolBar trajectoryToolBar; 24 | 25 | public EditorPane(DocumentManager documentManager) { 26 | this.documentManager = documentManager; 27 | 28 | pathToolBar = new PathToolBar(this.documentManager); 29 | pathPane = new PathPane(this.documentManager); 30 | infoText = new InfoText(); 31 | middleStack = new StackPane(infoText); 32 | trajectoryToolBar = new TrajectoryToolBar(this.documentManager); 33 | 34 | setPadding(new Insets(0, 0, 10, 5)); 35 | setSpacing(10.0); 36 | VBox.setVgrow(middleStack, Priority.ALWAYS); 37 | setAlignment(Pos.CENTER); 38 | 39 | middleStack.layoutBoundsProperty().addListener((currentValue, oldValue, newValue) -> { 40 | this.documentManager.setPathAreaWidth(newValue.getWidth()); 41 | this.documentManager.setPathAreaHeight(newValue.getHeight()); 42 | if (this.documentManager.actions().getLockZoom()) { 43 | this.documentManager.actions().zoomToFit(); 44 | } 45 | }); 46 | 47 | getChildren().addAll(pathToolBar, middleStack, trajectoryToolBar); 48 | 49 | loadDocument(this.documentManager.getDocument()); 50 | this.documentManager.documentProperty().addListener(this::documentChanged); //TODO: move all of these things to end of constructor 51 | } 52 | 53 | private void documentChanged(ObservableValue currentDocument, HDocument oldDocument, HDocument newDocument) { 54 | loadDocument(newDocument); 55 | } 56 | 57 | private void loadDocument(HDocument newDocument) { 58 | if (newDocument != null) { 59 | disableInfoText(); 60 | } else { 61 | enableInfoText(); 62 | } 63 | } 64 | 65 | private void disableInfoText() { 66 | middleStack.getChildren().set(0, pathPane); 67 | } 68 | private void enableInfoText() { 69 | middleStack.getChildren().set(0, infoText); 70 | } 71 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/InfoText.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor; 2 | 3 | import org.team2363.helixnavigator.global.Standards; 4 | 5 | import javafx.scene.layout.Background; 6 | import javafx.scene.layout.BackgroundFill; 7 | import javafx.scene.layout.StackPane; 8 | import javafx.scene.text.Text; 9 | 10 | public class InfoText extends StackPane { 11 | 12 | private final Text text = new Text("NO DOCUMENT OPEN"); 13 | 14 | public InfoText() { 15 | getChildren().addAll(text); 16 | setBackground(new Background(new BackgroundFill(Standards.BACKGROUND_COLOR, null, null))); 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/PathElementsPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.document.HDocument; 5 | import org.team2363.helixnavigator.ui.editor.field.FieldImagePane; 6 | import org.team2363.helixnavigator.ui.editor.line.LinesPane; 7 | import org.team2363.helixnavigator.ui.editor.obstacle.ObstaclesPane; 8 | import org.team2363.helixnavigator.ui.editor.trajectory.TrajectoryPane; 9 | import org.team2363.helixnavigator.ui.editor.waypoint.WaypointsPane; 10 | 11 | import javafx.beans.value.ObservableValue; 12 | import javafx.scene.layout.Pane; 13 | import javafx.scene.transform.Translate; 14 | 15 | public class PathElementsPane extends Pane { 16 | 17 | private final DocumentManager documentManager; 18 | 19 | private final FieldImagePane fieldImagePane; 20 | private final TrajectoryPane trajectoryPane; 21 | private final ObstaclesPane obstaclesPane; 22 | private final LinesPane linesPane; 23 | private final WaypointsPane waypointsPane; 24 | 25 | private final Translate pathAreaTranslate = new Translate(); 26 | private final Translate zoomTranslateTranslate = new Translate(); 27 | 28 | public PathElementsPane(DocumentManager documentManager) { 29 | this.documentManager = documentManager; 30 | 31 | fieldImagePane = new FieldImagePane(this.documentManager); 32 | trajectoryPane = new TrajectoryPane(this.documentManager); 33 | obstaclesPane = new ObstaclesPane(this.documentManager); 34 | linesPane = new LinesPane(this.documentManager); 35 | waypointsPane = new WaypointsPane(this.documentManager); 36 | 37 | getChildren().addAll(fieldImagePane, trajectoryPane, obstaclesPane, linesPane, waypointsPane); 38 | setPickOnBounds(false); 39 | 40 | pathAreaTranslate.xProperty().bind(this.documentManager.pathAreaWidthProperty().multiply(0.5)); 41 | pathAreaTranslate.yProperty().bind(this.documentManager.pathAreaHeightProperty().multiply(0.5)); 42 | 43 | getTransforms().addAll(pathAreaTranslate, zoomTranslateTranslate); 44 | 45 | loadDocument(this.documentManager.getDocument()); 46 | this.documentManager.documentProperty().addListener(this::documentChanged); // TODO: move all of these things to end of constructor 47 | } 48 | 49 | private void documentChanged(ObservableValue currentDocument, HDocument oldDocument, HDocument newDocument) { 50 | unloadDocument(oldDocument); 51 | loadDocument(newDocument); 52 | } 53 | 54 | private void unloadDocument(HDocument oldDocument) { 55 | if (oldDocument != null) { 56 | zoomTranslateTranslate.xProperty().unbind(); 57 | zoomTranslateTranslate.yProperty().unbind(); 58 | } 59 | } 60 | 61 | private void loadDocument(HDocument newDocument) { 62 | if (newDocument != null) { 63 | zoomTranslateTranslate.xProperty().bind(newDocument.zoomTranslateXProperty()); 64 | zoomTranslateTranslate.yProperty().bind(newDocument.zoomTranslateYProperty()); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/PathPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.Cursor; 6 | import javafx.scene.input.MouseButton; 7 | import javafx.scene.layout.Pane; 8 | import javafx.scene.shape.Rectangle; 9 | 10 | public class PathPane extends Pane { 11 | 12 | private final DocumentManager documentManager; 13 | 14 | private final BackgroundRectangle backgroundRectangle; 15 | private final PathElementsPane pathElementsPane; 16 | 17 | public PathPane(DocumentManager documentManager) { 18 | this.documentManager = documentManager; 19 | 20 | backgroundRectangle = new BackgroundRectangle(this.documentManager); 21 | pathElementsPane = new PathElementsPane(this.documentManager); 22 | 23 | getChildren().addAll(backgroundRectangle, pathElementsPane, backgroundRectangle.getSelectionRectangle()); 24 | 25 | setOnMousePressed(event -> { 26 | if (this.documentManager.getIsDocumentOpen() && !this.documentManager.actions().getLockZoom() 27 | && event.getButton() == MouseButton.MIDDLE) { 28 | setCursor(Cursor.CLOSED_HAND); 29 | } 30 | this.documentManager.actions().handleMousePressedAsPan(event); 31 | }); 32 | setOnMouseDragged(this.documentManager.actions()::handleMouseDraggedAsPan); 33 | setOnMouseDragged(event -> { 34 | this.documentManager.actions().handleMouseDraggedAsPan(event); 35 | }); 36 | setOnMouseReleased(event -> { 37 | setCursor(Cursor.DEFAULT); 38 | }); 39 | setOnScroll(this.documentManager.actions()::handleScrollAsZoom); 40 | 41 | Rectangle clip = new Rectangle(); 42 | clip.widthProperty().bind(this.documentManager.pathAreaWidthProperty()); 43 | clip.heightProperty().bind(this.documentManager.pathAreaHeightProperty()); 44 | setClip(clip); 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/field/OriginView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.field; 2 | 3 | import javafx.beans.property.BooleanProperty; 4 | import javafx.beans.property.SimpleBooleanProperty; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Circle; 8 | import javafx.scene.shape.Line; 9 | import javafx.scene.shape.StrokeLineCap; 10 | 11 | public class OriginView { 12 | 13 | private final Line xLine = new Line(0, 0, 16, 0); 14 | private final Line xArrowLine1 = new Line(16, 0, 13, -3); 15 | private final Line xArrowLine2 = new Line(16, 0, 13, 3); 16 | private final Line yLine = new Line(0, 0, 0, -16); 17 | private final Line yArrowLine1 = new Line(0, -16, -3, -13); 18 | private final Line yArrowLine2 = new Line(0, -16, 3, -13); 19 | private final Circle outerCircle = new Circle(7); 20 | private final Circle middleCircle = new Circle(5); 21 | private final Circle innerCircle = new Circle(3); 22 | 23 | private final Pane pane = new Pane(xLine, xArrowLine1, xArrowLine2, yLine, yArrowLine1, yArrowLine2, outerCircle, middleCircle, innerCircle); 24 | 25 | private final BooleanProperty enable = new SimpleBooleanProperty(this, "enable", true); 26 | 27 | public OriginView() { 28 | xLine.setStrokeWidth(3); 29 | xArrowLine1.setStrokeWidth(3); 30 | xArrowLine2.setStrokeWidth(3); 31 | yLine.setStrokeWidth(3); 32 | yArrowLine1.setStrokeWidth(3); 33 | yArrowLine2.setStrokeWidth(3); 34 | xLine.setStrokeLineCap(StrokeLineCap.ROUND); 35 | xArrowLine1.setStrokeLineCap(StrokeLineCap.ROUND); 36 | xArrowLine2.setStrokeLineCap(StrokeLineCap.ROUND); 37 | yLine.setStrokeLineCap(StrokeLineCap.ROUND); 38 | yArrowLine1.setStrokeLineCap(StrokeLineCap.ROUND); 39 | yArrowLine2.setStrokeLineCap(StrokeLineCap.ROUND); 40 | outerCircle.setFill(Color.BLACK); 41 | middleCircle.setFill(Color.WHITE); 42 | innerCircle.setFill(Color.BLACK); 43 | 44 | enable.addListener((obs, wasEnable, isEnable) -> { 45 | pane.setOpacity(isEnable ? 1 : 0); 46 | }); 47 | } 48 | 49 | public final BooleanProperty enableProperty() { 50 | return enable; 51 | } 52 | 53 | public final void setEnable(boolean value) { 54 | enable.set(value); 55 | } 56 | 57 | public final boolean isEnable() { 58 | return enable.get(); 59 | } 60 | 61 | public Pane getView() { 62 | return pane; 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/line/LineView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.line; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.beans.property.SimpleDoubleProperty; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Line; 8 | 9 | public class LineView { 10 | 11 | private final Line bottomLine = new Line(); 12 | private final Line topLine = new Line(); 13 | 14 | private final DoubleProperty startPointX = new SimpleDoubleProperty(this, "startPointX", 0.0); 15 | private final DoubleProperty startPointY = new SimpleDoubleProperty(this, "startPointY", 0.0); 16 | private final DoubleProperty endPointX = new SimpleDoubleProperty(this, "endPointX", 0.0); 17 | private final DoubleProperty endPointY = new SimpleDoubleProperty(this, "endPointY", 0.0); 18 | private final DoubleProperty zoomScale = new SimpleDoubleProperty(this, "zoomScale", 1.0); 19 | 20 | private final Pane pane = new Pane(bottomLine, topLine); 21 | 22 | public LineView() { 23 | bottomLine.startXProperty().bind(startPointX.multiply(zoomScale)); 24 | bottomLine.startYProperty().bind(startPointY.multiply(zoomScale).negate()); 25 | bottomLine.endXProperty().bind(endPointX.multiply(zoomScale)); 26 | bottomLine.endYProperty().bind(endPointY.multiply(zoomScale).negate()); 27 | 28 | topLine.startXProperty().bind(startPointX.multiply(zoomScale)); 29 | topLine.startYProperty().bind(startPointY.multiply(zoomScale).negate()); 30 | topLine.endXProperty().bind(endPointX.multiply(zoomScale)); 31 | topLine.endYProperty().bind(endPointY.multiply(zoomScale).negate()); 32 | 33 | bottomLine.setStrokeWidth(4); 34 | bottomLine.setStroke(Color.gray(0.6).deriveColor(0.0, 1.0, 1.0, 0.4)); 35 | topLine.setStrokeWidth(2); 36 | topLine.setStroke(Color.BLACK.deriveColor(0.0, 1.0, 1.0, 0.4)); 37 | } 38 | 39 | public final DoubleProperty startPointXProperty() { 40 | return startPointX; 41 | } 42 | 43 | public final void setStartPointX(double value) { 44 | startPointX.set(value); 45 | } 46 | 47 | public final double getStartPointX() { 48 | return startPointX.get(); 49 | } 50 | 51 | public final DoubleProperty startPointYProperty() { 52 | return startPointY; 53 | } 54 | 55 | public final void setStartPointY(double value) { 56 | startPointY.set(value); 57 | } 58 | 59 | public final double getStartPointY() { 60 | return startPointY.get(); 61 | } 62 | 63 | public final DoubleProperty endPointXProperty() { 64 | return endPointX; 65 | } 66 | 67 | public final void setEndPointX(double value) { 68 | endPointX.set(value); 69 | } 70 | 71 | public final double getEndPointX() { 72 | return endPointX.get(); 73 | } 74 | 75 | public final DoubleProperty endPointYProperty() { 76 | return endPointY; 77 | } 78 | 79 | public final void setEndPointY(double value) { 80 | endPointY.set(value); 81 | } 82 | 83 | public final double getEndPointY() { 84 | return endPointY.get(); 85 | } 86 | 87 | public final DoubleProperty zoomScaleProperty() { 88 | return zoomScale; 89 | } 90 | 91 | public final void setZoomScale(double value) { 92 | zoomScale.set(value); 93 | } 94 | 95 | public final double getZoomScale() { 96 | return zoomScale.get(); 97 | } 98 | 99 | public Pane getView() { 100 | return pane; 101 | } 102 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/obstacle/CircleObstacleView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HCircleObstacle; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Circle; 8 | import javafx.scene.shape.StrokeType; 9 | import javafx.scene.transform.Translate; 10 | 11 | public class CircleObstacleView extends ObstacleView { 12 | 13 | private final HCircleObstacle circleObstacle; 14 | 15 | private final Circle circle = new Circle(); 16 | 17 | private final Translate centerTranslate = new Translate(); 18 | 19 | public CircleObstacleView(HCircleObstacle circleObstacle) { 20 | super(circleObstacle); 21 | 22 | this.circleObstacle = circleObstacle; 23 | 24 | circle.setStroke(Color.ORANGE); 25 | circle.setStrokeWidth(0.0); 26 | circle.setStrokeType(StrokeType.OUTSIDE); 27 | circle.setFill(Standards.OBSTACLE_COLOR); 28 | 29 | pane.getChildren().addAll(circle); 30 | 31 | centerTranslate.xProperty().bind(this.circleObstacle.centerXProperty().multiply(zoomScaleProperty())); 32 | centerTranslate.yProperty().bind(this.circleObstacle.centerYProperty().multiply(zoomScaleProperty()).negate()); 33 | pane.getTransforms().addAll(centerTranslate); 34 | 35 | circle.radiusProperty().bind(this.circleObstacle.radiusProperty().multiply(zoomScaleProperty())); 36 | 37 | updateSelected(circleObstacle.isSelected()); 38 | } 39 | 40 | @Override 41 | protected void updateSelected(boolean isSelected) { 42 | circle.setStrokeWidth(isSelected ? 2.0 : 0.0); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/obstacle/ObstacleView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HObstacle; 4 | 5 | import javafx.beans.property.DoubleProperty; 6 | import javafx.beans.property.SimpleDoubleProperty; 7 | import javafx.scene.layout.Pane; 8 | 9 | public abstract class ObstacleView { 10 | 11 | private final HObstacle obstacle; 12 | 13 | protected final Pane pane = new Pane(); 14 | 15 | private final DoubleProperty zoomScale = new SimpleDoubleProperty(this, "zoomScale", 1.0); 16 | 17 | protected ObstacleView(HObstacle obstacle) { 18 | this.obstacle = obstacle; 19 | 20 | pane.setPickOnBounds(false); 21 | 22 | this.obstacle.selectedProperty().addListener((currentValue, wasSelected, isSelected) -> { 23 | updateSelected(isSelected); 24 | }); 25 | } 26 | 27 | protected abstract void updateSelected(boolean isSelected); 28 | 29 | public final DoubleProperty zoomScaleProperty() { 30 | return zoomScale; 31 | } 32 | 33 | public final void setZoomScale(double value) { 34 | zoomScale.set(value); 35 | } 36 | 37 | public final double getZoomScale() { 38 | return zoomScale.get(); 39 | } 40 | 41 | public Pane getView() { 42 | return pane; 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/obstacle/PolygonObstacleView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HPolygonObstacle; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Polygon; 8 | import javafx.scene.shape.StrokeLineCap; 9 | import javafx.scene.shape.StrokeType; 10 | 11 | public class PolygonObstacleView extends ObstacleView { 12 | 13 | private final HPolygonObstacle polygonObstacle; 14 | 15 | private final PolygonWrapper polygonWrapper = new PolygonWrapper(); 16 | private final Polygon polygon; 17 | 18 | public PolygonObstacleView(HPolygonObstacle polygonObstacle) { 19 | super(polygonObstacle); 20 | 21 | this.polygonObstacle = polygonObstacle; 22 | 23 | polygonWrapper.setPoints(this.polygonObstacle.getPoints()); 24 | polygonWrapper.zoomScaleProperty().bind(zoomScaleProperty()); 25 | polygon = polygonWrapper.getPolygon(); 26 | polygon.setFill(Standards.OBSTACLE_COLOR); 27 | polygon.setStroke(Color.ORANGE); 28 | polygon.setStrokeWidth(0.0); 29 | polygon.setStrokeType(StrokeType.OUTSIDE); 30 | polygon.setStrokeLineCap(StrokeLineCap.ROUND); 31 | 32 | pane.getChildren().add(polygon); 33 | 34 | updateSelected(polygonObstacle.isSelected()); 35 | } 36 | 37 | @Override 38 | protected void updateSelected(boolean isSelected) { 39 | polygon.setStrokeWidth(isSelected ? 2.0 : 0.0); 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/obstacle/PolygonPointView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HPolygonPoint; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.beans.property.DoubleProperty; 7 | import javafx.beans.property.SimpleDoubleProperty; 8 | import javafx.scene.Node; 9 | import javafx.scene.layout.Pane; 10 | import javafx.scene.paint.Color; 11 | import javafx.scene.shape.Circle; 12 | import javafx.scene.shape.StrokeType; 13 | 14 | public class PolygonPointView { 15 | 16 | private final HPolygonPoint polygonPoint; 17 | private final DoubleProperty zoomScale = new SimpleDoubleProperty(this, "zoomScale", 1.0); 18 | 19 | private final Pane pane = new Pane(); 20 | private final Circle circle = new Circle(6.0); 21 | 22 | public PolygonPointView(HPolygonPoint polygonPoint) { 23 | this.polygonPoint = polygonPoint; 24 | 25 | circle.setFill(Standards.COLOR_PALETTE[0]); 26 | circle.setStrokeType(StrokeType.OUTSIDE); 27 | circle.setStrokeWidth(0.0); 28 | circle.setStroke(Color.ORANGE); 29 | 30 | pane.setPickOnBounds(false); 31 | pane.getChildren().add(circle); 32 | 33 | circle.translateXProperty().bind(this.polygonPoint.xProperty().multiply(zoomScale)); 34 | circle.translateYProperty().bind(this.polygonPoint.yProperty().multiply(zoomScale).negate()); 35 | 36 | updateSelected(this.polygonPoint.isSelected()); 37 | this.polygonPoint.selectedProperty().addListener((currentValue, wasSelected, isSelected) -> { 38 | updateSelected(isSelected); 39 | }); 40 | } 41 | 42 | private void updateSelected(boolean isSelected) { 43 | circle.setStrokeWidth(isSelected ? 2.0 : 0.0); 44 | } 45 | 46 | public final DoubleProperty zoomScaleProperty() { 47 | return zoomScale; 48 | } 49 | 50 | public final void setZoomScale(double value) { 51 | zoomScale.set(value); 52 | } 53 | 54 | public final double getZoomScale() { 55 | return zoomScale.get(); 56 | } 57 | 58 | public Node getView() { 59 | return pane; 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/obstacle/RectangleObstacleView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HRectangleObstacle; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Rectangle; 8 | import javafx.scene.shape.StrokeType; 9 | import javafx.scene.transform.Rotate; 10 | import javafx.scene.transform.Translate; 11 | 12 | public class RectangleObstacleView extends ObstacleView { 13 | 14 | private final HRectangleObstacle rectangleObstacle; 15 | 16 | private final Rectangle rectangle = new Rectangle(); 17 | 18 | private final Translate originTranslate = new Translate(); 19 | private final Rotate rotation = new Rotate(); 20 | private final Translate centerTranslate = new Translate(); 21 | 22 | public RectangleObstacleView(HRectangleObstacle rectangleObstacle) { 23 | super(rectangleObstacle); 24 | 25 | this.rectangleObstacle = rectangleObstacle; 26 | 27 | rectangle.setStroke(Color.ORANGE); 28 | rectangle.setStrokeWidth(0.0); 29 | rectangle.setStrokeType(StrokeType.OUTSIDE); 30 | rectangle.setFill(Standards.OBSTACLE_COLOR); 31 | 32 | pane.getChildren().addAll(rectangle); 33 | 34 | originTranslate.xProperty().bind(this.rectangleObstacle.lengthProperty().multiply(zoomScaleProperty()).multiply(-0.5)); 35 | originTranslate.yProperty().bind(this.rectangleObstacle.widthProperty().multiply(zoomScaleProperty().multiply(-0.5))); 36 | rotation.angleProperty().bind(this.rectangleObstacle.rotateAngleProperty().multiply(-180 / Math.PI)); 37 | centerTranslate.xProperty().bind(this.rectangleObstacle.centerXProperty().multiply(zoomScaleProperty())); 38 | centerTranslate.yProperty().bind(this.rectangleObstacle.centerYProperty().multiply(zoomScaleProperty()).negate()); 39 | pane.getTransforms().addAll(centerTranslate, rotation, originTranslate); 40 | 41 | rectangle.widthProperty().bind(this.rectangleObstacle.lengthProperty().multiply(zoomScaleProperty())); 42 | rectangle.heightProperty().bind(this.rectangleObstacle.widthProperty().multiply(zoomScaleProperty())); 43 | 44 | updateSelected(rectangleObstacle.isSelected()); 45 | } 46 | 47 | @Override 48 | protected void updateSelected(boolean isSelected) { 49 | rectangle.setStrokeWidth(isSelected ? 2.0 : 0.0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/toolbar/PathToolBar.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.toolbar; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.Button; 7 | import javafx.scene.control.ToggleButton; 8 | import javafx.scene.control.ToolBar; 9 | 10 | public class PathToolBar extends ToolBar { 11 | 12 | private final DocumentManager documentManager; 13 | 14 | private final ToggleButton lockZoom = new ToggleButton("Lock Zoom"); 15 | private final ToggleButton showOrigin = new ToggleButton("Show Origin"); 16 | private final ToggleButton autoWaypoint = new ToggleButton("Auto Waypoint"); 17 | private final Button debug = new Button("Debug"); 18 | 19 | public PathToolBar(DocumentManager documentManager) { 20 | this.documentManager = documentManager; 21 | 22 | lockZoom.setOnAction(this::lockZoomToggled); 23 | this.documentManager.actions().lockZoomProperty().bind(lockZoom.selectedProperty()); 24 | this.documentManager.actions().showOriginProperty().bind(showOrigin.selectedProperty()); 25 | this.documentManager.actions().autoWaypointProperty().bind(autoWaypoint.selectedProperty()); 26 | debug.setOnAction(event -> { 27 | if (this.documentManager.getIsDocumentOpen() && 28 | this.documentManager.getDocument().isPathSelected() && 29 | !this.documentManager.getDocument().getSelectedPath().getWaypoints().isEmpty()) { 30 | debug.setText(String.valueOf(this.documentManager.getDocument().getSelectedPath().getWaypoints().get(0).isSelected())); 31 | } 32 | }); 33 | 34 | getItems().addAll(lockZoom, showOrigin, autoWaypoint, debug); 35 | } 36 | 37 | public void lockZoomToggled(ActionEvent event) { 38 | if (lockZoom.isSelected()) { 39 | documentManager.actions().zoomToFit(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/trajectory/SegmentView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.trajectory; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.beans.property.SimpleDoubleProperty; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.paint.Color; 7 | import javafx.scene.shape.Line; 8 | 9 | public class SegmentView { 10 | 11 | private final Line line = new Line(); 12 | 13 | private final DoubleProperty zoomScale = new SimpleDoubleProperty(this, "zoomScale", 1.0); 14 | 15 | private final Pane pane = new Pane(line); 16 | 17 | public SegmentView(double startX, double startY, double endX, double endY) { 18 | 19 | line.startXProperty().bind(zoomScale.multiply(startX)); 20 | line.startYProperty().bind(zoomScale.multiply(-startY)); 21 | line.endXProperty().bind(zoomScale.multiply(endX)); 22 | line.endYProperty().bind(zoomScale.multiply(-endY)); 23 | 24 | line.setStrokeWidth(2); 25 | line.setStroke(Color.BLACK); 26 | } 27 | 28 | public final DoubleProperty zoomScaleProperty() { 29 | return zoomScale; 30 | } 31 | 32 | public final void setZoomScale(double value) { 33 | zoomScale.set(value); 34 | } 35 | 36 | public final double getZoomScale() { 37 | return zoomScale.get(); 38 | } 39 | 40 | public Pane getView() { 41 | return pane; 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/trajectory/TrajectoryPane.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.trajectory; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.layout.Pane; 6 | 7 | public class TrajectoryPane extends Pane { 8 | 9 | private final DocumentManager documentManager; 10 | 11 | private final SegmentsPane segmentsPane; 12 | private final AnimationPane animationPane; 13 | 14 | public TrajectoryPane(DocumentManager documentManager) { 15 | this.documentManager = documentManager; 16 | 17 | segmentsPane = new SegmentsPane(this.documentManager); 18 | animationPane = new AnimationPane(this.documentManager); 19 | 20 | getChildren().addAll(segmentsPane, animationPane); 21 | setPickOnBounds(false); 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/waypoint/InitialGuessWaypointView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.waypoint; 2 | 3 | import org.team2363.helixnavigator.document.timeline.HInitialGuessWaypoint; 4 | import org.team2363.helixnavigator.global.Standards; 5 | 6 | import javafx.beans.property.DoubleProperty; 7 | import javafx.scene.paint.Color; 8 | 9 | public class InitialGuessWaypointView extends WaypointView { 10 | 11 | private final RobotView robotView = new RobotView(); 12 | 13 | private final HInitialGuessWaypoint initialGuessWaypoint; 14 | 15 | public InitialGuessWaypointView(HInitialGuessWaypoint initialGuessWaypoint) { 16 | super(initialGuessWaypoint); 17 | 18 | this.initialGuessWaypoint = initialGuessWaypoint; 19 | 20 | setWaypointFill(Color.SKYBLUE); 21 | 22 | robotView.getView().getTransforms().add(centerTranslate); 23 | robotView.headingProperty().bind(this.initialGuessWaypoint.headingProperty()); 24 | robotView.zoomScaleProperty().bind(zoomScaleProperty()); 25 | robotView.getView().setOnMouseDragged(event -> { 26 | // System.out.println("Dot dragged"); 27 | double x = event.getX(); 28 | double y = event.getY(); 29 | double[] lockAngles = {-180, -90, 0, 90, 180}; 30 | double lockRadius = Standards.HEADING_LOCK_RADIUS; 31 | double angle = Math.toDegrees(Math.atan2(y, x)); 32 | // System.out.println(angle); 33 | for (double lockAngle : lockAngles) { 34 | if (!event.isShiftDown() && Math.abs(angle - lockAngle) <= lockRadius) { 35 | if (lockAngle == -180) { 36 | lockAngle = 180; 37 | } 38 | angle = lockAngle; 39 | break; 40 | } 41 | } 42 | initialGuessWaypoint.setHeading(angle * (-Math.PI/180)); 43 | }); 44 | } 45 | 46 | public final DoubleProperty bumperLengthProperty() { 47 | return robotView.bumperLengthProperty(); 48 | } 49 | 50 | public final void setBumperLength(double value) { 51 | robotView.setBumperLength(value); 52 | } 53 | 54 | public final double getBumperLength() { 55 | return robotView.getBumperLength(); 56 | } 57 | 58 | public final DoubleProperty bumperWidthProperty() { 59 | return robotView.bumperWidthProperty(); 60 | } 61 | 62 | public final void setBumperWidth(double value) { 63 | robotView.setBumperWidth(value); 64 | } 65 | 66 | public final double getBumperWidth() { 67 | return robotView.getBumperWidth(); 68 | } 69 | 70 | public final DoubleProperty headingProperty() { 71 | return robotView.headingProperty(); 72 | } 73 | 74 | public final void setHeading(double value) { 75 | robotView.setHeading(value); 76 | } 77 | 78 | public final double getHeading() { 79 | return robotView.getHeading(); 80 | } 81 | 82 | public RobotView getRobotView() { 83 | return robotView; 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/waypoint/SoftWaypointView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.waypoint; 2 | 3 | import org.team2363.helixnavigator.document.timeline.HSoftWaypoint; 4 | 5 | public class SoftWaypointView extends WaypointView { 6 | 7 | public SoftWaypointView(HSoftWaypoint softWaypoint) { 8 | super(softWaypoint); 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/editor/waypoint/WaypointView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.editor.waypoint; 2 | 3 | import org.team2363.helixnavigator.document.timeline.HWaypoint; 4 | import org.team2363.helixnavigator.global.Standards; 5 | import org.team2363.helixnavigator.ui.prompts.waypoint.WaypointEditDialog; 6 | 7 | import javafx.beans.property.DoubleProperty; 8 | import javafx.beans.property.SimpleDoubleProperty; 9 | import javafx.scene.control.ContextMenu; 10 | import javafx.scene.control.MenuItem; 11 | import javafx.scene.layout.Pane; 12 | import javafx.scene.paint.Color; 13 | import javafx.scene.paint.Paint; 14 | import javafx.scene.shape.Circle; 15 | import javafx.scene.shape.StrokeType; 16 | import javafx.scene.transform.Translate; 17 | 18 | public abstract class WaypointView { 19 | 20 | private final HWaypoint waypoint; 21 | 22 | private final Circle selectionCircle = new Circle(12.0); 23 | private final Circle waypointCircle = new Circle(10.0); 24 | protected final Pane waypointPane = new Pane(selectionCircle, waypointCircle); 25 | protected final Pane pane = new Pane(waypointPane); 26 | 27 | private final DoubleProperty zoomScale = new SimpleDoubleProperty(this, "zoomScale", 1.0); 28 | 29 | protected final Translate centerTranslate = new Translate(); 30 | 31 | private final MenuItem editMenuItem = new MenuItem("Edit..."); 32 | private final ContextMenu contextMenu = new ContextMenu(editMenuItem); 33 | 34 | protected WaypointView(HWaypoint waypoint) { 35 | this.waypoint = waypoint; 36 | 37 | selectionCircle.setFill(Color.ORANGE); 38 | waypointCircle.setFill(Standards.COLOR_PALETTE[3]); 39 | 40 | waypointCircle.setStroke(Standards.COLOR_PALETTE[0]); 41 | waypointCircle.setStrokeType(StrokeType.INSIDE); 42 | waypointCircle.setStrokeWidth(3.0); 43 | selectionCircle.setOpacity(0.0); 44 | 45 | pane.setOnContextMenuRequested(event -> { 46 | contextMenu.show(pane, event.getScreenX(), event.getScreenY()); 47 | }); 48 | editMenuItem.setOnAction(event -> WaypointEditDialog.dialog(this.waypoint).show()); 49 | waypointPane.setPickOnBounds(false); 50 | pane.setPickOnBounds(false); 51 | 52 | // For y you must subtract to flip the coordinates, in graphics +y is down but in math/engineering/robotics +y is up (i think): 53 | centerTranslate.xProperty().bind(this.waypoint.xProperty().multiply(zoomScale)); 54 | centerTranslate.yProperty().bind(this.waypoint.yProperty().negate().multiply(zoomScale)); 55 | waypointPane.getTransforms().add(centerTranslate); 56 | 57 | updateSelected(this.waypoint.isSelected()); 58 | this.waypoint.selectedProperty().addListener((currentValue, wasSelected, isSelected) -> { 59 | updateSelected(isSelected); 60 | }); 61 | } 62 | 63 | private void updateSelected(boolean isSelected) { 64 | selectionCircle.setOpacity(isSelected ? 1.0 : 0.0); 65 | } 66 | 67 | protected void setWaypointFill(Paint paint) { 68 | waypointCircle.setFill(paint); 69 | } 70 | 71 | public final DoubleProperty zoomScaleProperty() { 72 | return zoomScale; 73 | } 74 | 75 | public final void setZoomScale(double value) { 76 | zoomScale.set(value); 77 | } 78 | 79 | public final double getZoomScale() { 80 | return zoomScale.get(); 81 | } 82 | 83 | public Pane getWaypointView() { 84 | return waypointPane; 85 | } 86 | 87 | public Pane getView() { 88 | return pane; 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/MainMenuBar.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.ui.menu.edit.EditMenu; 5 | import org.team2363.helixnavigator.ui.menu.file.FileMenu; 6 | import org.team2363.helixnavigator.ui.menu.help.HelpMenu; 7 | import org.team2363.helixnavigator.ui.menu.tools.ToolsMenu; 8 | import org.team2363.helixnavigator.ui.menu.view.ViewMenu; 9 | 10 | import javafx.scene.control.MenuBar; 11 | 12 | public class MainMenuBar extends MenuBar { 13 | 14 | private final DocumentManager documentManager; 15 | 16 | private final FileMenu fileMenu; 17 | private final EditMenu editMenu; 18 | private final ViewMenu viewMenu; 19 | private final ToolsMenu toolsMenu; 20 | private final HelpMenu helpMenu; 21 | 22 | public MainMenuBar(DocumentManager documentManager) { 23 | this.documentManager = documentManager; 24 | 25 | final String os = System.getProperty("os.name"); 26 | if (os != null && os.startsWith("Mac")) { 27 | useSystemMenuBarProperty().set(true); 28 | } 29 | 30 | fileMenu = new FileMenu(this.documentManager); 31 | editMenu = new EditMenu(this.documentManager); 32 | viewMenu = new ViewMenu(this.documentManager); 33 | toolsMenu = new ToolsMenu(this.documentManager); 34 | helpMenu = new HelpMenu(); 35 | 36 | getMenus().addAll(fileMenu, editMenu, viewMenu, toolsMenu, helpMenu); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/CopyMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class CopyMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public CopyMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Copy"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+C")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().copy(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/CutMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class CutMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public CutMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Cut"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+X")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().cut(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/DeleteMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class DeleteMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public DeleteMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Delete"); 16 | setAccelerator(KeyCombination.keyCombination("DELETE")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | if (documentManager.getIsDocumentOpen() && documentManager.getDocument().isPathSelected()) { 23 | documentManager.actions().deleteSelection(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/DeselectAllMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class DeselectAllMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public DeselectAllMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Deselect All"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+shift+A")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().clearSelection(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/EditMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.control.Menu; 6 | import javafx.scene.control.SeparatorMenuItem; 7 | 8 | public class EditMenu extends Menu { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | private final UndoMenuItem undoMenuItem; 13 | private final RedoMenuItem redoMenuItem; 14 | 15 | private final CutMenuItem cutMenuItem; 16 | private final CopyMenuItem copyMenuItem; 17 | private final PasteMenuItem pasteMenuItem; 18 | private final DeleteMenuItem deleteMenuItem; 19 | 20 | private final SelectAllMenuItem selectAllMenuItem; 21 | private final DeselectAllMenuItem deselectAllMenuItem; 22 | 23 | private final TransformMenuItem transformMenuItem; 24 | private final Rotate90ClockwiseMenuItem rotate90ClockwiseMenuItem; 25 | private final Rotate90CounterclockwiseMenuItem rotate90CounterclockwiseMenuItem; 26 | private final Rotate180MenuItem rotate180MenuItem; 27 | private final FlipToOppositeSideMenuItem flipToOppositeSideMenuItem; 28 | 29 | public EditMenu(DocumentManager documentManager) { 30 | this.documentManager = documentManager; 31 | 32 | setText("_Edit"); 33 | undoMenuItem = new UndoMenuItem(this.documentManager); 34 | redoMenuItem = new RedoMenuItem(this.documentManager); 35 | cutMenuItem = new CutMenuItem(this.documentManager); 36 | copyMenuItem = new CopyMenuItem(this.documentManager); 37 | pasteMenuItem = new PasteMenuItem(this.documentManager); 38 | deleteMenuItem = new DeleteMenuItem(this.documentManager); 39 | selectAllMenuItem = new SelectAllMenuItem(this.documentManager); 40 | deselectAllMenuItem = new DeselectAllMenuItem(this.documentManager); 41 | transformMenuItem = new TransformMenuItem(this.documentManager); 42 | rotate90ClockwiseMenuItem = new Rotate90ClockwiseMenuItem(this.documentManager); 43 | rotate90CounterclockwiseMenuItem = new Rotate90CounterclockwiseMenuItem(this.documentManager); 44 | rotate180MenuItem = new Rotate180MenuItem(this.documentManager); 45 | flipToOppositeSideMenuItem = new FlipToOppositeSideMenuItem(this.documentManager); 46 | 47 | getItems().add(undoMenuItem); 48 | getItems().add(redoMenuItem); 49 | getItems().add(new SeparatorMenuItem()); 50 | getItems().add(cutMenuItem); 51 | getItems().add(copyMenuItem); 52 | getItems().add(pasteMenuItem); 53 | getItems().add(deleteMenuItem); 54 | getItems().add(new SeparatorMenuItem()); 55 | getItems().add(selectAllMenuItem); 56 | getItems().add(deselectAllMenuItem); 57 | getItems().add(new SeparatorMenuItem()); 58 | getItems().add(transformMenuItem); 59 | getItems().add(rotate90ClockwiseMenuItem); 60 | getItems().add(rotate90CounterclockwiseMenuItem); 61 | getItems().add(rotate180MenuItem); 62 | getItems().add(flipToOppositeSideMenuItem); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/FlipToOppositeSideMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | 8 | public class FlipToOppositeSideMenuItem extends MenuItem { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | public FlipToOppositeSideMenuItem(DocumentManager documentManager) { 13 | this.documentManager = documentManager; 14 | setText("Flip Objects to Opposite Side"); 15 | // setAccelerator(KeyCombination.keyCombination("shortcut+RIGHT")); 16 | setOnAction(this::action); 17 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 18 | } 19 | 20 | public void action(ActionEvent event) { 21 | documentManager.actions().flipObjectsToOppositeSide(); 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/PasteMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class PasteMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public PasteMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Paste"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+V")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().paste(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/RedoMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class RedoMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public RedoMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Redo"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+Y")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | System.out.println("Redoing"); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/Rotate180MenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class Rotate180MenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public Rotate180MenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Rotate 180\u00B0"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+UP")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().rotateSelection180(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/Rotate90ClockwiseMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class Rotate90ClockwiseMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public Rotate90ClockwiseMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Rotate 90\u00B0 Clockwise"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+RIGHT")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().rotateSelection90Clockwise(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/Rotate90CounterclockwiseMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class Rotate90CounterclockwiseMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public Rotate90CounterclockwiseMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Rotate 90\u00B0 Counterclockwise"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+LEFT")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().rotateSelection90Counterclockwise(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/SelectAllMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class SelectAllMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public SelectAllMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Select All"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+A")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.actions().selectAll(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/TransformMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class TransformMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public TransformMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | 16 | setText("Transform..."); 17 | setAccelerator(KeyCombination.keyCombination("shortcut+T")); 18 | setOnAction(this::action); 19 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 20 | } 21 | 22 | public void action(ActionEvent event) { 23 | documentManager.actions().getTransformDialog().show(); 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/edit/UndoMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.edit; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class UndoMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public UndoMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Undo"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+Z")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | System.out.println("Undoing"); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/CloseDocumentMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class CloseDocumentMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public CloseDocumentMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Close Document"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+W")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.requestCloseDocument(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/ExportMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.control.Menu; 6 | 7 | public class ExportMenu extends Menu { 8 | 9 | private final DocumentManager documentManager; 10 | 11 | private final ExportWaypointBundleMenuItem exportWaypointBundleMenuItem; 12 | 13 | public ExportMenu(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Export"); 16 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 17 | 18 | exportWaypointBundleMenuItem = new ExportWaypointBundleMenuItem(this.documentManager); 19 | 20 | getItems().addAll(exportWaypointBundleMenuItem); 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/ExportWaypointBundleMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | 8 | public class ExportWaypointBundleMenuItem extends MenuItem { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | public ExportWaypointBundleMenuItem(DocumentManager documentManager) { 13 | this.documentManager = documentManager; 14 | 15 | setText("Export waypoint bundle..."); 16 | setOnAction(this::action); 17 | } 18 | 19 | private void action(ActionEvent event) { 20 | documentManager.requestExportWaypointBundle(); 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/FileMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.control.Menu; 6 | import javafx.scene.control.SeparatorMenuItem; 7 | 8 | public class FileMenu extends Menu { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | private final NewDocumentMenuItem newDocumentMenuItem; 13 | private final OpenDocumentMenuItem openDocumentMenuItem; 14 | private final SaveMenuItem saveMenuItem; 15 | private final SaveAsMenuItem saveAsMenuItem; 16 | private final ImportMenuItem importMenuItem; 17 | private final ExportMenu exportMenu; 18 | private final CloseDocumentMenuItem closeDocumentMenuItem; 19 | 20 | public FileMenu(DocumentManager documentManager) { 21 | this.documentManager = documentManager; 22 | 23 | setText("_File"); 24 | 25 | newDocumentMenuItem = new NewDocumentMenuItem(this.documentManager); 26 | openDocumentMenuItem = new OpenDocumentMenuItem(this.documentManager); 27 | saveMenuItem = new SaveMenuItem(this.documentManager); 28 | saveAsMenuItem = new SaveAsMenuItem(this.documentManager); 29 | importMenuItem = new ImportMenuItem(this.documentManager); 30 | exportMenu = new ExportMenu(this.documentManager); 31 | closeDocumentMenuItem = new CloseDocumentMenuItem(this.documentManager); 32 | 33 | getItems().add(newDocumentMenuItem); 34 | getItems().add(openDocumentMenuItem); 35 | getItems().add(new SeparatorMenuItem()); 36 | getItems().add(saveMenuItem); 37 | getItems().add(saveAsMenuItem); 38 | getItems().add(new SeparatorMenuItem()); 39 | getItems().add(importMenuItem); 40 | getItems().add(exportMenu); 41 | getItems().add(new SeparatorMenuItem()); 42 | getItems().add(closeDocumentMenuItem); 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/ImportMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | 8 | public class ImportMenuItem extends MenuItem { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | public ImportMenuItem(DocumentManager documentManager) { 13 | this.documentManager = documentManager; 14 | setText("Import..."); 15 | setOnAction(this::action); 16 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 17 | } 18 | 19 | public void action(ActionEvent event) { 20 | System.out.println("Importing"); 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/NewDocumentMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class NewDocumentMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public NewDocumentMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("New Document..."); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+N")); 17 | setOnAction(this::action); 18 | } 19 | 20 | public void action(ActionEvent event) { 21 | documentManager.requestNewDocument(); 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/OpenDocumentMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class OpenDocumentMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public OpenDocumentMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Open Document..."); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+O")); 17 | setOnAction(this::action); 18 | } 19 | 20 | public void action(ActionEvent event) { 21 | documentManager.requestOpenDocument(); 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/SaveAsMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class SaveAsMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public SaveAsMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Save As..."); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+shift+S")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.requestSaveAsDocument(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/file/SaveMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.file; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | import javafx.scene.input.KeyCombination; 8 | 9 | public class SaveMenuItem extends MenuItem { 10 | 11 | private final DocumentManager documentManager; 12 | 13 | public SaveMenuItem(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | setText("Save"); 16 | setAccelerator(KeyCombination.keyCombination("shortcut+S")); 17 | setOnAction(this::action); 18 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 19 | } 20 | 21 | public void action(ActionEvent event) { 22 | documentManager.requestSaveDocument(); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/help/AboutMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.help; 2 | 3 | import org.team2363.helixnavigator.global.Standards; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | 8 | public class AboutMenuItem extends MenuItem { 9 | 10 | private final AboutStage aboutStage = new AboutStage(); 11 | 12 | public AboutMenuItem() { 13 | setText("About " + Standards.APPLICATION_NAME); 14 | setOnAction(this::action); 15 | } 16 | 17 | public void action(ActionEvent event) { 18 | aboutStage.show(); 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/help/AboutStage.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.help; 2 | 3 | import java.io.InputStream; 4 | 5 | import org.team2363.helixnavigator.global.Standards; 6 | 7 | import javafx.geometry.Pos; 8 | import javafx.scene.Scene; 9 | import javafx.scene.image.Image; 10 | import javafx.scene.image.ImageView; 11 | import javafx.scene.layout.VBox; 12 | import javafx.scene.text.Font; 13 | import javafx.scene.text.FontPosture; 14 | import javafx.scene.text.FontWeight; 15 | import javafx.scene.text.Text; 16 | import javafx.stage.Stage; 17 | 18 | public class AboutStage { 19 | 20 | private static final Font FONT = Font.font("Helvetica Neue", FontWeight.THIN, FontPosture.REGULAR, 11); 21 | 22 | private final ImageView iconView = new ImageView(); 23 | private final Text applicationNameText = new Text(Standards.APPLICATION_NAME); 24 | private final Text versionText = new Text("Version " + Standards.APPLICATION_VERSION); 25 | private final Text createdByText = new Text("Created by Justin Babilino"); 26 | private final Text copyrightText = new Text("Copyright © 2021-2022 Triple Helix Robotics"); 27 | private final VBox layout = new VBox(iconView, applicationNameText, versionText, createdByText, copyrightText); 28 | private final Scene scene = new Scene(layout); 29 | private final Stage stage = new Stage(); 30 | 31 | public AboutStage() { 32 | InputStream stream = AboutStage.class.getResourceAsStream("/icon.png"); 33 | if (stream != null) { 34 | iconView.setImage(new Image(stream)); 35 | } 36 | iconView.setFitWidth(100); 37 | iconView.setFitHeight(100); 38 | applicationNameText.setFont(FONT); 39 | versionText.setFont(FONT); 40 | createdByText.setFont(FONT); 41 | copyrightText.setFont(FONT); 42 | layout.setAlignment(Pos.CENTER); 43 | stage.setResizable(false); 44 | stage.setMinWidth(300); 45 | stage.setMaxWidth(300); 46 | stage.setMinHeight(230); 47 | stage.setMaxHeight(230); 48 | stage.setScene(scene); 49 | } 50 | 51 | public void show() { 52 | if (stage.isShowing()) { 53 | stage.requestFocus(); 54 | } 55 | stage.show(); 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/help/HelpMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.help; 2 | 3 | import javafx.scene.control.Menu; 4 | 5 | public class HelpMenu extends Menu { 6 | 7 | private final AboutMenuItem aboutMenuItem; 8 | 9 | public HelpMenu() { 10 | setText("_Help"); 11 | aboutMenuItem = new AboutMenuItem(); 12 | 13 | getItems().add(aboutMenuItem); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/tools/EditDocumentConfigurationMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.tools; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | import org.team2363.helixnavigator.document.HDocument; 5 | import org.team2363.helixnavigator.ui.prompts.documentconfig.DocumentConfigDialog; 6 | 7 | import javafx.beans.value.ObservableValue; 8 | import javafx.event.ActionEvent; 9 | import javafx.scene.control.MenuItem; 10 | 11 | public class EditDocumentConfigurationMenuItem extends MenuItem { 12 | 13 | private final DocumentManager documentManager; 14 | 15 | private DocumentConfigDialog dialog; 16 | 17 | public EditDocumentConfigurationMenuItem(DocumentManager documentManager) { 18 | this.documentManager = documentManager; 19 | 20 | setText("Edit Document Configuration..."); 21 | setOnAction(this::action); 22 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 23 | 24 | loadDocument(this.documentManager.getDocument()); 25 | this.documentManager.documentProperty().addListener(this::documentChanged); 26 | } 27 | 28 | public void action(ActionEvent event) { 29 | dialog.show(); 30 | } 31 | 32 | private void documentChanged(ObservableValue currentDocument, HDocument oldDocument, HDocument newDocument) { 33 | unloadDocument(oldDocument); 34 | loadDocument(newDocument); 35 | } 36 | 37 | private void unloadDocument(HDocument oldDocument) { 38 | if (oldDocument != null) { 39 | dialog.close(); 40 | dialog = null; 41 | } 42 | } 43 | 44 | private void loadDocument(HDocument newDocument) { 45 | if (newDocument != null) { 46 | dialog = new DocumentConfigDialog(newDocument); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/tools/EditRobotConfigurationMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.tools; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.event.ActionEvent; 6 | import javafx.scene.control.MenuItem; 7 | 8 | public class EditRobotConfigurationMenuItem extends MenuItem { 9 | 10 | private final DocumentManager documentManager; 11 | 12 | public EditRobotConfigurationMenuItem(DocumentManager documentManager) { 13 | this.documentManager = documentManager; 14 | 15 | setText("Edit Robot Configuration..."); 16 | setOnAction(this::action); 17 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 18 | } 19 | 20 | public void action(ActionEvent event) { 21 | this.documentManager.actions().getRobotConfigDialog().show(); 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/tools/ToolsMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.tools; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.control.Menu; 6 | 7 | public class ToolsMenu extends Menu { 8 | 9 | private final DocumentManager documentManager; 10 | 11 | private final EditDocumentConfigurationMenuItem editDocumentConfigurationMenuItem; 12 | private final EditRobotConfigurationMenuItem editRobotConfigurationMenuItem; 13 | 14 | public ToolsMenu(DocumentManager documentManager) { 15 | this.documentManager = documentManager; 16 | 17 | editRobotConfigurationMenuItem = new EditRobotConfigurationMenuItem(this.documentManager); 18 | editDocumentConfigurationMenuItem = new EditDocumentConfigurationMenuItem(this.documentManager); 19 | 20 | setText("_Tools"); 21 | getItems().add(editDocumentConfigurationMenuItem); 22 | getItems().add(editRobotConfigurationMenuItem); 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/view/ViewMenu.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.view; 2 | 3 | import org.team2363.helixnavigator.document.DocumentManager; 4 | 5 | import javafx.scene.control.Menu; 6 | 7 | public class ViewMenu extends Menu { 8 | 9 | private final DocumentManager documentManager; 10 | 11 | private final ZoomToFitMenuItem zoomToFitMenuItem; 12 | 13 | public ViewMenu(DocumentManager documentManager) { 14 | this.documentManager = documentManager; 15 | 16 | zoomToFitMenuItem = new ZoomToFitMenuItem(this.documentManager); 17 | 18 | setText("_View"); 19 | getItems().add(zoomToFitMenuItem); 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/menu/view/ZoomToFitMenuItem.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.menu.view; 2 | 3 | import java.util.logging.Logger; 4 | 5 | import org.team2363.helixnavigator.document.DocumentManager; 6 | 7 | import javafx.event.ActionEvent; 8 | import javafx.scene.control.MenuItem; 9 | 10 | public class ZoomToFitMenuItem extends MenuItem { 11 | 12 | private final Logger logger = Logger.getLogger("org.team2363.helixnavigator.ui.menu.view"); 13 | 14 | private final DocumentManager documentManager; 15 | 16 | public ZoomToFitMenuItem(DocumentManager documentManager) { 17 | this.documentManager = documentManager; 18 | setText("Zoom To Fit"); 19 | setOnAction(this::action); 20 | disableProperty().bind(this.documentManager.isDocumentOpenProperty().not()); 21 | } 22 | 23 | public void action(ActionEvent event) { 24 | logger.info("Zooming to fit."); 25 | documentManager.actions().zoomToFit(); 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/metadata/MetadataPane.java: -------------------------------------------------------------------------------- 1 | // package com.team2363.helixnavigator.ui.metadata; 2 | 3 | // import com.team2363.helixnavigator.document.CurrentDocument; 4 | // import com.team2363.helixnavigator.document.HPath; 5 | 6 | // import javafx.geometry.Pos; 7 | // import javafx.scene.layout.Pane; 8 | // import javafx.scene.layout.StackPane; 9 | // import javafx.scene.layout.VBox; 10 | // import javafx.scene.text.Text; 11 | 12 | // public class MetadataPane extends VBox { 13 | 14 | // private Pane noDocumentMetaPane = new StackPane(new Text("NO DOCUMENT LOADED")); 15 | // private Pane noPathMetaPane = new StackPane(new Text("NO PATH LOADED")); 16 | // private Pane multiSelectionMetaPane; 17 | // private Pane waypointSelectionMetaPane; 18 | // private Pane obstacleSelectionMetaPane; 19 | 20 | // private static enum Mode { 21 | // NO_DOCUMENT, NO_PATH, MULTI_SELECTION, WAYPOINT_SELECTION, OBSTACLE_SELECTION 22 | // } 23 | 24 | // public MetadataPane() { 25 | // setMode(Mode.NO_DOCUMENT); 26 | // CurrentDocument.documentProperty().addListener((currentVal, oldVal, newVal) -> refreshDocument()); 27 | 28 | // setMinWidth(100); 29 | // } 30 | 31 | // private void setMode(Mode mode) { 32 | // getChildren().clear(); 33 | // switch (mode) { 34 | // case NO_DOCUMENT: 35 | // getChildren().add(noDocumentMetaPane); 36 | // break; 37 | // case NO_PATH: 38 | // getChildren().add(noPathMetaPane); 39 | // break; 40 | // case MULTI_SELECTION: 41 | // getChildren().add(multiSelectionMetaPane); 42 | // break; 43 | // case WAYPOINT_SELECTION: 44 | // getChildren().add(multiSelectionMetaPane); 45 | // getChildren().add(waypointSelectionMetaPane); 46 | // break; 47 | // case OBSTACLE_SELECTION: 48 | // getChildren().add(multiSelectionMetaPane); 49 | // getChildren().add(obstacleSelectionMetaPane); 50 | // break; // no need for default bc this is a private method, never will be null 51 | // } 52 | // } 53 | 54 | // private void updatePanes(HPath newPath) { 55 | // multiSelectionMetaPane = new MultiSelectionMetaPane(newPath); 56 | // } 57 | 58 | // private void refreshDocument() { 59 | // if (CurrentDocument.getDocument() == null) { 60 | // setMode(Mode.NO_DOCUMENT); 61 | // } else { 62 | // CurrentDocument.getDocument().selectedPathIndexProperty().addListener((currentVal, oldVal, newVal) -> { 63 | // if (newVal.intValue() < 0) { 64 | // setMode(Mode.NO_PATH); 65 | // } else { 66 | // updatePanes(CurrentDocument.getDocument().getSelectedPath()); 67 | // } 68 | // }); 69 | // } 70 | // } 71 | // } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/metadata/MultiSelectionMetaPane.java: -------------------------------------------------------------------------------- 1 | // package com.team2363.helixnavigator.ui.metadata; 2 | 3 | // import com.team2363.helixnavigator.document.HPath; 4 | 5 | // import javafx.event.ActionEvent; 6 | // import javafx.scene.control.TextField; 7 | // import javafx.scene.layout.HBox; 8 | // import javafx.scene.layout.VBox; 9 | // import javafx.scene.text.Text; 10 | 11 | // public class MultiSelectionMetaPane extends VBox { 12 | 13 | // private final HPath hPath; 14 | // private final Text titleText = new Text("Translate Selection"); 15 | 16 | // private final HBox translateRelativeXBox; 17 | // private final Text translateRelativeXText = new Text("Translate X: "); 18 | // private final TextField translateRelativeXTextField = new TextField("0.0"); 19 | 20 | // private final HBox translateRelativeYBox; 21 | // private final Text translateRelativeYText = new Text("Translate Y: "); 22 | // private final TextField translateRelativeYTextField = new TextField("0.0"); 23 | 24 | // public MultiSelectionMetaPane(HPath hPath) { 25 | // this.hPath = hPath; 26 | 27 | // translateRelativeXTextField.setOnAction(this::onTranslateRelativeX); 28 | // translateRelativeYTextField.setOnAction(this::onTranslateRelativeY); 29 | 30 | // translateRelativeXBox = new HBox(translateRelativeXText, translateRelativeXTextField); 31 | // translateRelativeYBox = new HBox(translateRelativeYText, translateRelativeYTextField); 32 | 33 | // getChildren().addAll(titleText, translateRelativeXBox, translateRelativeYBox); 34 | 35 | // } 36 | 37 | // private void onTranslateRelativeX(ActionEvent event) { 38 | // String textEntered = translateRelativeXTextField.getText(); 39 | // try { 40 | // final double value = Double.parseDouble(textEntered); 41 | // if (hPath.inPolygonPointMode()) { 42 | // hPath.getPolygonPointsSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeX(value)); 43 | // } else { 44 | // hPath.getWaypointsSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeX(value)); 45 | // hPath.getObstaclesSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeX(value)); 46 | // } 47 | // } catch (NumberFormatException e) { 48 | // translateRelativeXTextField.setText("0.0"); 49 | // } 50 | // } 51 | 52 | // private void onTranslateRelativeY(ActionEvent event) { 53 | // String textEntered = translateRelativeYTextField.getText(); 54 | // try { 55 | // final double value = Double.parseDouble(textEntered); 56 | // if (hPath.inPolygonPointMode()) { 57 | // hPath.getPolygonPointsSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeY(value)); 58 | // } else { 59 | // hPath.getWaypointsSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeY(value)); 60 | // hPath.getObstaclesSelectionModel().getSelectedItems().forEach(element -> element.translateRelativeY(value)); 61 | // } 62 | // } catch (NumberFormatException e) { 63 | // translateRelativeYTextField.setText("0.0"); 64 | // } 65 | // } 66 | // } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/metadata/WaypointSelectionMetaPane.java: -------------------------------------------------------------------------------- 1 | // package com.team2363.helixnavigator.ui.metadata; 2 | 3 | // import com.team2363.helixnavigator.document.HPath; 4 | 5 | // public class WaypointSelectionMetaPane { 6 | // public WaypointSelectionMetaPane(HPath hPath) { 7 | 8 | // } 9 | // } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/documentconfig/DocumentConfigDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.documentconfig; 2 | 3 | import org.team2363.helixnavigator.document.HDocument; 4 | 5 | import javafx.geometry.Insets; 6 | import javafx.geometry.Pos; 7 | import javafx.scene.Scene; 8 | import javafx.scene.control.Button; 9 | import javafx.scene.control.TabPane; 10 | import javafx.scene.layout.HBox; 11 | import javafx.scene.layout.VBox; 12 | import javafx.stage.Stage; 13 | 14 | public class DocumentConfigDialog { 15 | 16 | private final HDocument document; 17 | 18 | private final GeneralTab generalTab; 19 | private final RobotTab robotTab; 20 | private final TabPane tabPane; 21 | private final Button okButton = new Button("OK"); 22 | private final HBox buttonBox = new HBox(okButton); 23 | private final VBox vBox; 24 | private final Scene scene; 25 | private final Stage stage = new Stage(); 26 | 27 | public DocumentConfigDialog(HDocument document) { 28 | this.document = document; 29 | 30 | generalTab = new GeneralTab(this.document); 31 | robotTab = new RobotTab(this.document); 32 | tabPane = new TabPane(generalTab, robotTab); 33 | vBox = new VBox(tabPane, buttonBox); 34 | scene = new Scene(vBox); 35 | 36 | buttonBox.setAlignment(Pos.CENTER_RIGHT); 37 | vBox.setPadding(new Insets(10, 10, 10, 10)); 38 | vBox.setSpacing(10); 39 | stage.setScene(scene); 40 | 41 | okButton.setOnAction(event -> close()); 42 | } 43 | 44 | public void show() { 45 | if (stage.isShowing()) { 46 | stage.requestFocus(); 47 | } else { 48 | stage.show(); 49 | } 50 | } 51 | 52 | public void close() { 53 | stage.close(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/documentconfig/RobotTab.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.documentconfig; 2 | 3 | import org.team2363.helixnavigator.document.HDocument; 4 | 5 | import javafx.scene.control.Label; 6 | import javafx.scene.control.Tab; 7 | 8 | public class RobotTab extends Tab { 9 | 10 | private final HDocument document; 11 | private final Label content = new Label("beep boop"); 12 | 13 | public RobotTab(HDocument document) { 14 | this.document = document; 15 | setText("Robot"); 16 | setContent(content); 17 | setClosable(false); 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/obstacle/PolygonObstacleEditDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HPolygonObstacle; 4 | import org.team2363.helixnavigator.document.obstacle.HPolygonPoint; 5 | 6 | import javafx.scene.control.Button; 7 | import javafx.scene.layout.HBox; 8 | 9 | public class PolygonObstacleEditDialog extends ObstacleEditDialog { 10 | 11 | private final HPolygonObstacle polygonObstacle; 12 | private final HPolygonObstacle backupPolygonObstacle; 13 | 14 | private final PolygonPointsTableView pointsTable = new PolygonPointsTableView(); 15 | private final Button addPointButton = new Button("+"); 16 | private final Button removePointButton = new Button("-"); 17 | private final HBox pointsButtons = new HBox(addPointButton, removePointButton); 18 | 19 | public PolygonObstacleEditDialog(HPolygonObstacle polygonObstacle) { 20 | super(polygonObstacle, new HPolygonObstacle()); 21 | this.polygonObstacle = (HPolygonObstacle) obstacle; 22 | this.backupPolygonObstacle = (HPolygonObstacle) backupObstacle; 23 | 24 | pointsTable.setItems(this.polygonObstacle.getPoints()); 25 | 26 | addPointButton.setOnAction(event -> { 27 | this.polygonObstacle.getPoints().add(new HPolygonPoint()); 28 | }); 29 | 30 | removePointButton.setOnAction(event -> { 31 | this.polygonObstacle.getPoints().remove(pointsTable.getSelectionModel().getSelectedIndex()); 32 | }); 33 | 34 | vBox.getChildren().add(ADDITIONAL_NODES_ROW, pointsTable); 35 | vBox.getChildren().add(ADDITIONAL_NODES_ROW + 1, pointsButtons); 36 | 37 | backupObstacle(); 38 | // Set ui to values of Obstacle: 39 | initializeTextFields(); 40 | // Now bind the Obstacle to the values of the ui 41 | bindObstacle(); 42 | } 43 | 44 | @Override 45 | protected void initializeTextFields() { 46 | super.initializeTextFields(); 47 | } 48 | 49 | @Override 50 | protected void unbindObstacle() { 51 | super.unbindObstacle(); 52 | } 53 | 54 | @Override 55 | protected void bindObstacle() { 56 | super.bindObstacle(); 57 | } 58 | 59 | @Override 60 | protected void backupObstacle() { 61 | super.backupObstacle(); 62 | backupPolygonObstaclePoints(polygonObstacle, backupPolygonObstacle); 63 | } 64 | 65 | @Override 66 | protected void restoreBackup() { 67 | super.restoreBackup(); 68 | restorePolygonObstaclePoints(polygonObstacle, backupPolygonObstacle); 69 | } 70 | 71 | private static void backupPolygonObstaclePoints(HPolygonObstacle polygonObstacle, HPolygonObstacle backupPolygonObstacle) { 72 | backupPolygonObstacle.getPoints().clear(); 73 | for (HPolygonPoint point : polygonObstacle.getPoints()) { 74 | HPolygonPoint backupPoint = new HPolygonPoint(); 75 | backupPoint.setX(point.getX()); 76 | backupPoint.setY(point.getY()); 77 | backupPolygonObstacle.getPoints().add(backupPoint); 78 | // need to create new polygon point objects since they would update together if didn't 79 | } 80 | } 81 | 82 | private static void restorePolygonObstaclePoints(HPolygonObstacle polygonObstacle, HPolygonObstacle backupPolygonObstacle) { 83 | polygonObstacle.getPoints().clear(); 84 | polygonObstacle.getPoints().addAll(backupPolygonObstacle.getPoints()); 85 | // it's ok to use same objects here since they aren't used for anything else 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/obstacle/PolygonPointsTableView.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.obstacle; 2 | 3 | import org.team2363.helixnavigator.document.obstacle.HPolygonPoint; 4 | 5 | import javafx.scene.control.TableColumn; 6 | import javafx.scene.control.TableView; 7 | import javafx.scene.control.cell.PropertyValueFactory; 8 | import javafx.scene.control.cell.TextFieldTableCell; 9 | import javafx.util.StringConverter; 10 | 11 | public class PolygonPointsTableView extends TableView { 12 | 13 | private final StringConverter decimalConverter = new StringConverter() { 14 | 15 | @Override 16 | public String toString(Double object) { 17 | if (object != null) { 18 | return Double.toString(object); 19 | } else { 20 | return ""; 21 | } 22 | } 23 | 24 | @Override 25 | public Double fromString(String string) { 26 | double rawValue; 27 | try { 28 | rawValue = Double.parseDouble(string); 29 | } catch (NumberFormatException e) { 30 | rawValue = 0.0; 31 | } 32 | return rawValue; 33 | } 34 | }; 35 | 36 | public PolygonPointsTableView() { 37 | TableColumn xColumn = new TableColumn<>("X"); 38 | xColumn.setCellFactory(TextFieldTableCell.forTableColumn(decimalConverter)); 39 | xColumn.setCellValueFactory(new PropertyValueFactory<>("x")); 40 | xColumn.setSortable(false); 41 | xColumn.setResizable(false); 42 | xColumn.setReorderable(false); 43 | xColumn.setPrefWidth(113); 44 | TableColumn yColumn = new TableColumn<>("Y"); 45 | yColumn.setCellFactory(TextFieldTableCell.forTableColumn(decimalConverter)); 46 | yColumn.setCellValueFactory(new PropertyValueFactory<>("y")); 47 | yColumn.setSortable(false); 48 | yColumn.setResizable(false); 49 | yColumn.setReorderable(false); 50 | yColumn.setPrefWidth(113); 51 | 52 | getColumns().add(xColumn); 53 | getColumns().add(yColumn); 54 | 55 | setEditable(true); 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/waypoint/HardWaypointEditDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.waypoint; 2 | 3 | import java.util.List; 4 | 5 | import org.team2363.helixnavigator.document.timeline.HHardWaypoint; 6 | 7 | import javafx.scene.layout.GridPane; 8 | import javafx.scene.text.Text; 9 | 10 | public class HardWaypointEditDialog extends WaypointEditDialog { 11 | 12 | private HHardWaypoint hardWaypoint; 13 | private HHardWaypoint backupHardWaypoint; 14 | 15 | private final Text headingText = new Text("Heading:"); 16 | private final HeadingTextField headingTextField = new HeadingTextField(); 17 | 18 | public HardWaypointEditDialog(HHardWaypoint hardWaypoint) { 19 | super(hardWaypoint, new HHardWaypoint()); 20 | this.hardWaypoint = (HHardWaypoint) waypoint; 21 | this.backupHardWaypoint = (HHardWaypoint) backupWaypoint; 22 | GridPane.setConstraints(headingText, 0, 3); 23 | GridPane.setConstraints(headingTextField, 1, 3); 24 | 25 | addGridItems(List.of(headingText, headingTextField)); 26 | backupWaypoint(); 27 | // Set ui to values of HWaypoint: 28 | initializeTextFields(); 29 | // Now bind the Waypoint to the values of the ui 30 | bindWaypoint(); 31 | } 32 | 33 | @Override 34 | protected void initializeTextFields() { 35 | super.initializeTextFields(); 36 | headingTextField.setValue(hardWaypoint.getHeading()); 37 | } 38 | 39 | @Override 40 | protected void unbindWaypoint() { 41 | super.unbindWaypoint(); 42 | hardWaypoint.headingProperty().unbind(); 43 | } 44 | 45 | @Override 46 | protected void bindWaypoint() { 47 | super.bindWaypoint(); 48 | hardWaypoint.headingProperty().bind(headingTextField.valueProperty()); 49 | } 50 | 51 | @Override 52 | protected void backupWaypoint() { 53 | super.backupWaypoint(); 54 | backupHardWaypoint.setHeading(hardWaypoint.getHeading()); 55 | } 56 | 57 | @Override 58 | protected void restoreBackup() { 59 | super.restoreBackup(); 60 | hardWaypoint.setHeading(backupHardWaypoint.getHeading()); 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/waypoint/HeadingTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.waypoint; 2 | 3 | import java.util.function.UnaryOperator; 4 | 5 | import javax.measure.quantity.Angle; 6 | 7 | import org.team2363.helixnavigator.global.Standards; 8 | import org.team2363.helixnavigator.global.Standards.ExportedUnits; 9 | import org.team2363.helixnavigator.global.Standards.SupportedUnits.SupportedAngle; 10 | import org.team2363.lib.ui.validation.UnitTextField; 11 | 12 | public class HeadingTextField extends UnitTextField { 13 | 14 | private static final UnaryOperator transformation = new UnaryOperator() { 15 | @Override 16 | public Double apply(Double input) { 17 | // if (Math.abs(input) >= 1E15) { 18 | // return 0.0; 19 | // } 20 | // int factor = (int) (input.doubleValue() / (2*Math.PI)); 21 | // input = input - (2*Math.PI) * factor; 22 | // if (input <= Standards.MIN_HEADING) { 23 | // return apply(input + (2*Math.PI)); 24 | // } else if (input > Standards.MAX_HEADING) { 25 | // return apply(input - (2*Math.PI)); 26 | // } else { 27 | // return input; 28 | // } 29 | return input; 30 | } 31 | }; 32 | 33 | public HeadingTextField() { 34 | super(ExportedUnits.ANGLE_UNIT, SupportedAngle.UNITS); 35 | setInputTransformation(transformation); 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/waypoint/InitialGuessWaypointEditDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.waypoint; 2 | 3 | import java.util.List; 4 | 5 | import org.team2363.helixnavigator.document.timeline.HInitialGuessWaypoint; 6 | 7 | import javafx.scene.layout.GridPane; 8 | import javafx.scene.text.Text; 9 | 10 | public class InitialGuessWaypointEditDialog extends WaypointEditDialog { 11 | 12 | private HInitialGuessWaypoint initialGuessWaypoint; 13 | private HInitialGuessWaypoint backupInitialGuessWaypoint; 14 | 15 | private final Text headingText = new Text("Heading:"); 16 | private final HeadingTextField headingTextField = new HeadingTextField(); 17 | 18 | public InitialGuessWaypointEditDialog(HInitialGuessWaypoint initialGuessWaypoint) { 19 | super(initialGuessWaypoint, new HInitialGuessWaypoint()); 20 | this.initialGuessWaypoint = (HInitialGuessWaypoint) super.waypoint; 21 | this.backupInitialGuessWaypoint = (HInitialGuessWaypoint) super.backupWaypoint; 22 | 23 | GridPane.setConstraints(headingText, 0, 3); 24 | GridPane.setConstraints(headingTextField, 1, 3); 25 | 26 | addGridItems(List.of(headingText, headingTextField)); 27 | 28 | backupWaypoint(); 29 | // Set ui to values of HWaypoint: 30 | initializeTextFields(); 31 | // Now bind the Waypoint to the values of the ui 32 | bindWaypoint(); 33 | } 34 | 35 | @Override 36 | protected void initializeTextFields() { 37 | super.initializeTextFields(); 38 | headingTextField.setValue(initialGuessWaypoint.getHeading()); 39 | } 40 | 41 | @Override 42 | protected void unbindWaypoint() { 43 | super.unbindWaypoint(); 44 | initialGuessWaypoint.headingProperty().unbind(); 45 | } 46 | 47 | @Override 48 | protected void bindWaypoint() { 49 | super.bindWaypoint(); 50 | initialGuessWaypoint.headingProperty().bind(headingTextField.valueProperty()); 51 | } 52 | 53 | @Override 54 | protected void backupWaypoint() { 55 | super.backupWaypoint(); 56 | backupInitialGuessWaypoint.setHeading(initialGuessWaypoint.getHeading()); 57 | } 58 | 59 | @Override 60 | protected void restoreBackup() { 61 | super.restoreBackup(); 62 | initialGuessWaypoint.setHeading(backupInitialGuessWaypoint.getHeading()); 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/helixnavigator/ui/prompts/waypoint/SoftWaypointEditDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.helixnavigator.ui.prompts.waypoint; 2 | 3 | import org.team2363.helixnavigator.document.timeline.HSoftWaypoint; 4 | 5 | public class SoftWaypointEditDialog extends WaypointEditDialog { 6 | 7 | // private HSoftWaypoint softWaypoint; 8 | // private HSoftWaypoint backupSoftWaypoint; 9 | 10 | public SoftWaypointEditDialog(HSoftWaypoint softWaypoint) { 11 | super(softWaypoint, new HSoftWaypoint()); 12 | // this.softWaypoint = (HSoftWaypoint) super.waypoint; 13 | // this.backupSoftWaypoint = (HSoftWaypoint) super.backupWaypoint; 14 | 15 | backupWaypoint(); 16 | // Set ui to values of HWaypoint: 17 | initializeTextFields(); 18 | // Now bind the Waypoint to the values of the ui 19 | bindWaypoint(); 20 | } 21 | 22 | // @Override 23 | // protected void initializeTextFields() { 24 | // super.initializeTextFields(); 25 | // } 26 | 27 | // @Override 28 | // protected void unbindWaypoint() { 29 | // super.unbindWaypoint(); 30 | // } 31 | 32 | // @Override 33 | // protected void bindWaypoint() { 34 | // super.bindWaypoint(); 35 | // } 36 | 37 | // @Override 38 | // protected void backupWaypoint() { 39 | // super.backupWaypoint(); 40 | // } 41 | 42 | // @Override 43 | // protected void restoreBackup() { 44 | // super.restoreBackup(); 45 | // } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/base64/Base64Decoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Justin Babilino 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | package org.team2363.lib.base64; 18 | 19 | import java.io.ByteArrayInputStream; 20 | import java.io.FileNotFoundException; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.util.Base64; 24 | 25 | /** 26 | * 27 | * @author Justin Babilino 28 | */ 29 | public class Base64Decoder { 30 | private byte[] decodedBytes; 31 | private InputStream inputStream; 32 | public Base64Decoder(byte[] bytes) { 33 | decodedBytes = Base64.getDecoder().decode(bytes); 34 | } 35 | public Base64Decoder(InputStream input) throws IOException { 36 | this(input.readAllBytes()); 37 | } 38 | public Base64Decoder(String base64String) throws FileNotFoundException { 39 | decodedBytes = Base64.getDecoder().decode(base64String); 40 | } 41 | public byte[] getDecodedBytes() { 42 | return decodedBytes; 43 | } 44 | public InputStream getDecodedInputStream() { 45 | if (inputStream == null) { 46 | inputStream = new ByteArrayInputStream(decodedBytes); 47 | } 48 | return inputStream; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/base64/Base64Encoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Justin Babilino 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | package org.team2363.lib.base64; 18 | 19 | import java.io.ByteArrayInputStream; 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.nio.charset.StandardCharsets; 25 | import java.util.Base64; 26 | 27 | public class Base64Encoder { 28 | private byte[] encodedBytes; 29 | private InputStream encodedInputStream; 30 | private String base64String; 31 | public Base64Encoder(byte[] data) { 32 | encodedBytes = Base64.getEncoder().encode(data); 33 | } 34 | public Base64Encoder(InputStream input) throws IOException { 35 | this(input.readAllBytes()); 36 | } 37 | public Base64Encoder(File file) throws IOException { 38 | this(new FileInputStream(file)); 39 | } 40 | public Base64Encoder(String filePath) throws IOException { 41 | this(new File(filePath)); 42 | } 43 | public byte[] getEncodedBytes() { 44 | return encodedBytes; 45 | } 46 | public InputStream getEncodedInputStream() { 47 | if (encodedInputStream == null) { 48 | encodedInputStream = new ByteArrayInputStream(encodedBytes); 49 | } 50 | return encodedInputStream; 51 | } 52 | public String getString() { 53 | if (base64String == null) { 54 | base64String = new String(encodedBytes, StandardCharsets.ISO_8859_1); 55 | } 56 | return base64String; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/base64/Base64Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Justin Babilino 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | package org.team2363.lib.base64; 18 | 19 | import javafx.application.Application; 20 | import javafx.scene.Scene; 21 | import javafx.scene.image.Image; 22 | import javafx.scene.image.ImageView; 23 | import javafx.scene.layout.Pane; 24 | import javafx.stage.Stage; 25 | 26 | /** 27 | * 28 | * @author Justin Babilino 29 | */ 30 | public class Base64Test extends Application { 31 | 32 | public static void main(String[] args) { 33 | launch(args); 34 | } 35 | 36 | @Override 37 | public void start(Stage stage) throws Exception { 38 | try { 39 | Base64Encoder encoder = new Base64Encoder("A:/bliss.png"); 40 | System.out.println(encoder.getString()); 41 | 42 | Base64Decoder decoder = new Base64Decoder(encoder.getEncodedBytes()); 43 | Image image = new Image(decoder.getDecodedInputStream()); 44 | ImageView iview = new ImageView(image); 45 | Scene scene = new Scene(new Pane(iview)); 46 | stage.setScene(scene); 47 | } catch (Exception e) { 48 | System.out.println(e.getMessage()); 49 | } 50 | stage.show(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/base64/FileEncodeTest.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.base64; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | public class FileEncodeTest { 7 | public static void main(String[] args) throws IOException { 8 | File file = new File("2020_field_image.png"); 9 | Base64Encoder encoder = new Base64Encoder(file); 10 | System.out.println(encoder.getString()); 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/MouseEventWrapper.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui; 2 | 3 | import javafx.event.EventHandler; 4 | import javafx.scene.input.MouseEvent; 5 | 6 | public class MouseEventWrapper { 7 | 8 | private final EventHandler onMousePressed; 9 | private final EventHandler onMouseDragBegin; 10 | private final EventHandler onMouseDragged; 11 | private final EventHandler onMouseDragEnd; 12 | private final EventHandler onMouseReleased; 13 | 14 | private final EventHandler wrappedOnMousePressed; 15 | private final EventHandler wrappedOnMouseDragged; 16 | private final EventHandler wrappedOnMouseReleased; 17 | 18 | private boolean inDrag = false; 19 | 20 | public MouseEventWrapper( 21 | EventHandler onMousePressed, 22 | EventHandler onMouseDragBegin, 23 | EventHandler onMouseDragged, 24 | EventHandler onMouseDragEnd, 25 | EventHandler onMouseReleased) { 26 | this.onMousePressed = onMousePressed; 27 | this.onMouseDragBegin = onMouseDragBegin; 28 | this.onMouseDragged = onMouseDragged; 29 | this.onMouseDragEnd = onMouseDragEnd; 30 | this.onMouseReleased = onMouseReleased; 31 | 32 | wrappedOnMousePressed = (event) -> { 33 | inDrag = false; // this is probably redundant, but it could help prevent bugs 34 | this.onMousePressed.handle(event); 35 | }; 36 | wrappedOnMouseDragged = (event) -> { 37 | if (!inDrag) { 38 | this.onMouseDragBegin.handle(event); 39 | inDrag = true; 40 | } 41 | this.onMouseDragged.handle(event); 42 | }; 43 | wrappedOnMouseReleased = (event) -> { 44 | if (inDrag) { 45 | this.onMouseDragEnd.handle(event); 46 | inDrag = false; 47 | } else { 48 | this.onMouseReleased.handle(event); 49 | } 50 | }; 51 | } 52 | 53 | public EventHandler getOnMousePressed() { 54 | return wrappedOnMousePressed; 55 | } 56 | 57 | public EventHandler getOnMouseDragged() { 58 | return wrappedOnMouseDragged; 59 | } 60 | 61 | public EventHandler getOnMouseReleased() { 62 | return wrappedOnMouseReleased; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/prompts/SavePrompt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Triple Helix Robotics - FRC Team 2363 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package org.team2363.lib.ui.prompts; 19 | 20 | import javafx.scene.control.ButtonType; 21 | import javafx.scene.control.Dialog; 22 | 23 | public class SavePrompt extends Dialog { 24 | public SavePrompt() { 25 | setHeaderText("Do you want to save the current document?"); 26 | getDialogPane().getButtonTypes().addAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/prompts/legacy/DecimalTextInputDialog.java: -------------------------------------------------------------------------------- 1 | // package org.team2363.lib.ui.prompts; 2 | 3 | // import javafx.application.Platform; 4 | // import javafx.beans.property.ObjectProperty; 5 | // import javafx.scene.control.TextFormatter; 6 | // import javafx.scene.control.TextInputDialog; 7 | 8 | // public class DecimalTextInputDialog extends TextInputDialog { 9 | 10 | // private final ObjectProperty value; 11 | 12 | // public DecimalTextInputDialog() { 13 | // TextFormatter formatter = new TextFormatter<>(DecimalTextField.DECIMAL_CONVERTER, 0.0, DecimalTextField.DECIMAL_FILTER); 14 | // value = formatter.valueProperty(); 15 | // getEditor().setTextFormatter(formatter); 16 | // getEditor().setText("0.0"); 17 | // getEditor().focusedProperty().addListener((val, wasFocused, isNowFocused) -> { 18 | // if (isNowFocused) { 19 | // Platform.runLater(getEditor()::selectAll); 20 | // } 21 | // }); 22 | // setHeaderText("Enter a number"); 23 | // } 24 | 25 | // public final ObjectProperty valueProperty() { 26 | // return value; 27 | // } 28 | 29 | // public final void setValue(double value) { 30 | // this.value.set(value); 31 | // } 32 | 33 | // public final double getValue() { 34 | // return value.get(); 35 | // } 36 | // } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/prompts/legacy/IntegerTextInputDialog.java: -------------------------------------------------------------------------------- 1 | // package org.team2363.lib.ui.prompts; 2 | 3 | // import javafx.application.Platform; 4 | // import javafx.beans.property.ObjectProperty; 5 | // import javafx.scene.control.TextFormatter; 6 | // import javafx.scene.control.TextInputDialog; 7 | 8 | // public class IntegerTextInputDialog extends TextInputDialog { 9 | 10 | // private final ObjectProperty value; 11 | 12 | // public IntegerTextInputDialog() { 13 | // TextFormatter formatter = new TextFormatter<>(IntegerTextField.INTEGER_CONVERTER, 0, IntegerTextField.INTEGER_FILTER); 14 | // value = formatter.valueProperty(); 15 | // getEditor().setTextFormatter(formatter); 16 | // getEditor().setText("0"); 17 | // getEditor().focusedProperty().addListener((val, wasFocused, isNowFocused) -> { 18 | // if (isNowFocused) { 19 | // Platform.runLater(getEditor()::selectAll); 20 | // } 21 | // }); 22 | // setHeaderText("Enter an integer"); 23 | // } 24 | 25 | // public final ObjectProperty valueProperty() { 26 | // return value; 27 | // } 28 | 29 | // public final void setValue(int value) { 30 | // this.value.set(value); 31 | // } 32 | 33 | // public final int getValue() { 34 | // return value.get(); 35 | // } 36 | // } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/DecimalTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.DecimalValidator.DECIMAL_CONVERTER; 4 | import static org.team2363.lib.ui.validation.DecimalValidator.DECIMAL_FILTER; 5 | 6 | import java.util.function.UnaryOperator; 7 | 8 | import javafx.application.Platform; 9 | import javafx.beans.property.ObjectProperty; 10 | import javafx.scene.control.TextField; 11 | import javafx.scene.control.TextFormatter; 12 | import javafx.util.StringConverter; 13 | 14 | public class DecimalTextField extends TextField { 15 | 16 | private final ObjectProperty value; 17 | 18 | private DecimalTextField(StringConverter converter) { 19 | TextFormatter formatter = new TextFormatter(converter, 0.0, DECIMAL_FILTER); 20 | value = formatter.valueProperty(); 21 | setTextFormatter(formatter); 22 | setText("0.0"); 23 | focusedProperty().addListener((val, wasFocused, isNowFocused) -> { 24 | if (isNowFocused) { 25 | Platform.runLater(this::selectAll); 26 | } 27 | }); 28 | setOnAction(event -> { 29 | selectAll(); 30 | }); 31 | } 32 | 33 | public DecimalTextField() { 34 | this(DECIMAL_CONVERTER); 35 | } 36 | 37 | public DecimalTextField(double lowerBound, double upperBound) { 38 | this(DecimalValidator.converter(lowerBound, upperBound)); 39 | } 40 | 41 | public DecimalTextField(UnaryOperator transformation) { 42 | this(DecimalValidator.converter(transformation)); 43 | } 44 | 45 | public final ObjectProperty valueProperty() { 46 | return value; 47 | } 48 | 49 | public final void setValue(double value) { 50 | this.value.set(value); 51 | } 52 | 53 | public final double getValue() { 54 | return value.get(); 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/DecimalValidator.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.FilteredTextField.filterFor; 4 | 5 | import java.util.function.UnaryOperator; 6 | import java.util.regex.Pattern; 7 | 8 | import javafx.scene.control.TextFormatter; 9 | import javafx.util.StringConverter; 10 | 11 | public class DecimalValidator { 12 | 13 | public static final Pattern DECIMAL_PATTERN = Pattern.compile("-?\\d*(\\.\\d*)?((e|E)\\d*)?"); 14 | public static final UnaryOperator DECIMAL_FILTER = filterFor(Integer.MAX_VALUE, DECIMAL_PATTERN); 15 | public static final StringConverter DECIMAL_CONVERTER = new DecimalValidator().getConverter(); 16 | 17 | public static StringConverter converter(double lowerBound, double upperBound) { 18 | return new DecimalValidator() { 19 | 20 | @Override 21 | protected double transformInput(double input) { 22 | return Math.min(Math.max(input, lowerBound), upperBound); 23 | } 24 | }.getConverter(); 25 | } 26 | 27 | public static StringConverter converter(UnaryOperator transformation) { 28 | return new DecimalValidator() { 29 | 30 | @Override 31 | protected double transformInput(double input) { 32 | return transformation.apply(input); 33 | } 34 | }.getConverter(); 35 | } 36 | 37 | private final StringConverter converter = new StringConverter<>() { 38 | 39 | @Override 40 | public String toString(Double object) { 41 | if (object != null) { 42 | return Double.toString(object); 43 | } else { 44 | return ""; 45 | } 46 | } 47 | 48 | @Override 49 | public Double fromString(String string) { 50 | double rawValue; 51 | try { 52 | rawValue = Double.parseDouble(string); 53 | } catch (NumberFormatException e) { 54 | rawValue = 0.0; 55 | } 56 | return transformInput(rawValue); 57 | } 58 | }; 59 | 60 | private DecimalValidator() { 61 | } 62 | 63 | protected double transformInput(double input) { 64 | return input; 65 | } 66 | 67 | public StringConverter getConverter() { 68 | return converter; 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/FilteredTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import java.util.function.UnaryOperator; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import javafx.beans.property.IntegerProperty; 8 | import javafx.beans.property.ObjectProperty; 9 | import javafx.beans.property.SimpleIntegerProperty; 10 | import javafx.beans.property.SimpleObjectProperty; 11 | import javafx.beans.value.ObservableValue; 12 | import javafx.scene.control.TextField; 13 | import javafx.scene.control.TextFormatter; 14 | 15 | public class FilteredTextField extends TextField { 16 | 17 | private final IntegerProperty maxChars = new SimpleIntegerProperty(this, "maxChars", Integer.MAX_VALUE); 18 | private final ObjectProperty validator = new SimpleObjectProperty<>(this, "validator", Pattern.compile(".*")); 19 | 20 | protected final UnaryOperator filter; 21 | 22 | public FilteredTextField() { 23 | filter = filterFor(maxChars, validator); 24 | setTextFormatter(new TextFormatter(filter)); 25 | maxChars.addListener((currentVal, oldVal, newVal) -> { 26 | if (getText().length() > newVal.intValue()) { 27 | setText(getText().substring(0, newVal.intValue())); 28 | } 29 | }); 30 | } 31 | 32 | public FilteredTextField(int maxChars, Pattern validator) { 33 | this(); 34 | setMaxChars(maxChars); 35 | setValidator(validator); 36 | } 37 | 38 | public final IntegerProperty maxCharsProperty() { 39 | return maxChars; 40 | } 41 | 42 | public final void setMaxChars(int value) { 43 | maxChars.set(value); 44 | } 45 | 46 | public final int getMaxChars() { 47 | return maxChars.get(); 48 | } 49 | 50 | public final ObjectProperty validatorProperty() { 51 | return validator; 52 | } 53 | 54 | public final void setValidator(Pattern value) { 55 | validator.set(value); 56 | } 57 | 58 | public final Pattern getValidator() { 59 | return validator.get(); 60 | } 61 | 62 | public static UnaryOperator filterFor(int maxChars, Pattern validator) { 63 | return input -> { 64 | String newText = input.getControlNewText(); 65 | Matcher matcher = validator.matcher(newText); 66 | if (!matcher.matches() || newText.length() > maxChars) { 67 | input.setText(""); 68 | } 69 | return input; 70 | }; 71 | } 72 | 73 | public static UnaryOperator filterFor(ObservableValue maxChars, ObservableValue validator) { 74 | return input -> { 75 | String newText = input.getControlNewText(); 76 | Matcher matcher = validator.getValue().matcher(newText); 77 | if (!matcher.matches() || newText.length() > maxChars.getValue().intValue()) { 78 | input.setText(""); 79 | } 80 | return input; 81 | }; 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/FilteredTextInputDialog.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.FilteredTextField.filterFor; 4 | 5 | import java.util.function.UnaryOperator; 6 | import java.util.regex.Pattern; 7 | 8 | import javafx.beans.property.IntegerProperty; 9 | import javafx.beans.property.ObjectProperty; 10 | import javafx.beans.property.SimpleIntegerProperty; 11 | import javafx.beans.property.SimpleObjectProperty; 12 | import javafx.scene.control.TextFormatter; 13 | import javafx.scene.control.TextInputDialog; 14 | 15 | public class FilteredTextInputDialog extends TextInputDialog { 16 | 17 | private IntegerProperty maxChars = new SimpleIntegerProperty(this, "maxChars", Integer.MAX_VALUE); 18 | private ObjectProperty validator = new SimpleObjectProperty<>(this, "validator", Pattern.compile(".*")); 19 | 20 | public FilteredTextInputDialog() { 21 | UnaryOperator filter = filterFor(maxChars, validator); 22 | getEditor().setTextFormatter(new TextFormatter(filter)); 23 | maxChars.addListener((currentVal, oldVal, newVal) -> { 24 | if (getEditor().getText().length() > newVal.intValue()) { 25 | getEditor().setText(getEditor().getText().substring(0, newVal.intValue())); 26 | } 27 | }); 28 | } 29 | 30 | public final IntegerProperty maxCharsProperty() { 31 | return maxChars; 32 | } 33 | 34 | public final void setMaxChars(int value) { 35 | maxChars.set(value); 36 | } 37 | 38 | public final int getMaxChars() { 39 | return maxChars.get(); 40 | } 41 | 42 | public final ObjectProperty validatorProperty() { 43 | return validator; 44 | } 45 | 46 | public final void setValidator(Pattern value) { 47 | validator.set(value); 48 | } 49 | 50 | public final Pattern getValidator() { 51 | return validator.get(); 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/IntegerTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.IntegerValidator.INTEGER_CONVERTER; 4 | import static org.team2363.lib.ui.validation.IntegerValidator.INTEGER_FILTER; 5 | 6 | import java.util.function.UnaryOperator; 7 | 8 | import javafx.application.Platform; 9 | import javafx.beans.property.ObjectProperty; 10 | import javafx.scene.control.TextField; 11 | import javafx.scene.control.TextFormatter; 12 | import javafx.util.StringConverter; 13 | 14 | public class IntegerTextField extends TextField { 15 | 16 | private final ObjectProperty value; 17 | 18 | private IntegerTextField(StringConverter converter) { 19 | TextFormatter formatter = new TextFormatter(converter, 0, INTEGER_FILTER); 20 | value = formatter.valueProperty(); 21 | setTextFormatter(formatter); 22 | setText("0"); 23 | focusedProperty().addListener((val, wasFocused, isNowFocused) -> { 24 | if (isNowFocused) { 25 | Platform.runLater(this::selectAll); 26 | } 27 | }); 28 | } 29 | 30 | public IntegerTextField() { 31 | this(INTEGER_CONVERTER); 32 | } 33 | 34 | public IntegerTextField(int lowerBound, int upperBound) { 35 | this(IntegerValidator.converter(lowerBound, upperBound)); 36 | } 37 | 38 | public IntegerTextField(UnaryOperator transformation) { 39 | this(IntegerValidator.converter(transformation)); 40 | } 41 | 42 | public final ObjectProperty valueProperty() { 43 | return value; 44 | } 45 | 46 | public final void setValue(int value) { 47 | this.value.set(value); 48 | } 49 | 50 | public final int getValue() { 51 | return value.get(); 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/IntegerValidator.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.FilteredTextField.filterFor; 4 | 5 | import java.util.function.UnaryOperator; 6 | import java.util.regex.Pattern; 7 | 8 | import javafx.scene.control.TextFormatter; 9 | import javafx.util.StringConverter; 10 | 11 | public class IntegerValidator { 12 | 13 | public static final Pattern INTEGER_PATTERN = Pattern.compile("-?\\d*((e|E)\\d*)?"); 14 | public static final UnaryOperator INTEGER_FILTER = filterFor(Integer.MAX_VALUE, INTEGER_PATTERN); 15 | public static final StringConverter INTEGER_CONVERTER = new IntegerValidator().getConverter(); 16 | 17 | public static StringConverter converter(int lowerBound, int upperBound) { 18 | return new IntegerValidator() { 19 | 20 | @Override 21 | protected int transformInput(int input) { 22 | return Math.min(Math.max(input, lowerBound), upperBound); 23 | } 24 | }.getConverter(); 25 | } 26 | 27 | public static StringConverter converter(UnaryOperator transformation) { 28 | return new IntegerValidator() { 29 | 30 | @Override 31 | protected int transformInput(int input) { 32 | return transformation.apply(input); 33 | } 34 | }.getConverter(); 35 | } 36 | 37 | private final StringConverter converter = new StringConverter<>() { 38 | 39 | @Override 40 | public String toString(Integer object) { 41 | if (object != null) { 42 | return Integer.toString(object); 43 | } else { 44 | return ""; 45 | } 46 | } 47 | 48 | @Override 49 | public Integer fromString(String string) { 50 | int rawValue; 51 | try { 52 | rawValue = Integer.parseInt(string); 53 | } catch (NumberFormatException e) { 54 | rawValue = 0; 55 | } 56 | return transformInput(rawValue); 57 | } 58 | }; 59 | 60 | private IntegerValidator() { 61 | } 62 | 63 | protected int transformInput(int input) { 64 | return input; 65 | } 66 | 67 | public StringConverter getConverter() { 68 | return converter; 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/MathExpressionTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import static org.team2363.lib.ui.validation.FilteredTextField.filterFor; 4 | 5 | import java.text.DecimalFormat; 6 | import java.util.function.UnaryOperator; 7 | import java.util.regex.Pattern; 8 | 9 | import org.team2363.lib.math.ExpressionParser; 10 | 11 | import javafx.application.Platform; 12 | import javafx.beans.property.ObjectProperty; 13 | import javafx.scene.control.TextField; 14 | import javafx.scene.control.TextFormatter; 15 | import javafx.util.StringConverter; 16 | 17 | public class MathExpressionTextField extends TextField { 18 | 19 | public static final Pattern EXPRESSION_VALIDATOR = Pattern.compile(".*"); 20 | public static final UnaryOperator EXPRESSION_FILTER = filterFor(Integer.MAX_VALUE, EXPRESSION_VALIDATOR); 21 | 22 | private DecimalFormat decimalFormat; 23 | private UnaryOperator inputTransformation = input -> input; 24 | private UnaryOperator outputTransformation = output -> output; 25 | private final StringConverter expressionConverter = new StringConverter() { 26 | 27 | @Override 28 | public String toString(Double object) { 29 | if (object != null) { 30 | double transformed = outputTransformation.apply(object); 31 | if (decimalFormat != null) { 32 | return decimalFormat.format(transformed); 33 | } else { 34 | return Double.toString(transformed); 35 | } 36 | } else { 37 | return ""; 38 | } 39 | } 40 | 41 | @Override 42 | public Double fromString(String string) { 43 | double rawValue; 44 | try { 45 | rawValue = ExpressionParser.eval(string); 46 | } catch (Exception e) { 47 | rawValue = 0.0; 48 | } 49 | return inputTransformation.apply(rawValue); 50 | } 51 | }; 52 | private final ObjectProperty value; 53 | 54 | public MathExpressionTextField() { 55 | // System.out.println("TESTING: Instantiating Math text field"); 56 | TextFormatter formatter = new TextFormatter(expressionConverter, 0.0, EXPRESSION_FILTER); 57 | value = formatter.valueProperty(); 58 | setTextFormatter(formatter); 59 | setText("0.0"); 60 | focusedProperty().addListener((val, wasFocused, isNowFocused) -> { 61 | if (isNowFocused) { 62 | Platform.runLater(this::selectAll); 63 | } 64 | }); 65 | setOnAction(event -> { 66 | selectAll(); 67 | }); 68 | } 69 | 70 | public final ObjectProperty valueProperty() { 71 | return value; 72 | } 73 | public final void setValue(double value) { 74 | this.value.set(value); 75 | } 76 | public final double getValue() { 77 | return value.get(); 78 | } 79 | 80 | public void setDecimalFormat(DecimalFormat decimalFormat) { 81 | this.decimalFormat = decimalFormat; 82 | } 83 | public void setInputTransformation(UnaryOperator transformation) { 84 | inputTransformation = transformation; 85 | } 86 | public void setOutputTransformation(UnaryOperator transformation) { 87 | outputTransformation = transformation; 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/ui/validation/UnitTextField.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.ui.validation; 2 | 3 | import java.text.DecimalFormat; 4 | import java.util.function.UnaryOperator; 5 | 6 | import javax.measure.Quantity; 7 | import javax.measure.Unit; 8 | 9 | import javafx.beans.property.ObjectProperty; 10 | import javafx.collections.ObservableList; 11 | import javafx.scene.control.ChoiceBox; 12 | import javafx.scene.layout.HBox; 13 | import javafx.scene.layout.Priority; 14 | import tech.units.indriya.quantity.Quantities; 15 | 16 | public class UnitTextField> extends HBox { 17 | 18 | private final Unit baseUnit; 19 | 20 | private final ChoiceBox> unitChoiceBox = new ChoiceBox<>(); 21 | private final MathExpressionTextField textField = new MathExpressionTextField(); 22 | 23 | private UnaryOperator inputTransformation = input -> input; 24 | 25 | public UnitTextField(Unit baseUnit, ObservableList> unitChoices) { 26 | // System.out.println("TESTING: Instantiating unit text field"); 27 | this.baseUnit = baseUnit; 28 | 29 | getChildren().addAll(textField, unitChoiceBox); 30 | unitChoiceBox.setMinWidth(60.0); 31 | unitChoiceBox.setMaxWidth(60.0); 32 | HBox.setHgrow(textField, Priority.ALWAYS); 33 | 34 | unitChoiceBox.setItems(unitChoices); 35 | unitChoiceBox.getSelectionModel().select(0); 36 | unitChoiceBox.setOnAction(event -> { 37 | // Might be a more natural way to do this. 38 | // You need to probe the text field so the text gets updated. 39 | textField.setValue(textField.getValue()); 40 | }); 41 | 42 | textField.setInputTransformation(input -> { 43 | Unit chosenUnit = unitChoiceBox.getValue(); 44 | Quantity quantity = Quantities.getQuantity(input, chosenUnit); 45 | input = quantity.to(baseUnit).getValue().doubleValue(); 46 | return inputTransformation.apply(input); 47 | }); 48 | textField.setOutputTransformation(output -> { 49 | Unit chosenUnit = unitChoiceBox.getValue(); 50 | Quantity quantity = Quantities.getQuantity(output, this.baseUnit); 51 | output = quantity.to(chosenUnit).getValue().doubleValue(); 52 | return output; 53 | }); 54 | } 55 | 56 | public ObjectProperty valueProperty() { 57 | return textField.valueProperty(); 58 | } 59 | public void setValue(double value) { 60 | textField.setValue(value); 61 | } 62 | public double getValue() { 63 | return textField.getValue(); 64 | } 65 | 66 | public void setCurrentUnit(Unit unit) { 67 | unitChoiceBox.getSelectionModel().select(unit); 68 | textField.setValue(textField.getValue()); 69 | } 70 | 71 | public void setDecimalFormat(DecimalFormat decimalFormat) { 72 | textField.setDecimalFormat(decimalFormat); 73 | } 74 | public void setInputTransformation(UnaryOperator transformation) { 75 | //TODO: add null checks for MathExpressionTextField 76 | if (transformation != null) { 77 | inputTransformation = transformation; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/unit/CustomUnits.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.unit; 2 | 3 | import javax.measure.Unit; 4 | import javax.measure.quantity.Acceleration; 5 | import javax.measure.quantity.Force; 6 | 7 | import si.uom.NonSI; 8 | import si.uom.quantity.AngularSpeed; 9 | import si.uom.quantity.Torque; 10 | import systems.uom.common.USCustomary; 11 | import systems.uom.unicode.CLDR; 12 | import tech.units.indriya.function.AddConverter; 13 | import tech.units.indriya.function.MultiplyConverter; 14 | import tech.units.indriya.unit.AlternateUnit; 15 | import tech.units.indriya.unit.ProductUnit; 16 | import tech.units.indriya.unit.TransformedUnit; 17 | import tech.units.indriya.unit.Units; 18 | 19 | public class CustomUnits { 20 | 21 | public static final Unit POUND_FORCE = new TransformedUnit( 22 | "lbf", "Pound-Force", Units.NEWTON, Units.NEWTON, MultiplyConverter.of(4.4482216152605)); 23 | 24 | public static final Unit NEWTON_METRE = 25 | new ProductUnit<>(Units.NEWTON.multiply(Units.METRE)); 26 | 27 | public static final Unit POUND_FOOT = 28 | new ProductUnit<>(POUND_FORCE.multiply(USCustomary.FOOT)); 29 | 30 | public static final Unit REVOLUTION_PER_MINUTE = 31 | new ProductUnit<>(NonSI.REVOLUTION.divide(Units.MINUTE)); 32 | 33 | public static final Unit DEGREE_ANGLE_PER_SECOND = 34 | new ProductUnit<>(NonSI.DEGREE_ANGLE.divide(Units.SECOND)); 35 | 36 | public static final Unit FOOT_PER_SQUARE_SECOND = 37 | new ProductUnit<>(USCustomary.FOOT.divide(Units.SECOND.pow(2))); 38 | 39 | public static final Unit KILOGRAM_SQUARE_METRE = 40 | new ProductUnit<>(Units.KILOGRAM.multiply(Units.SQUARE_METRE)); 41 | 42 | public static final Unit POUND_SQUARE_INCH = 43 | new ProductUnit<>(USCustomary.POUND.multiply(USCustomary.INCH.pow(2))); 44 | } -------------------------------------------------------------------------------- /app/src/main/java/org/team2363/lib/unit/MomentOfInertia.java: -------------------------------------------------------------------------------- 1 | package org.team2363.lib.unit; 2 | 3 | import javax.measure.Quantity; 4 | 5 | public interface MomentOfInertia extends Quantity { 6 | } -------------------------------------------------------------------------------- /app/src/main/resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/icon.icns -------------------------------------------------------------------------------- /app/src/main/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/icon.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/2021-infiniterechargeathome.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Infinite Recharge At Home", 3 | "field-image": "2021-infiniterechargeathome.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 0, 7 | 0 8 | ], 9 | "bottom-right": [ 10 | 1000, 11 | 500 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/2021-infiniterechargeathome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/2021-infiniterechargeathome.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/blankfield.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Blank Field", 3 | "field-image": "blankfield.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 0, 7 | 0 8 | ], 9 | "bottom-right": [ 10 | 649, 11 | 319 12 | ] 13 | }, 14 | "field-size": [ 15 | 54, 16 | 27 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/blankfield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/extrafieldimages/blankfield.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2018-field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2018-field.jpg -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2018-powerup.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "FIRST Power Up", 3 | "field-image": "2018-field.jpg", 4 | "field-corners": { 5 | "top-left": [ 6 | 125, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 827, 11 | 370 12 | ] 13 | }, 14 | "field-size": [ 15 | 54, 16 | 27 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2019-deepspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Destination: Deep Space", 3 | "field-image": "2019-field.jpg", 4 | "field-corners": { 5 | "top-left": [ 6 | 217, 7 | 40 8 | ], 9 | "bottom-right": [ 10 | 1372, 11 | 615 12 | ] 13 | }, 14 | "field-size": [ 15 | 54, 16 | 27 17 | ], 18 | "field-unit": "foot" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2019-field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2019-field.jpg -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2020-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2020-field.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2020-infiniterecharge.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Infinite Recharge", 3 | "field-image": "2020-field.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 96, 7 | 25 8 | ], 9 | "bottom-right": [ 10 | 1040, 11 | 514 12 | ] 13 | }, 14 | "field-size": [ 15 | 52.4375, 16 | 26.9375 17 | ], 18 | "field-unit": "foot" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-barrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-barrel.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-barrelracingpath.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Barrel Racing Path", 3 | "field-image": "2021-barrel.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 20, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 780, 11 | 400 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-bounce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-bounce.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-bouncepath.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Bounce Path", 3 | "field-image": "2021-bounce.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 20, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 780, 11 | 400 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-field.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearcha.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Galactic Search A", 3 | "field-image": "2021-galacticsearcha.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 20, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 780, 11 | 400 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearcha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearcha.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearchb.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Galactic Search B", 3 | "field-image": "2021-galacticsearchb.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 20, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 780, 11 | 400 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearchb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-galacticsearchb.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-infiniterecharge.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Infinite Recharge 2021", 3 | "field-image": "2021-field.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 127, 7 | 34 8 | ], 9 | "bottom-right": [ 10 | 1323, 11 | 649 12 | ] 13 | }, 14 | "field-size": [ 15 | 52.4375, 16 | 26.9375 17 | ], 18 | "field-unit": "foot" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-slalom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-slalom.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2021-slalompath.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Slalom Path", 3 | "field-image": "2021-slalom.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 20, 7 | 20 8 | ], 9 | "bottom-right": [ 10 | 780, 11 | 400 12 | ] 13 | }, 14 | "field-size": [ 15 | 30, 16 | 15 17 | ], 18 | "field-unit": "feet" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2022-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2022-field.png -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2022-rapidreact.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Rapid React", 3 | "field-image": "2022-field.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 74, 7 | 50 8 | ], 9 | "bottom-right": [ 10 | 1774, 11 | 900 12 | ] 13 | }, 14 | "field-size": [ 15 | 54, 16 | 27 17 | ], 18 | "field-unit": "foot" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2023-chargedup.json: -------------------------------------------------------------------------------- 1 | { 2 | "game": "Charged Up", 3 | "field-image": "2023-field.png", 4 | "field-corners": { 5 | "top-left": [ 6 | 46, 7 | 36 8 | ], 9 | "bottom-right": [ 10 | 1088, 11 | 544 12 | ] 13 | }, 14 | "field-size": [ 15 | 54.27083, 16 | 26.2916 17 | ], 18 | "field-unit": "foot" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2023-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/org/team2363/helixnavigator/global/wpifieldimages/2023-field.png -------------------------------------------------------------------------------- /app/src/main/resources/script.py: -------------------------------------------------------------------------------- 1 | print("hello world") 2 | -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/hard_waypoint_100px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/hard_waypoint_100px.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/hard_waypoint_20px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/hard_waypoint_20px.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/soft_waypoint_100px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/soft_waypoint_100px.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/soft_waypoint_20px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/soft_waypoint_20px.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/waypoints_dragged_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/waypoints_dragged_1.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/waypoints_dragged_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/waypoints_dragged_2.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/waypoints_dragged_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/waypoints_dragged_3.png -------------------------------------------------------------------------------- /app/src/main/resources/waypoint_images/waypoints_dragged_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/app/src/main/resources/waypoint_images/waypoints_dragged_4.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TripleHelixProgramming/HelixNavigator/96ad2e91b2e68bd2e3f132202340d14017fd372b/gradlew -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "HelixNavigator" 2 | include("app") --------------------------------------------------------------------------------