From 386ba3fd0cd473c1fb7a6df93725cb09705494c5 Mon Sep 17 00:00:00 2001 From: Karl Zschiebsch Date: Thu, 4 May 2023 21:17:29 +0200 Subject: [PATCH] Init --- .github/workflows/codeql.yml | 76 ++++ .github/workflows/dependency-review.yml | 20 + .github/workflows/maven.yml | 31 ++ .gitignore | 12 + README.md | 57 +++ pom.xml | 133 +++++++ .../io/scvis/game/AbstractHostingClient.java | 31 ++ .../io/scvis/game/AbstractHostingServer.java | 47 +++ src/main/java/io/scvis/game/Board.java | 8 + src/main/java/io/scvis/game/Children.java | 10 + src/main/java/io/scvis/game/Clock.java | 46 +++ src/main/java/io/scvis/game/Entity.java | 19 + src/main/java/io/scvis/game/FixedBoard.java | 65 ++++ src/main/java/io/scvis/game/NetworkItem.java | 10 + src/main/java/io/scvis/game/Parent.java | 18 + src/main/java/io/scvis/game/TreeItem.java | 12 + src/main/java/io/scvis/game/UnsizedBoard.java | 23 ++ src/main/java/io/scvis/geometry/Area.java | 96 +++++ src/main/java/io/scvis/geometry/Border2D.java | 55 +++ src/main/java/io/scvis/geometry/Border3D.java | 41 ++ src/main/java/io/scvis/geometry/Kinetic.java | 19 + .../java/io/scvis/geometry/Kinetic2D.java | 99 +++++ .../java/io/scvis/geometry/Kinetic3D.java | 94 +++++ src/main/java/io/scvis/geometry/Layout2D.java | 129 +++++++ src/main/java/io/scvis/geometry/Layout3D.java | 137 +++++++ src/main/java/io/scvis/geometry/Shape.java | 359 ++++++++++++++++++ src/main/java/io/scvis/geometry/Vector2D.java | 143 +++++++ src/main/java/io/scvis/geometry/Vector3D.java | 127 +++++++ .../io/scvis/observable/ChangeListener.java | 52 +++ .../java/io/scvis/observable/EventType.java | 15 + .../observable/InvalidationListener.java | 35 ++ .../java/io/scvis/observable/Objective.java | 51 +++ .../io/scvis/observable/ObjectiveManager.java | 29 ++ .../java/io/scvis/observable/Observable.java | 8 + .../java/io/scvis/observable/Property.java | 96 +++++ .../scvis/proto/AbstractExchangeHelper.java | 30 ++ .../io/scvis/proto/AbstractStoreHelper.java | 41 ++ .../java/io/scvis/proto/Corresponding.java | 21 + .../java/io/scvis/proto/ExchangeHelper.java | 47 +++ .../java/io/scvis/proto/Identifiable.java | 23 ++ src/main/java/io/scvis/proto/Mapper.java | 26 ++ src/main/java/io/scvis/proto/Mirror.java | 33 ++ src/main/java/io/scvis/proto/Reference.java | 5 + src/main/proto/io/scvis/game/hosting.proto | 55 +++ .../proto/io/scvis/geometry/kinetic2d.proto | 14 + .../proto/io/scvis/geometry/layout2d.proto | 10 + src/main/proto/io/scvis/geometry/shape.proto | 19 + .../proto/io/scvis/geometry/vector2d.proto | 9 + .../proto/io/scvis/geometry/vector3d.proto | 10 + .../proto/io/scvis/proto/identifiable.proto | 9 + src/test/java/io/scvis/TestSerialisation.java | 91 +++++ src/test/java/io/scvis/TestVector.java | 25 ++ 52 files changed, 2671 insertions(+) create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/maven.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/io/scvis/game/AbstractHostingClient.java create mode 100644 src/main/java/io/scvis/game/AbstractHostingServer.java create mode 100644 src/main/java/io/scvis/game/Board.java create mode 100644 src/main/java/io/scvis/game/Children.java create mode 100644 src/main/java/io/scvis/game/Clock.java create mode 100644 src/main/java/io/scvis/game/Entity.java create mode 100644 src/main/java/io/scvis/game/FixedBoard.java create mode 100644 src/main/java/io/scvis/game/NetworkItem.java create mode 100644 src/main/java/io/scvis/game/Parent.java create mode 100644 src/main/java/io/scvis/game/TreeItem.java create mode 100644 src/main/java/io/scvis/game/UnsizedBoard.java create mode 100644 src/main/java/io/scvis/geometry/Area.java create mode 100644 src/main/java/io/scvis/geometry/Border2D.java create mode 100644 src/main/java/io/scvis/geometry/Border3D.java create mode 100644 src/main/java/io/scvis/geometry/Kinetic.java create mode 100644 src/main/java/io/scvis/geometry/Kinetic2D.java create mode 100644 src/main/java/io/scvis/geometry/Kinetic3D.java create mode 100644 src/main/java/io/scvis/geometry/Layout2D.java create mode 100644 src/main/java/io/scvis/geometry/Layout3D.java create mode 100644 src/main/java/io/scvis/geometry/Shape.java create mode 100644 src/main/java/io/scvis/geometry/Vector2D.java create mode 100644 src/main/java/io/scvis/geometry/Vector3D.java create mode 100644 src/main/java/io/scvis/observable/ChangeListener.java create mode 100644 src/main/java/io/scvis/observable/EventType.java create mode 100644 src/main/java/io/scvis/observable/InvalidationListener.java create mode 100644 src/main/java/io/scvis/observable/Objective.java create mode 100644 src/main/java/io/scvis/observable/ObjectiveManager.java create mode 100644 src/main/java/io/scvis/observable/Observable.java create mode 100644 src/main/java/io/scvis/observable/Property.java create mode 100644 src/main/java/io/scvis/proto/AbstractExchangeHelper.java create mode 100644 src/main/java/io/scvis/proto/AbstractStoreHelper.java create mode 100644 src/main/java/io/scvis/proto/Corresponding.java create mode 100644 src/main/java/io/scvis/proto/ExchangeHelper.java create mode 100644 src/main/java/io/scvis/proto/Identifiable.java create mode 100644 src/main/java/io/scvis/proto/Mapper.java create mode 100644 src/main/java/io/scvis/proto/Mirror.java create mode 100644 src/main/java/io/scvis/proto/Reference.java create mode 100644 src/main/proto/io/scvis/game/hosting.proto create mode 100644 src/main/proto/io/scvis/geometry/kinetic2d.proto create mode 100644 src/main/proto/io/scvis/geometry/layout2d.proto create mode 100644 src/main/proto/io/scvis/geometry/shape.proto create mode 100644 src/main/proto/io/scvis/geometry/vector2d.proto create mode 100644 src/main/proto/io/scvis/geometry/vector3d.proto create mode 100644 src/main/proto/io/scvis/proto/identifiable.proto create mode 100644 src/test/java/io/scvis/TestSerialisation.java create mode 100644 src/test/java/io/scvis/TestVector.java diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f7ca1e8 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,76 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '39 9 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..fe461b4 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v2 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..c97b5b3 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,31 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn install diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f952401 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# generated classes +target +*.class +*.jar + +# Eclipse +.settings/* +*.classpath +*.project + +# VS Code +.vscode/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac89344 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# scvis +[![Release](https://jitpack.io/v/karl-zschiebsch/scvis.svg)](https://jitpack.io/#karl-zschiebsch/scvis) +[![CodeQL](https://github.com/karl-zschiebsch/scvis/actions/workflows/codeql.yml/badge.svg)](https://github.com/karl-zschiebsch/scvis/actions/workflows/codeql.yml) +[![Dependency Review](https://github.com/karl-zschiebsch/scvis/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/karl-zschiebsch/scvis/actions/workflows/dependency-review.yml) +[![Java CI with Maven](https://github.com/karl-zschiebsch/scvis/actions/workflows/maven.yml/badge.svg)](https://github.com/karl-zschiebsch/scvis/actions/workflows/maven.yml) + +## Table of Content +- [Table of Content](#table-of-content) +- [Installation](#installation) + - [Maven](#maven) + - [Gradle](#gradle) +- [Features](#features) + - [Game](#game) + - [Geometry](#geometry) + - [Observable](#observable) + - [Proto](#proto) + +## Installation +### Maven +```xml + + + jitpack.io + https://jitpack.io + + +``` + +```xml + + com.github.karl-zschiebsch + scvis + tag + +``` +### Gradle +```gradle +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} +``` + +```gradle +dependencies { + implementation 'com.github.karl-zschiebsch:scvis:tag' +} +``` +## Features +### Game + +### Geometry + +### Observable + +### Proto \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..511ecb6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,133 @@ + + 4.0.0 + io.scvis + scvis + 0.0.1-SNAPSHOT + + UTF-8 + 11 + 1.53.0 + ${project.javaVersion} + ${project.javaVersion} + ${project.javaVersion} + + + + + com.google.protobuf + protobuf-java + 3.22.2 + + + io.grpc + grpc-netty-shaded + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + javax.annotation + javax.annotation-api + 1.3.2 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.14.1 + + + + org.slf4j + slf4j-api + 2.0.7 + + + org.slf4j + slf4j-simple + 2.0.7 + + + org.pf4j + pf4j-update + 2.3.0 + + + + org.junit.jupiter + junit-jupiter-api + 5.9.1 + test + + + org.junit.jupiter + junit-jupiter-params + 5.9.1 + test + + + + + + + io.grpc + grpc-bom + ${grpc.version} + pom + import + + + + + + + + kr.motd.maven + os-maven-plugin + 1.6.2 + + + + + + kr.motd.maven + os-maven-plugin + 1.7.0 + + + initialize + + detect + + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + + compile + compile-custom + test-compile + test-compile-custom + + + + + + + \ No newline at end of file diff --git a/src/main/java/io/scvis/game/AbstractHostingClient.java b/src/main/java/io/scvis/game/AbstractHostingClient.java new file mode 100644 index 0000000..6b79eb3 --- /dev/null +++ b/src/main/java/io/scvis/game/AbstractHostingClient.java @@ -0,0 +1,31 @@ +package io.scvis.game; + +import java.util.Set; + +import io.scvis.grpc.game.GameDescription; +import io.scvis.grpc.game.HostResponse; +import io.scvis.grpc.game.JoinResponse; +import io.scvis.grpc.game.ListResponse; +import io.scvis.grpc.game.PingResponse; + +public abstract class AbstractHostingClient { + + public abstract ListResponse list(); + + public abstract HostResponse host(); + + public abstract JoinResponse join(); + + public abstract PingResponse ping(); + + protected Set descriptions; + + public Set getDescriptions() { + return descriptions; + } + + public long getPing() { + long now = System.currentTimeMillis(); + return ping().getPing() - now; + } +} diff --git a/src/main/java/io/scvis/game/AbstractHostingServer.java b/src/main/java/io/scvis/game/AbstractHostingServer.java new file mode 100644 index 0000000..743053b --- /dev/null +++ b/src/main/java/io/scvis/game/AbstractHostingServer.java @@ -0,0 +1,47 @@ +package io.scvis.game; + +import java.util.Set; + +import io.grpc.stub.StreamObserver; +import io.scvis.grpc.game.GameDescription; +import io.scvis.grpc.game.HostRequest; +import io.scvis.grpc.game.HostResponse; +import io.scvis.grpc.game.HostingGrpc.HostingImplBase; +import io.scvis.grpc.game.JoinRequest; +import io.scvis.grpc.game.JoinResponse; +import io.scvis.grpc.game.ListRequest; +import io.scvis.grpc.game.ListResponse; +import io.scvis.grpc.game.PingRequest; +import io.scvis.grpc.game.PingResponse; + +public class AbstractHostingServer { + + protected AbstractHostingService service; + + public AbstractHostingService getService() { + return service; + } + + public static abstract class AbstractHostingService extends HostingImplBase { + @Override + public abstract void host(HostRequest request, StreamObserver responseObserver); + + @Override + public abstract void join(JoinRequest request, StreamObserver responseObserver); + + @Override + public abstract void list(ListRequest request, StreamObserver responseObserver); + + @Override + public void ping(PingRequest request, StreamObserver responseObserver) { + responseObserver.onNext(PingResponse.newBuilder().setPing(System.currentTimeMillis()).build()); + responseObserver.onCompleted(); + } + + protected Set descriptions; + + public Set getDescriptions() { + return descriptions; + } + } +} diff --git a/src/main/java/io/scvis/game/Board.java b/src/main/java/io/scvis/game/Board.java new file mode 100644 index 0000000..459e3d4 --- /dev/null +++ b/src/main/java/io/scvis/game/Board.java @@ -0,0 +1,8 @@ +package io.scvis.game; + +public interface Board { + + V get(R row, C column); + + V set(R row, C column, V value); +} diff --git a/src/main/java/io/scvis/game/Children.java b/src/main/java/io/scvis/game/Children.java new file mode 100644 index 0000000..b77f0ec --- /dev/null +++ b/src/main/java/io/scvis/game/Children.java @@ -0,0 +1,10 @@ +package io.scvis.game; + +public interface Children extends Entity { + + default void destroy() { + getParent().getChildren().remove(this); + } + + Parent getParent(); +} diff --git a/src/main/java/io/scvis/game/Clock.java b/src/main/java/io/scvis/game/Clock.java new file mode 100644 index 0000000..8751bf4 --- /dev/null +++ b/src/main/java/io/scvis/game/Clock.java @@ -0,0 +1,46 @@ +package io.scvis.game; + +public class Clock extends Thread { + private final long millis; + private final int nanos; + + private boolean done = false; + + public Clock(Runnable target, long millis, int nanos) { + super(target, Clock.class.getName()); + assert target != null; + setDaemon(true); + this.millis = millis; + this.nanos = nanos; + } + + public Clock(Runnable target, long millis) { + this(target, millis, 0); + } + + public Clock(Runnable target) { + this(target, 0l, 0); + } + + @Override + public final void run() { + while (!done) { + synchronized (this) { + try { + wait(millis, nanos); + } catch (InterruptedException e) { + break; // we are fine with this + } + } + super.run(); + } + } + + public boolean isDone() { + return done; + } + + public void markAsDone() { + done = true; + } +} diff --git a/src/main/java/io/scvis/game/Entity.java b/src/main/java/io/scvis/game/Entity.java new file mode 100644 index 0000000..a0771d9 --- /dev/null +++ b/src/main/java/io/scvis/game/Entity.java @@ -0,0 +1,19 @@ +package io.scvis.game; + +/** + * Entities are objects in a discrete simulation that can be updated over time. + * + * @author karlz + * @see Parent + * @see Children + * @see #update(double) + */ +public interface Entity { + + /** + * updates the object with a time difference of deltaT time units. + * + * @param deltaT The time difference. + */ + void update(double deltaT); +} diff --git a/src/main/java/io/scvis/game/FixedBoard.java b/src/main/java/io/scvis/game/FixedBoard.java new file mode 100644 index 0000000..3643800 --- /dev/null +++ b/src/main/java/io/scvis/game/FixedBoard.java @@ -0,0 +1,65 @@ +package io.scvis.game; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class FixedBoard implements Board { + + private final Map rowsToIndex; + private final Map columnsToIndex; + + private final Set rows; + private final Set columns; + + private final V fields[][]; + + public FixedBoard(Set rows, Set columns) { + this.rowsToIndex = mapToIndex(rows); + this.columnsToIndex = mapToIndex(columns); + + this.rows = rows; + this.columns = columns; + @SuppressWarnings("unchecked") + V array[][] = (V[][]) new Object[rows.size()][columns.size()]; + this.fields = array; + } + + private Map mapToIndex(Collection iter) { + Map generated = new HashMap<>(iter.size()); + Iterator iterator = iter.iterator(); + for (int index = 0; iterator.hasNext(); index++) + generated.put(iterator.next(), index); + return generated; + } + + public boolean containsRow(R row) { + return rows.contains(row); + } + + public boolean containsColumn(C column) { + return columns.contains(column); + } + + public V get(int row, int column) { + return fields[row][column]; + } + + public V set(int row, int column, V value) { + V previous = get(row, column); + fields[row][column] = value; + return previous; + } + + @Override + public V get(R row, C column) { + return get(rowsToIndex.get(row), columnsToIndex.get(column)); + } + + @Override + public V set(R row, C column, V value) { + return set(rowsToIndex.get(row), columnsToIndex.get(column), value); + } +} diff --git a/src/main/java/io/scvis/game/NetworkItem.java b/src/main/java/io/scvis/game/NetworkItem.java new file mode 100644 index 0000000..107c3c8 --- /dev/null +++ b/src/main/java/io/scvis/game/NetworkItem.java @@ -0,0 +1,10 @@ +package io.scvis.game; + +import java.util.Collection; + +public interface NetworkItem { + + S getNode(); + + Collection getConnections(); +} diff --git a/src/main/java/io/scvis/game/Parent.java b/src/main/java/io/scvis/game/Parent.java new file mode 100644 index 0000000..97fa7fd --- /dev/null +++ b/src/main/java/io/scvis/game/Parent.java @@ -0,0 +1,18 @@ +package io.scvis.game; + +import java.util.List; + +import javax.annotation.Nonnull; + +public interface Parent extends Entity { + + @Override + default void update(double deltaT) { + for (int i = 0; i < getChildren().size(); i++) { + getChildren().get(i).update(deltaT); + } + } + + @Nonnull + List getChildren(); +} diff --git a/src/main/java/io/scvis/game/TreeItem.java b/src/main/java/io/scvis/game/TreeItem.java new file mode 100644 index 0000000..64705fe --- /dev/null +++ b/src/main/java/io/scvis/game/TreeItem.java @@ -0,0 +1,12 @@ +package io.scvis.game; + +import java.util.Collection; + +public interface TreeItem { + + R getOrigin(); + + S getTribe(); + + Collection getBranches(); +} diff --git a/src/main/java/io/scvis/game/UnsizedBoard.java b/src/main/java/io/scvis/game/UnsizedBoard.java new file mode 100644 index 0000000..cb5526b --- /dev/null +++ b/src/main/java/io/scvis/game/UnsizedBoard.java @@ -0,0 +1,23 @@ +package io.scvis.game; + +import java.util.HashMap; +import java.util.Map; + +public class UnsizedBoard implements Board { + + private final Map> fields = new HashMap<>(); + + private Map getColumn(R row) { + return fields.computeIfAbsent(row, r -> new HashMap<>()); + } + + @Override + public V get(R row, C column) { + return getColumn(row).get(column); + } + + @Override + public V set(R row, C column, V value) { + return getColumn(row).put(column, value); + } +} diff --git a/src/main/java/io/scvis/geometry/Area.java b/src/main/java/io/scvis/geometry/Area.java new file mode 100644 index 0000000..5ec1973 --- /dev/null +++ b/src/main/java/io/scvis/geometry/Area.java @@ -0,0 +1,96 @@ +package io.scvis.geometry; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import io.scvis.geometry.Shape.Polygon; +import io.scvis.proto.Mapper; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public final class Area implements Border2D { + @JsonProperty("outsides") + private final List outsides; + @JsonProperty("insides") + private final List insides; + + @JsonCreator + public Area(@JsonProperty("outsides") List outsides, + @JsonProperty("insides") List insides) { + this.outsides = outsides; + this.insides = insides; + } + + public Area(Border2D border2D) { + outsides = List.of(border2D); + insides = List.of(); + } + + @Override + public boolean contains(@Nonnull Vector2D vector2D) { + for (Border2D outside : getOutsides()) { + if (outside.contains(vector2D)) { + for (Border2D inside : getInsides()) + if (inside.contains(vector2D)) + return false; + return true; + } + } + return false; + } + + @Override + public boolean intersects(@Nonnull Border2D border2D) { + for (Border2D outside : getOutsides()) { + if (outside.intersects(border2D)) + return true; + } + return false; + } + + @Override + @Nonnull + public Area translate(double x, double y) { + Mapper mapper = Mapper.create((Border2D e) -> e.translate(x, y)); + return new Area(mapper.map(outsides), mapper.map(insides)); + } + + @Override + @Nonnull + public Area rotate(@Nonnull Vector2D center, double a) { + Mapper mapper = Mapper.create((Border2D e) -> e.rotate(center, a)); + return new Area(mapper.map(outsides), mapper.map(insides)); + } + + @Override + @Nonnull + public Vector2D centroid() { + List centers = new ArrayList<>(); + for (Border2D outside : getOutsides()) { + centers.add(outside.centroid()); + } + return new Polygon(centers).centroid(); + } + + public List getOutsides() { + return outsides; + } + + public List getInsides() { + return insides; + } + + @Override + public String toString() { + return "Area [outside = " + outsides + ", insides = " + insides + "]"; + } +} \ No newline at end of file diff --git a/src/main/java/io/scvis/geometry/Border2D.java b/src/main/java/io/scvis/geometry/Border2D.java new file mode 100644 index 0000000..ff2010a --- /dev/null +++ b/src/main/java/io/scvis/geometry/Border2D.java @@ -0,0 +1,55 @@ +package io.scvis.geometry; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import io.scvis.geometry.Shape.Circle; +import io.scvis.geometry.Shape.Polygon; +import io.scvis.geometry.Shape.Rectangle; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") +@JsonSubTypes({ @Type(value = Polygon.class, name = "Polygon"), @Type(value = Rectangle.class, name = "Rectangle"), + @Type(value = Circle.class, name = "Circle"), @Type(value = Area.class, name = "Area"), + @Type(value = Kinetic2D.class, name = "Kinetic") }) +@JsonSerialize +@JsonDeserialize +public interface Border2D { + @CheckReturnValue + boolean contains(@Nonnull Vector2D vector2D); + + @CheckReturnValue + boolean intersects(@Nonnull Border2D border2D); + + @CheckReturnValue + @Nonnull + Border2D translate(double x, double y); + + @CheckReturnValue + @Nonnull + default Border2D translate(@Nonnull Vector2D v) { + return translate(v.getX(), v.getY()); + } + + @CheckReturnValue + @Nonnull + Border2D rotate(@Nonnull Vector2D center, double a); + + @CheckReturnValue + @Nonnull + default Border2D rotate(double a) { + return rotate(centroid(), a); + } + + @CheckReturnValue + @Nonnull + Vector2D centroid(); + +} diff --git a/src/main/java/io/scvis/geometry/Border3D.java b/src/main/java/io/scvis/geometry/Border3D.java new file mode 100644 index 0000000..083b8ec --- /dev/null +++ b/src/main/java/io/scvis/geometry/Border3D.java @@ -0,0 +1,41 @@ +package io.scvis.geometry; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@JsonSerialize +@JsonDeserialize +public interface Border3D { + @CheckReturnValue + boolean contains(@Nonnull Vector3D vector3D); + + @CheckReturnValue + boolean intersects(@Nonnull Border3D border3D); + + @CheckReturnValue + @Nonnull + Border3D translate(double x, double y, double z); + + @CheckReturnValue + @Nonnull + default Border3D translate(@Nonnull Vector3D v) { + return translate(v.getX(), v.getY(), v.getZ()); + } + + @CheckReturnValue + @Nonnull + Border3D rotate(@Nonnull Vector3D center, double a, double b); + + @CheckReturnValue + @Nonnull + default Border3D rotate(double a, double b) { + return rotate(centroid(), a, b); + } + + @CheckReturnValue + @Nonnull + Vector3D centroid(); +} diff --git a/src/main/java/io/scvis/geometry/Kinetic.java b/src/main/java/io/scvis/geometry/Kinetic.java new file mode 100644 index 0000000..b345e5c --- /dev/null +++ b/src/main/java/io/scvis/geometry/Kinetic.java @@ -0,0 +1,19 @@ +package io.scvis.geometry; + +import io.scvis.game.Entity; + +public interface Kinetic extends Entity { + + @Override + default void update(double deltaT) { + accelerate(deltaT); + velocitate(deltaT); + displacement(deltaT); + } + + void accelerate(double deltaT); + + void velocitate(double deltaT); + + void displacement(double deltaT); +} diff --git a/src/main/java/io/scvis/geometry/Kinetic2D.java b/src/main/java/io/scvis/geometry/Kinetic2D.java new file mode 100644 index 0000000..475128b --- /dev/null +++ b/src/main/java/io/scvis/geometry/Kinetic2D.java @@ -0,0 +1,99 @@ +package io.scvis.geometry; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import io.scvis.proto.Identifiable; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public abstract class Kinetic2D extends Layout2D implements Kinetic, Identifiable { + + @JsonProperty(value = "acceleration", index = 17) + private Vector2D acceleration = Vector2D.ZERO; + @JsonProperty(value = "velocity", index = 18) + private Vector2D velocity = Vector2D.ZERO; + @JsonProperty(value = "circularSpeed", index = 19) + private double circularSpeed = 5; + + @JsonCreator + public Kinetic2D(@JsonProperty("local") @Nonnull Border2D local, + @JsonProperty("position") @Nonnull Vector2D position, @JsonProperty("rotation") double rotation, + @JsonProperty("acceleration") Vector2D acceleration, @JsonProperty("velocity") Vector2D velocity) { + super(local, position, rotation); + this.acceleration = acceleration; + this.velocity = velocity; + } + + @JsonProperty(value = "destination", index = 16) + @Nullable + private Vector2D destination = null; + + public boolean hasDestination() { + return destination != null; + } + + @Nonnull + public Vector2D getDestination() { + final Vector2D destination = this.destination; + if (destination != null) + return destination; + return getPosition(); + } + + public void setDestination(@Nullable Vector2D destination) { + this.destination = destination; + } + + @JsonIgnore + @Nullable + private Border2D target = null; + + public boolean hasTarget() { + return target != null; + } + + @Nonnull + public Border2D getTarget() { + final Border2D target = this.target; + if (target != null) + return target; + return this; + } + + public void setTarget(@Nullable Border2D target) { + this.target = target; + } + + public Vector2D getAcceleration() { + return acceleration; + } + + public void setAcceleration(Vector2D acceleration) { + this.acceleration = acceleration; + } + + public Vector2D getVelocity() { + return velocity; + } + + public void setVelocity(Vector2D velocity) { + this.velocity = velocity; + } + + public double getCircularSpeed() { + return circularSpeed; + } + + public void setCircularSpeed(double circularSpeed) { + this.circularSpeed = circularSpeed; + } +} diff --git a/src/main/java/io/scvis/geometry/Kinetic3D.java b/src/main/java/io/scvis/geometry/Kinetic3D.java new file mode 100644 index 0000000..d2d47cf --- /dev/null +++ b/src/main/java/io/scvis/geometry/Kinetic3D.java @@ -0,0 +1,94 @@ +package io.scvis.geometry; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import io.scvis.proto.Identifiable; + +public abstract class Kinetic3D extends Layout3D implements Kinetic, Identifiable { + + @JsonProperty(value = "acceleration", index = 17) + private double acceleration = 0.0; + @JsonProperty(value = "velocity", index = 18) + private double velocity = 0.0; + @JsonProperty(value = "circularSpeed", index = 19) + private double circularSpeed = 5; + + @JsonCreator + protected Kinetic3D(@JsonProperty("local") @Nonnull Border3D local, + @JsonProperty("position") @Nonnull Vector3D position, @JsonProperty("rotationA") double rotationA, + @JsonProperty("rotationB") double rotationB, @JsonProperty("acceleration") double acceleration, + @JsonProperty("velocity") double velocity) { + super(local, position, rotationA, rotationB); + this.acceleration = acceleration; + this.velocity = velocity; + } + + @JsonProperty(value = "destination", index = 16) + @Nullable + private Vector3D destination = null; + + public boolean hasDestination() { + return destination != null; + } + + @Nonnull + public Vector3D getDestination() { + final Vector3D destination = this.destination; + if (destination != null) + return destination; + return getPosition(); + } + + public void setDestination(@Nullable Vector3D destination) { + this.destination = destination; + } + + @JsonIgnore + @Nullable + private Border3D target = null; + + public boolean hasTarget() { + return target != null; + } + + @Nonnull + public Border3D getTarget() { + final Border3D target = this.target; + if (target != null) + return target; + return this; + } + + public void setTarget(@Nullable Border3D target) { + this.target = target; + } + + public double getAcceleration() { + return acceleration; + } + + public void setAcceleration(double acceleration) { + this.acceleration = acceleration; + } + + public double getVelocity() { + return velocity; + } + + public void setVelocity(double velocity) { + this.velocity = velocity; + } + + public double getCircularSpeed() { + return circularSpeed; + } + + public void setCircularSpeed(double circularSpeed) { + this.circularSpeed = circularSpeed; + } +} diff --git a/src/main/java/io/scvis/geometry/Layout2D.java b/src/main/java/io/scvis/geometry/Layout2D.java new file mode 100644 index 0000000..a8d4a67 --- /dev/null +++ b/src/main/java/io/scvis/geometry/Layout2D.java @@ -0,0 +1,129 @@ +package io.scvis.geometry; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.errorprone.annotations.DoNotCall; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public class Layout2D implements Border2D, Cloneable { + @JsonProperty(value = "local", index = 5) + @Nonnull + private final Border2D local; + @JsonIgnore + @CheckForNull + private transient Border2D parent; + + @JsonProperty(value = "position", index = 6) + @Nonnull + private Vector2D position = Vector2D.ZERO; + @JsonProperty(value = "rotation", index = 7) + private double rotation = 0; + + @JsonCreator + public Layout2D(@JsonProperty("local") @Nonnull Border2D local, + @JsonProperty("position") @Nonnull Vector2D position, @JsonProperty("rotation") double rotation) { + this.local = local; + this.position = position; + this.rotation = rotation; + } + + @Override + public Layout2D clone() { + return new Layout2D(local); + } + + public Layout2D(@Nonnull Border2D local) { + this.local = local; + } + + public void applyTransformation() { + if (changed || parent == null) { + this.parent = local.translate(position).rotate(rotation); + this.changed = false; + } + } + + @Override + public boolean contains(@Nonnull Vector2D vector2D) { + applyTransformation(); + return parent.contains(vector2D); + } + + @Override + public boolean intersects(@Nonnull Border2D border2D) { + applyTransformation(); + return parent.intersects(border2D); + } + + @JsonIgnore + protected transient boolean changed; + + @Override + @Nonnull + public Border2D translate(double x, double y) { + this.position = position.add(x, y); + this.changed = true; + return this; + } + + @Override + @Nonnull + public Border2D rotate(double a) { + this.rotation += a; + this.changed = true; + return this; + } + + @Override + @DoNotCall + @Nonnull + public Border2D rotate(@Nonnull Vector2D center, double a) { + throw new UnsupportedOperationException(); + } + + @Override + @Nonnull + public Vector2D centroid() { + applyTransformation(); + return parent.centroid(); + } + + @JsonIgnore + public Border2D getBorderInLocal() { + return local; + } + + @JsonIgnore + public Border2D getBorderInParent() { + applyTransformation(); + return parent; + } + + @Nonnull + public Vector2D getPosition() { + return position; + } + + public void setPosition(@Nonnull Vector2D position) { + this.changed = true; + this.position = position; + } + + public double getRotation() { + return rotation; + } + + public void setRotation(double rotation) { + this.changed = true; + this.rotation = rotation; + } +} diff --git a/src/main/java/io/scvis/geometry/Layout3D.java b/src/main/java/io/scvis/geometry/Layout3D.java new file mode 100644 index 0000000..171ecaf --- /dev/null +++ b/src/main/java/io/scvis/geometry/Layout3D.java @@ -0,0 +1,137 @@ +package io.scvis.geometry; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.errorprone.annotations.DoNotCall; + +public class Layout3D implements Border3D, Cloneable { + @JsonProperty(value = "local", index = 5) + @Nonnull + private final Border3D local; + @JsonIgnore + @CheckForNull + private transient Border3D parent; + + @JsonProperty(value = "position", index = 6) + @Nonnull + private Vector3D position = Vector3D.ZERO; + @JsonProperty(value = "rotationA", index = 7) + private double rotationA = 0; + @JsonProperty(value = "rotationB", index = 7) + private double rotationB = 0; + + @JsonCreator + public Layout3D(@JsonProperty("local") @Nonnull Border3D local, + @JsonProperty("position") @Nonnull Vector3D position, @JsonProperty("rotationA") double rotationA, + @JsonProperty("rotationB") double rotationB) { + this.local = local; + this.position = position; + this.rotationA = rotationA; + this.rotationB = rotationB; + } + + @Override + public Layout3D clone() { + return new Layout3D(local); + } + + public Layout3D(@Nonnull Border3D local) { + this.local = local; + } + + public void applyTransformation() { + if (changed || parent == null) { + this.parent = local.translate(position).rotate(rotationA, rotationB); + this.changed = false; + } + } + + @Override + public boolean contains(@Nonnull Vector3D vector3D) { + applyTransformation(); + return parent.contains(vector3D); + } + + @Override + public boolean intersects(@Nonnull Border3D border3D) { + applyTransformation(); + return parent.intersects(border3D); + } + + @JsonIgnore + protected transient boolean changed; + + @Override + @Nonnull + public Border3D translate(double x, double y, double z) { + this.position = position.add(x, y, z); + this.changed = true; + return this; + } + + @Override + @Nonnull + public Border3D rotate(double a, double b) { + this.rotationA += a; + this.rotationB += b; + this.changed = true; + return this; + } + + @Override + @DoNotCall + @Nonnull + public Border3D rotate(@Nonnull Vector3D center, double a, double b) { + throw new UnsupportedOperationException(); + } + + @Override + @Nonnull + public Vector3D centroid() { + applyTransformation(); + return parent.centroid(); + } + + @JsonIgnore + public Border3D getBorderInLocal() { + return local; + } + + @JsonIgnore + public Border3D getBorderInParent() { + applyTransformation(); + return parent; + } + + @Nonnull + public Vector3D getPosition() { + return position; + } + + public void setPosition(@Nonnull Vector3D position) { + this.changed = true; + this.position = position; + } + + public double getRotationA() { + return rotationA; + } + + public void setRotationA(double rotationA) { + this.changed = true; + this.rotationA = rotationA; + } + + public double getRotationB() { + return rotationB; + } + + public void setRotationB(double rotationB) { + this.changed = true; + this.rotationB = rotationB; + } +} diff --git a/src/main/java/io/scvis/geometry/Shape.java b/src/main/java/io/scvis/geometry/Shape.java new file mode 100644 index 0000000..698b653 --- /dev/null +++ b/src/main/java/io/scvis/geometry/Shape.java @@ -0,0 +1,359 @@ +package io.scvis.geometry; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import io.scvis.proto.Corresponding; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public abstract class Shape implements Border2D { + + protected Vector2D center; + + @Nonnull + public Vector2D getCenter() { + return centroid(); + } + + @JsonIgnore + private transient int hash = 0; + + @Override + public int hashCode() { + if (hash == 0) + hash = super.hashCode(); + return hash; + } + + @Override + public String toString() { + return "UnknownShape [center = " + center + ", class = " + getClass() + ", hash = " + hashCode() + "]"; + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + @JsonSerialize + @JsonDeserialize + public static class Polygon extends Shape implements Corresponding { + @JsonProperty("points") + @Nonnull + private final List points; + @JsonProperty("minX") + private final double minX; + @JsonProperty("minY") + private final double minY; + @JsonProperty("maxX") + private final double maxX; + @JsonProperty("maxY") + private final double maxY; + + @JsonCreator + protected Polygon(@JsonProperty("points") @Nonnull List points, @JsonProperty("minX") double minX, + @JsonProperty("minY") double minY, @JsonProperty("maxX") double maxX, + @JsonProperty("maxY") double maxY) { + this.points = points; + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + public Polygon(@Nonnull List points) { + this.points = points; + minX = pick(points, (a, b) -> (int) (a.getX() - b.getX())).getX(); + minY = pick(points, (a, b) -> (int) (a.getY() - b.getY())).getY(); + maxX = pick(points, (a, b) -> (int) (b.getX() - a.getX())).getX(); + maxY = pick(points, (a, b) -> (int) (b.getY() - a.getY())).getY(); + } + + private static boolean contains(List polygon, Vector2D vector2D) { + boolean inside = false; + for (int i = 0; i < polygon.size(); i++) { + int j = (i + 1) % polygon.size(); + if (crosses(polygon.get(i), polygon.get(j), vector2D)) + inside = !inside; + } + return inside; + } + + private static boolean crosses(Vector2D a, Vector2D b, Vector2D vector2D) { + if (vector2D.getY() == a.getY() && a.getY() == b.getY()) + if (a.getX() <= vector2D.getX() && vector2D.getX() <= b.getX() + || b.getX() <= vector2D.getX() && vector2D.getX() <= a.getX()) + return true; + else + return false; + if (vector2D.getY() == a.getY() && vector2D.getX() == b.getX()) + return true; + if (a.getY() > b.getY()) { + var t = a; + a = b; + b = t; + } + if (vector2D.getY() <= a.getY() || vector2D.getY() > b.getY()) + return false; + double x = (a.getX() - vector2D.getX()) * (b.getY() - vector2D.getY()) + - (a.getY() - vector2D.getY()) * (b.getX() - vector2D.getX()); + if (x < 0) + return false; + else + return true; + } + + private static T pick(List list, Comparator comparator) { + if (list.isEmpty()) + return null; + List temp = new ArrayList<>(list); + temp.sort(comparator); + return temp.get(0); + } + + @Override + public boolean contains(@Nonnull Vector2D vector2D) { + if (vector2D.getX() < minX || vector2D.getX() > maxX) + return false; + if (vector2D.getY() < minY || vector2D.getY() > maxY) + return false; + return contains(points, vector2D); + } + + @Override + public boolean intersects(@Nonnull Border2D border2D) { + if (border2D instanceof Polygon) { + Polygon poly = (Polygon) border2D; + for (Vector2D point : poly.getPoints()) + if (point != null) + if (contains(point)) + return true; + } + for (Vector2D point : getPoints()) + if (point != null) + if (contains(point)) + return true; + return false; + } + + @Override + @Nonnull + public Polygon translate(@Nonnull Vector2D v) { + return translate(v.getX(), v.getY()); + } + + @Override + @Nonnull + public Polygon translate(double x, double y) { + List points = new ArrayList<>(); + for (Vector2D point : this.points) + points.add(point.add(x, y)); + return new Polygon(points); + } + + @Override + @Nonnull + public Polygon rotate(double a) { + return rotate(centroid(), a); + } + + @Override + @Nonnull + public Polygon rotate(@Nonnull Vector2D center, double a) { + List points = new ArrayList<>(); + Vector2D centroid = center; + for (Vector2D point : this.points) + points.add(point.subtract(centroid).rotate(a).add(centroid)); + return new Polygon(points); + } + + @Override + @Nonnull + public Vector2D centroid() { + /* Checked */ + final Vector2D center = this.center; + if (center == null) { + double x = 0, y = 0; + for (Vector2D vector2D : points) { + x += vector2D.getX(); + y += vector2D.getY(); + } + return this.center = new Vector2D(x / points.size(), y / points.size()); + } + return center; + } + + @Nonnull + public List getPoints() { + return points; + } + + @Override + public String toString() { + return "Polygon [points = " + points + ", maxX = " + maxX + ", maxY = " + maxY + ", minX = " + minX + + ", minY = " + minY + "]"; + } + + @Override + public io.scvis.grpc.geometry.Polygon associated() { + return io.scvis.grpc.geometry.Polygon.newBuilder().addAllPoints(Corresponding.transform(points)).build(); + } + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + @JsonSerialize + @JsonDeserialize + public static class Rectangle extends Polygon { + @JsonProperty("width") + private final double width; + @JsonProperty("height") + private final double height; + + @JsonCreator + protected Rectangle(@JsonProperty("points") @Nonnull List points, @JsonProperty("minX") double minX, + @JsonProperty("minY") double minY, @JsonProperty("maxX") double maxX, @JsonProperty("maxY") double maxY, + @JsonProperty("width") double width, @JsonProperty("height") double height) { + super(points, minX, minY, maxX, maxY); + this.width = width; + this.height = height; + } + + public Rectangle(@Nonnull List points, double width, double height) { + super(points); + this.width = width; + this.height = height; + } + + public Rectangle(double width, double height) { + super(new ArrayList<>( + List.of(new Vector2D(0, 0), new Vector2D(width, 0), new Vector2D(width, height), new Vector2D(0, height))), + 0, 0, width, height); + this.width = width; + this.height = height; + } + + public Rectangle(double startX, double startY, double endX, double endY) { + super(new ArrayList<>(List.of(new Vector2D(startX, startY), new Vector2D(endX, startY), new Vector2D(endX, endY), + new Vector2D(startX, endY))), startX, startY, endX, endY); + this.width = endX - startX; + this.height = endY - startY; + } + + @Override + public Rectangle translate(Vector2D v) { + return translate(v.getX(), v.getY()); + } + + @Override + public Rectangle translate(double x, double y) { + List points = new ArrayList<>(); + for (Vector2D point : getPoints()) + points.add(point.add(x, y)); + return new Rectangle(points, width, height); + } + + @Override + @Nonnull + public Rectangle rotate(double a) { + return rotate(centroid(), a); + } + + @Override + @Nonnull + public Rectangle rotate(@Nonnull Vector2D center, double a) { + List points = new ArrayList<>(); + Vector2D centroid = center; + for (Vector2D point : getPoints()) + points.add(point.subtract(centroid).rotate(a).add(centroid)); + return new Rectangle(points, width, height); + } + + public double getWidth() { + return width; + } + + public double getHeight() { + return height; + } + + @Override + public String toString() { + return "Rectangle [points = " + getPoints() + ", width = " + width + ", height = " + height + "]"; + } + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + @JsonSerialize + @JsonDeserialize + public static class Circle extends Shape implements Corresponding { + @JsonProperty("radius") + private final double radius; + + @JsonCreator + public Circle(@JsonProperty("center") @Nonnull Vector2D center, @JsonProperty("radius") double radius) { + this.center = center; + this.radius = radius; + } + + @Override + public boolean contains(@Nonnull Vector2D v) { + v = v.subtract(center); + return radius >= v.magnitude(); + } + + @Override + public boolean intersects(@Nonnull Border2D border2D) { + if (border2D instanceof Circle) { + Circle circle = (Circle) border2D; + return (radius + circle.radius) >= center.subtract(circle.center).magnitude(); + } + return border2D.contains(center); + } + + @Override + @Nonnull + public Circle translate(double x, double y) { + return new Circle(center.add(x, y), radius); + } + + @Override + @Nonnull + public Circle rotate(double a) { + return new Circle(center, radius); + } + + @Override + @Nonnull + public Circle rotate(@Nonnull Vector2D center, double r) { + return new Circle(center.subtract(center).rotate(r).add(center), radius); + } + + @Nonnull + public Vector2D centroid() { + return center; + } + + public double getRadius() { + return radius; + } + + @Override + public String toString() { + return "Circle [center = " + center + ", radius = " + radius + "]"; + } + + @Override + public io.scvis.grpc.geometry.Circle associated() { + return io.scvis.grpc.geometry.Circle.newBuilder().setCenter(Corresponding.transform(center)) + .setRadius(radius).build(); + } + } +} diff --git a/src/main/java/io/scvis/geometry/Vector2D.java b/src/main/java/io/scvis/geometry/Vector2D.java new file mode 100644 index 0000000..7e71207 --- /dev/null +++ b/src/main/java/io/scvis/geometry/Vector2D.java @@ -0,0 +1,143 @@ +package io.scvis.geometry; + +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import io.scvis.proto.Corresponding; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public class Vector2D implements Corresponding { + public static final @Nonnull Vector2D ZERO = new Vector2D(0.0, 0.0); + + /** + * The x coordinate of the vector.} + */ + @JsonProperty("x") + private final double x; + + /** + * The y coordinate of the vector.} + */ + @JsonProperty("y") + private final double y; + + @JsonCreator + public Vector2D(@JsonProperty("x") double x, @JsonProperty("y") double y) { + this.x = x; + this.y = y; + } + + @Nonnull + public Vector2D add(@Nonnull Vector2D v) { + return add(v.getX(), v.getY()); + } + + @Nonnull + public Vector2D add(double x, double y) { + return new Vector2D(this.x + x, this.y + y); + } + + @Nonnull + public Vector2D subtract(@Nonnull Vector2D v) { + return subtract(v.getX(), v.getY()); + } + + @Nonnull + public Vector2D subtract(double x, double y) { + return new Vector2D(this.x - x, this.y - y); + } + + @Nonnull + public Vector2D multiply(double s) { + return new Vector2D(x * s, y * s); + } + + public double dotProduct(@Nonnull Vector2D v) { + return dotProduct(v.x, v.y); + } + + public double dotProduct(double x, double y) { + return this.x * x + this.y * y; + } + + public double distance(@Nonnull Vector2D v) { + return distance(v.x, v.y); + } + + public double distance(double x, double y) { + double dx = this.x - x; + double dy = this.x - y; + return Math.sqrt(dx * dx + dy * dy); + } + + @Nonnull + public Vector2D normalize() { + double mag = magnitude(); + if (mag == 0.0) { + return ZERO; + } + return new Vector2D(x / mag, y / mag); + } + + @Nonnull + public Vector2D midpoint(@Nonnull Vector2D v) { + return midpoint(v.x, v.y); + } + + @Nonnull + public Vector2D midpoint(double x, double y) { + return new Vector2D(x + (this.x - x) / 2.0, y + (this.y - y) / 2.0); + } + + public double angle(@Nonnull Vector2D v) { + return angle(v.getX(), v.getY()); + } + + public double angle(double x, double y) { + return Math.atan2(this.y - y, this.x - x); + } + + @Nonnull + public Vector2D rotate(double a) { + return new Vector2D(Math.cos(a) * x - Math.sin(a) * y, Math.sin(a) * x + Math.cos(a) * y); + } + + public double magnitude() { + return Math.sqrt(x * x + y * y); + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector2D)) + return false; + if (obj == this) + return true; + Vector2D vec = (Vector2D) obj; + return x == vec.x && y == vec.y; + } + + @Override + public String toString() { + return "Vector [x = " + x + ", y = " + y + "]"; + } + + @Override + public io.scvis.grpc.geometry.Vector2D associated() { + return io.scvis.grpc.geometry.Vector2D.newBuilder().setX(x).setY(y).build(); + } +} \ No newline at end of file diff --git a/src/main/java/io/scvis/geometry/Vector3D.java b/src/main/java/io/scvis/geometry/Vector3D.java new file mode 100644 index 0000000..addfa5f --- /dev/null +++ b/src/main/java/io/scvis/geometry/Vector3D.java @@ -0,0 +1,127 @@ +package io.scvis.geometry; + +import javax.annotation.Nonnull; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonSerialize +@JsonDeserialize +public class Vector3D { + public static final @Nonnull Vector3D ZERO = new Vector3D(0.0, 0.0, 0.0); + + /** + * The x coordinate of the vector.} + */ + @JsonProperty("x") + private final double x; + + /** + * The y coordinate of the vector.} + */ + @JsonProperty("y") + private final double y; + + /** + * The z coordinate of the vector.} + */ + @JsonProperty("z") + private final double z; + + @JsonCreator + public Vector3D(@JsonProperty("x") double x, @JsonProperty("y") double y, @JsonProperty("z") double z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Nonnull + public Vector3D add(@Nonnull Vector3D v) { + return add(v.getX(), v.getY(), v.getZ()); + } + + @Nonnull + public Vector3D add(double x, double y, double z) { + return new Vector3D(this.x + x, this.y + y, this.z + z); + } + + @Nonnull + public Vector3D subtract(@Nonnull Vector3D v) { + return subtract(v.getX(), v.getY(), v.getZ()); + } + + @Nonnull + public Vector3D subtract(double x, double y, double z) { + return new Vector3D(this.x - x, this.y - y, this.z - z); + } + + @Nonnull + public Vector3D multiply(double s) { + return new Vector3D(x * s, y * s, z * s); + } + + public double distance(@Nonnull Vector3D v) { + return distance(v.x, v.y, v.z); + } + + public double distance(double x, double y, double z) { + double dx = this.x - x; + double dy = this.x - y; + double dz = this.z - z; + return Math.sqrt(Math.sqrt(dx * dx + dy * dy) + dz * dz); + } + + @Nonnull + public Vector3D normalize() { + double mag = magnitude(); + if (mag == 0.0) { + return ZERO; + } + return new Vector3D(x / mag, y / mag, z / mag); + } + + @Nonnull + public Vector3D midpoint(@Nonnull Vector3D v) { + return midpoint(v.x, v.y, v.z); + } + + @Nonnull + public Vector3D midpoint(double x, double y, double z) { + return new Vector3D(x + (this.x - x) / 2.0, y + (this.y - y) / 2.0, z + (this.z - z) / 2); + } + + public double magnitude() { + return Math.sqrt(Math.sqrt(x * x + y * y) + z * z); + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + public double getZ() { + return z; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector2D)) + return false; + if (obj == this) + return true; + Vector3D vec = (Vector3D) obj; + return x == vec.x && y == vec.y && z == vec.z; + } + + @Override + public String toString() { + return "Vector [x = " + x + ", y = " + y + ", z = " + z + "]"; + } +} diff --git a/src/main/java/io/scvis/observable/ChangeListener.java b/src/main/java/io/scvis/observable/ChangeListener.java new file mode 100644 index 0000000..c633196 --- /dev/null +++ b/src/main/java/io/scvis/observable/ChangeListener.java @@ -0,0 +1,52 @@ +package io.scvis.observable; + +import java.util.EventListener; +import java.util.EventObject; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +@FunctionalInterface +public interface ChangeListener extends EventListener { + + void changed(@Nonnull ChangeEvent event); + + class ChangeEvent extends EventObject { + + private static final long serialVersionUID = -3032299925044664903L; + + @Nonnull + private final Property property; + @Nullable + private final T o; + @Nullable + private final T n; + + public ChangeEvent(@Nonnull Property property, @Nullable T o, @Nullable T n) { + super(property); + this.property = property; + this.o = o; + this.n = n; + } + + @Nonnull + public Property getProperty() { + return property; + } + + @Nullable + public T getOld() { + return o; + } + + @Nullable + public T getNew() { + return n; + } + + @Override + public String toString() { + return property + " changed from " + o + " to " + n; + } + } +} diff --git a/src/main/java/io/scvis/observable/EventType.java b/src/main/java/io/scvis/observable/EventType.java new file mode 100644 index 0000000..3315d9a --- /dev/null +++ b/src/main/java/io/scvis/observable/EventType.java @@ -0,0 +1,15 @@ +package io.scvis.observable; + +import java.util.EventObject; + +public class EventType { + private final String name; + + public EventType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/io/scvis/observable/InvalidationListener.java b/src/main/java/io/scvis/observable/InvalidationListener.java new file mode 100644 index 0000000..373e4b9 --- /dev/null +++ b/src/main/java/io/scvis/observable/InvalidationListener.java @@ -0,0 +1,35 @@ +package io.scvis.observable; + +import java.util.EventListener; +import java.util.EventObject; + +import javax.annotation.Nonnull; + +@FunctionalInterface +public interface InvalidationListener extends EventListener { + + void invalidated(@Nonnull InvalidationEvent event); + + static class InvalidationEvent extends EventObject { + + private static final long serialVersionUID = -2374322950935754101L; + + @Nonnull + private final Observable observable; + + public InvalidationEvent(@Nonnull Observable observable) { + super(observable); + this.observable = observable; + } + + @Nonnull + public Observable getObservable() { + return observable; + } + + @Override + public String toString() { + return "invalidated " + observable; + } + } +} diff --git a/src/main/java/io/scvis/observable/Objective.java b/src/main/java/io/scvis/observable/Objective.java new file mode 100644 index 0000000..dbd0618 --- /dev/null +++ b/src/main/java/io/scvis/observable/Objective.java @@ -0,0 +1,51 @@ +package io.scvis.observable; + +public class Objective { + private String title; + private String description; + private float delayVisible; + private boolean optional; + private boolean completed; + + public Objective(String title, String description) { + this.title = title; + this.description = description; + } + + public void start() { + + } + + public void update(String description, String counter, String notification) { + + } + + public void complete(String description, String counter, String notification) { + completed = true; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public float getDelayVisible() { + return delayVisible; + } + + public boolean isOptional() { + return optional; + } + + public boolean isCompleted() { + return completed; + } + + public boolean isBlocking() { + return !(optional || completed); + } + +} diff --git a/src/main/java/io/scvis/observable/ObjectiveManager.java b/src/main/java/io/scvis/observable/ObjectiveManager.java new file mode 100644 index 0000000..7affecd --- /dev/null +++ b/src/main/java/io/scvis/observable/ObjectiveManager.java @@ -0,0 +1,29 @@ +package io.scvis.observable; + +import java.util.ArrayList; +import java.util.List; + +public class ObjectiveManager { + private final List objectives = new ArrayList<>(); + + private boolean completed = false; + + public void registerObjective(Objective objective) { + objectives.add(objective); + } + + public void update() { + if (objectives.size() == 0 || completed) + return; + for (int i = 0; i < objectives.size(); i++) { + if (objectives.get(i).isBlocking()) { + return; + } + } + completed = true; + } + + public boolean isCompleted() { + return completed; + } +} diff --git a/src/main/java/io/scvis/observable/Observable.java b/src/main/java/io/scvis/observable/Observable.java new file mode 100644 index 0000000..be244e5 --- /dev/null +++ b/src/main/java/io/scvis/observable/Observable.java @@ -0,0 +1,8 @@ +package io.scvis.observable; + +public interface Observable { + + void addInvalidationListener(InvalidationListener listener); + + void removeInvalidationListener(InvalidationListener listener); +} diff --git a/src/main/java/io/scvis/observable/Property.java b/src/main/java/io/scvis/observable/Property.java new file mode 100644 index 0000000..b203201 --- /dev/null +++ b/src/main/java/io/scvis/observable/Property.java @@ -0,0 +1,96 @@ +package io.scvis.observable; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.scvis.observable.ChangeListener.ChangeEvent; +import io.scvis.observable.InvalidationListener.InvalidationEvent; + +public class Property implements Observable { + + private static final Logger logger = LoggerFactory.getLogger(Property.class); + + @Nullable + private T value; + + public Property(@Nullable T value) { + this.value = value; + } + + @CheckForNull + private Set> invalidationListeners; + + protected void fireInvalidationEvent(@Nonnull InvalidationEvent event) { + logger.debug(event.toString()); + Iterator> iterator = getInvalidationListeners().iterator(); + while (iterator.hasNext()) + iterator.next().invalidated(event); + } + + @Override + public void addInvalidationListener(@Nonnull InvalidationListener listener) { + getInvalidationListeners().add(listener); + } + + @Override + public void removeInvalidationListener(@Nonnull InvalidationListener listener) { + getInvalidationListeners().remove(listener); + } + + @Nonnull + private Set> getInvalidationListeners() { + final Set> listeners = invalidationListeners; + if (listeners == null) { + return invalidationListeners = new HashSet<>(); + } + return listeners; + } + + @CheckForNull + private Set> changeListeners; + + protected void fireChangeEvent(@Nonnull ChangeEvent event) { + logger.debug(event.toString()); + Iterator> iterator = getChangeListeners().iterator(); + while (iterator.hasNext()) + iterator.next().changed(event); + } + + public void addChangeListener(@Nonnull ChangeListener listener) { + getChangeListeners().add(listener); + } + + public void removeChangeListener(@Nonnull ChangeListener listener) { + getChangeListeners().remove(listener); + } + + @Nonnull + private Set> getChangeListeners() { + final Set> listeners = changeListeners; + if (listeners == null) { + return changeListeners = new HashSet<>(); + } + return listeners; + } + + @Nullable + public T get() { + return value; + } + + public void set(@Nullable T value) { + if (get() != value) { + fireChangeEvent(new ChangeEvent<>(this, this.value, value)); + this.value = value; + } + fireInvalidationEvent(new InvalidationEvent<>(this)); + } +} diff --git a/src/main/java/io/scvis/proto/AbstractExchangeHelper.java b/src/main/java/io/scvis/proto/AbstractExchangeHelper.java new file mode 100644 index 0000000..5563ee2 --- /dev/null +++ b/src/main/java/io/scvis/proto/AbstractExchangeHelper.java @@ -0,0 +1,30 @@ +package io.scvis.proto; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import io.scvis.proto.ExchangeHelper.DispatchHelper; + +public abstract class AbstractExchangeHelper implements DispatchHelper, R> { + private final Map, Collection>> container = new HashMap<>(); + + @Override + public abstract R associated(); + + @Override + public void clean() { + for (Collection> collection : container.values()) { + collection.clear(); + } + } + + @Override + public void push(Collection> collection, Corresponding element) { + collection.add(element); + } + + public Map, Collection>> getContainer() { + return container; + } +} diff --git a/src/main/java/io/scvis/proto/AbstractStoreHelper.java b/src/main/java/io/scvis/proto/AbstractStoreHelper.java new file mode 100644 index 0000000..6707ae2 --- /dev/null +++ b/src/main/java/io/scvis/proto/AbstractStoreHelper.java @@ -0,0 +1,41 @@ +package io.scvis.proto; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import io.scvis.proto.ExchangeHelper.StoreHelper; + +/** + * @author karlz + */ +public abstract class AbstractStoreHelper implements StoreHelper, R> { + private final Map>> creators = new HashMap<>(); + private final Map>> container = new HashMap<>(); + + @Override + public abstract void update(R reference); + + @Override + public Map>> getContainer() { + return container; + } + + @Override + public Map>> getCreators() { + return creators; + } + + @Override + public Reference save(Map> map, String type, String id) { + Reference reference = map.get(id); + if ((reference = map.get(id)) == null) { + Reference newValue; + if ((newValue = getCreators().get(type).get()) != null) { + map.put(id, newValue); + return newValue; + } + } + return reference; + } +} diff --git a/src/main/java/io/scvis/proto/Corresponding.java b/src/main/java/io/scvis/proto/Corresponding.java new file mode 100644 index 0000000..d66864f --- /dev/null +++ b/src/main/java/io/scvis/proto/Corresponding.java @@ -0,0 +1,21 @@ +package io.scvis.proto; + +import java.util.Collection; + +import com.google.protobuf.Message; + +public interface Corresponding { + T associated(); + + public static interface ExtendableCorresponding extends Corresponding { + + } + + public static T transform(Corresponding corresponding) { + return corresponding.associated(); + } + + public static Collection transform(Collection> corresponding) { + return Mapper.create((Corresponding c) -> c.associated()).map(corresponding); + } +} diff --git a/src/main/java/io/scvis/proto/ExchangeHelper.java b/src/main/java/io/scvis/proto/ExchangeHelper.java new file mode 100644 index 0000000..58775da --- /dev/null +++ b/src/main/java/io/scvis/proto/ExchangeHelper.java @@ -0,0 +1,47 @@ +package io.scvis.proto; + +import java.util.Collection; +import java.util.Map; +import java.util.function.Supplier; + +public interface ExchangeHelper { + + public static interface DispatchHelper extends ExchangeHelper, Corresponding { + void clean(); + + default void push(Collection collection, E element) { + collection.add(element); + } + + default C dispatch() { + try { + return associated(); + } finally { + clean(); + } + } + } + + public static interface StoreHelper extends ExchangeHelper, Reference { + Map> getContainer(); + + Map> getCreators(); + + default E save(Map map, String type, String id) { + E reference = map.get(id); + if ((reference = map.get(id)) == null) { + E newValue; + if ((newValue = getCreators().get(type).get()) != null) { + map.put(id, newValue); + return newValue; + } + } + return reference; + } + + default void store(R reference) { + update(reference); + } + } + +} diff --git a/src/main/java/io/scvis/proto/Identifiable.java b/src/main/java/io/scvis/proto/Identifiable.java new file mode 100644 index 0000000..311ed54 --- /dev/null +++ b/src/main/java/io/scvis/proto/Identifiable.java @@ -0,0 +1,23 @@ +package io.scvis.proto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.protobuf.Message; + +import io.scvis.proto.Corresponding.ExtendableCorresponding; + +public interface Identifiable extends ExtendableCorresponding { + @JsonIgnore + default String getType() { + return getClass().getSimpleName(); + } + + @JsonIgnore + default String getId() { + return Integer.toHexString(hashCode()); + } + + @Override + default Message associated() { + return io.scvis.grpc.proto.Identifiable.newBuilder().setId(getId()).setType(getType()).build(); + } +} diff --git a/src/main/java/io/scvis/proto/Mapper.java b/src/main/java/io/scvis/proto/Mapper.java new file mode 100644 index 0000000..1a15103 --- /dev/null +++ b/src/main/java/io/scvis/proto/Mapper.java @@ -0,0 +1,26 @@ +package io.scvis.proto; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public interface Mapper extends Function { + public static Mapper create(Mapper mapper) { + return mapper; + } + + default List map(List list) { + return list.stream().map(this).collect(Collectors.toList()); + } + + default Set map(Set set) { + return set.stream().map(this).collect(Collectors.toSet()); + } + + default Collection map(Collection collection) { + return collection.stream().map(this).collect(Collectors.toCollection(() -> new ArrayList<>())); + } +} diff --git a/src/main/java/io/scvis/proto/Mirror.java b/src/main/java/io/scvis/proto/Mirror.java new file mode 100644 index 0000000..a657a5b --- /dev/null +++ b/src/main/java/io/scvis/proto/Mirror.java @@ -0,0 +1,33 @@ +package io.scvis.proto; + +public abstract class Mirror implements Reference { + + private R reflection; + + public Mirror(S source, R reflection) { + this.reflection = reflection; + } + + public Mirror() { + + } + + public R getReflection() { + return reflection; + } + + public void setReflection(R reflection) { + this.reflection = reflection; + } + + private S source; + + public void setSource(S source) { + this.source = source; + } + + public S getSource() { + return source; + } + +} diff --git a/src/main/java/io/scvis/proto/Reference.java b/src/main/java/io/scvis/proto/Reference.java new file mode 100644 index 0000000..7f5403c --- /dev/null +++ b/src/main/java/io/scvis/proto/Reference.java @@ -0,0 +1,5 @@ +package io.scvis.proto; + +public interface Reference { + void update(T reference); +} diff --git a/src/main/proto/io/scvis/game/hosting.proto b/src/main/proto/io/scvis/game/hosting.proto new file mode 100644 index 0000000..df2882f --- /dev/null +++ b/src/main/proto/io/scvis/game/hosting.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.game"; +option java_outer_classname = "HostingProto"; +service Hosting { + rpc List (ListRequest) returns (ListResponse); + rpc Host (HostRequest) returns (HostResponse); + rpc Join (JoinRequest) returns (JoinResponse); + rpc Ping (PingRequest) returns (PingResponse); +} + +message GameDescription { + string id = 1; + string name = 2; + string map = 3; + int32 current_players = 4; + int32 max_players = 5; + bool started = 6; + bool running = 7; + string address = 8; + int64 port = 9; +} + +message ListRequest { +} + +message ListResponse { + repeated GameDescription descriptions = 1; +} + +message HostRequest { + GameDescription description = 1; +} + +message HostResponse { + string token = 1; +} + +message JoinRequest { + map < string, string > details = 2; +} + +message JoinResponse { + string token = 1; + string player_id = 2; +} + +message PingRequest { +} + +message PingResponse { + sint64 ping = 1; +} \ No newline at end of file diff --git a/src/main/proto/io/scvis/geometry/kinetic2d.proto b/src/main/proto/io/scvis/geometry/kinetic2d.proto new file mode 100644 index 0000000..2918d4d --- /dev/null +++ b/src/main/proto/io/scvis/geometry/kinetic2d.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +import "io/scvis/geometry/layout2d.proto"; +import "io/scvis/geometry/vector2d.proto"; +import "io/scvis/proto/identifiable.proto"; +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.geometry"; +message Kinetic2D { + Layout2D layout = 1; + Identifiable identifiable = 2; + Vector2D acceleration = 3; + Vector2D velocity = 4; +} \ No newline at end of file diff --git a/src/main/proto/io/scvis/geometry/layout2d.proto b/src/main/proto/io/scvis/geometry/layout2d.proto new file mode 100644 index 0000000..2893226 --- /dev/null +++ b/src/main/proto/io/scvis/geometry/layout2d.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +import "io/scvis/geometry/vector2d.proto"; +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.geometry"; +message Layout2D { + Vector2D position = 1; + double rotation = 2; +} \ No newline at end of file diff --git a/src/main/proto/io/scvis/geometry/shape.proto b/src/main/proto/io/scvis/geometry/shape.proto new file mode 100644 index 0000000..e89349f --- /dev/null +++ b/src/main/proto/io/scvis/geometry/shape.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +import "io/scvis/geometry/vector2d.proto"; +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.geometry"; +message Polygon { + repeated Vector2D points = 1; + double minX = 2; + double minY = 3; + double maxX = 4; + double maxY = 5; +} + +message Circle { + Vector2D center = 1; + double radius = 2; +} + diff --git a/src/main/proto/io/scvis/geometry/vector2d.proto b/src/main/proto/io/scvis/geometry/vector2d.proto new file mode 100644 index 0000000..c8406fb --- /dev/null +++ b/src/main/proto/io/scvis/geometry/vector2d.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.geometry"; +message Vector2D { + double x = 1; + double y = 2; +} \ No newline at end of file diff --git a/src/main/proto/io/scvis/geometry/vector3d.proto b/src/main/proto/io/scvis/geometry/vector3d.proto new file mode 100644 index 0000000..4cb197c --- /dev/null +++ b/src/main/proto/io/scvis/geometry/vector3d.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.geometry"; +message Vector3D { + double x = 1; + double y = 2; + double z = 3; +} \ No newline at end of file diff --git a/src/main/proto/io/scvis/proto/identifiable.proto b/src/main/proto/io/scvis/proto/identifiable.proto new file mode 100644 index 0000000..65211e8 --- /dev/null +++ b/src/main/proto/io/scvis/proto/identifiable.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option optimize_for = SPEED; +option java_package = "io.scvis.grpc.proto"; +message Identifiable { + string id = 1; + string type = 2; +} \ No newline at end of file diff --git a/src/test/java/io/scvis/TestSerialisation.java b/src/test/java/io/scvis/TestSerialisation.java new file mode 100644 index 0000000..6990c74 --- /dev/null +++ b/src/test/java/io/scvis/TestSerialisation.java @@ -0,0 +1,91 @@ +package io.scvis; + +import java.io.IOException; +import java.lang.reflect.Type; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.exc.StreamWriteException; +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; + +import io.scvis.geometry.Border2D; +import io.scvis.geometry.Kinetic2D; +import io.scvis.geometry.Shape.Circle; +import io.scvis.geometry.Vector2D; + +public class TestSerialisation { + static Kinetic2D object = new Kinetic2D(new Circle(new Vector2D(5, 5), 5), Vector2D.ZERO, 0, Vector2D.ZERO, + Vector2D.ZERO) { + @Override + public void accelerate(double deltaT) { + } + + @Override + public void velocitate(double deltaT) { + } + + @Override + public void displacement(double deltaT) { + } + }; +} + +class TestJacksonJson { + + @Test + void serialisation() throws StreamWriteException, DatabindException, IOException { + ObjectMapper mapper = new ObjectMapper(); + System.out.println(mapper.writeValueAsString(TestSerialisation.object)); + } + + @Test + void deserialisation() throws JsonMappingException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + Kinetic2D kinetic2D = mapper.readValue(mapper.writeValueAsString(TestSerialisation.object), Kinetic2D.class); + System.out.println(kinetic2D.getPosition()); + } +} + +class TestJacksonXml { + + @Test + void serialisation() throws StreamWriteException, DatabindException, IOException { + ObjectMapper mapper = new XmlMapper(); + System.out.println(mapper.writeValueAsString(TestSerialisation.object)); + } + + @Test + void deserialisation() throws JsonMappingException, JsonProcessingException { + ObjectMapper mapper = new XmlMapper(); + Kinetic2D kinetic2D = mapper.readValue(mapper.writeValueAsString(TestSerialisation.object), + TestSerialisation.object.getClass()); + System.out.println(kinetic2D.getPosition()); + } +} + +class TestGson { + + @Test + void serialisation() { + Gson gson = new Gson(); + System.out.println(gson.toJson(TestSerialisation.object)); + } + + @Test + void deserialisation() { + Gson gson = new GsonBuilder().registerTypeAdapter(Border2D.class, new InstanceCreator() { + @Override + public Border2D createInstance(Type type) { + return new Circle(new Vector2D(5, 5), 5); + } + }).create(); + System.out.println(gson.fromJson(gson.toJson(TestSerialisation.object), Kinetic2D.class).getBorderInLocal()); + } +} diff --git a/src/test/java/io/scvis/TestVector.java b/src/test/java/io/scvis/TestVector.java new file mode 100644 index 0000000..a1e4dfb --- /dev/null +++ b/src/test/java/io/scvis/TestVector.java @@ -0,0 +1,25 @@ +package io.scvis; + +import java.util.stream.Stream; + +import javax.annotation.Nonnull; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import io.scvis.geometry.Vector2D; + +public class TestVector { + + @ParameterizedTest + @MethodSource("vectors") + void add(@Nonnull Vector2D vector2D) { + System.out.println(new Vector2D(100, 100).add(vector2D)); + } + + static Stream vectors() { + return Stream.of(Arguments.of(new Vector2D(100, 200)), Arguments.of(new Vector2D(400, 200)), + Arguments.of(new Vector2D(0, 0))); + } +}