From 82dfacd2840b182c630d642788920c542756a687 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 31 Dec 2022 17:12:24 +0100 Subject: [PATCH 001/125] Replaced busy-waiting in Timing class with waitTillFinished() --- .../java/fr/radi3nt/tasks/tasks/ManagerTask.java | 1 + .../fr/radi3nt/tasks/tasks/TemplateManagerTask.java | 10 ++++++++++ .../src/main/java/fr/radi3nt/timing/Timing.java | 4 ++-- .../src/main/java/fr/radi3nt/timing/TimingUtil.java | 12 +++++------- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java index c11466d..9b1e5f2 100644 --- a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java +++ b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java @@ -9,4 +9,5 @@ public interface ManagerTask { long getId(); + void waitTillFinished() throws InterruptedException; } diff --git a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java index 61a4a24..c2c3ba6 100644 --- a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java +++ b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java @@ -21,6 +21,16 @@ public void run() { started = true; run_(); finished = true; + synchronized (this) { + this.notifyAll(); + } + } + + @Override + public void waitTillFinished() throws InterruptedException { + synchronized (this) { + this.wait(); + } } protected abstract void run_(); diff --git a/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java b/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java index 6253e8a..969bd67 100644 --- a/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java +++ b/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java @@ -37,9 +37,9 @@ public static Timing from(int amount, TimeConvention... time) { } public void waitUtilExpired() { - while (!isExpired()) { + synchronized (this) { try { - Thread.sleep(remainingTime()); + this.wait(remainingTime()); } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java b/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java index f9b2124..0580ca5 100644 --- a/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java +++ b/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java @@ -4,13 +4,11 @@ public class TimingUtil { - public static void waitUntilTaskFinished(ManagerTask GLTask) { - while (!GLTask.isFinished()) { - try { - Thread.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } + public static void waitUntilTaskFinished(ManagerTask gLTask) { + try { + gLTask.waitTillFinished(); + } catch (InterruptedException e) { + e.printStackTrace(); } } From 7c23a92abb6d58aeb42445da97f1c8d00b30a9b3 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 31 Dec 2022 17:13:03 +0100 Subject: [PATCH 002/125] Fixed wrong packages --- .../src/main/java/fr/radi3nt/noise/SimpleNoise3D.java | 5 +---- .../src/main/java/fr/radi3nt/noise/TerrainHeight2D.java | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java index 503ee4b..34daefb 100644 --- a/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java @@ -1,7 +1,4 @@ -package fr.radi3nt.noise.noise; - -import fr.radi3nt.noise.Noise3D; -import fr.radi3nt.noise.SimplexNoise; +package fr.radi3nt.noise; public class SimpleNoise3D implements Noise3D { diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java index 2bd34fc..5c84746 100644 --- a/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java @@ -1,7 +1,4 @@ -package fr.radi3nt.noise.noise; - -import fr.radi3nt.noise.Noise3D; -import fr.radi3nt.noise.SimplexNoise; +package fr.radi3nt.noise; public class TerrainHeight2D implements Noise3D { From 4e98b8d36f2ea9e1b22ea69672e48d617ed4b90a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 31 Dec 2022 17:14:47 +0100 Subject: [PATCH 003/125] Removed unused imports in ColorData class --- .../main/java/fr/radi3nt/maths/colour/colors/ColorData.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java index 1da21d1..42eb182 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java @@ -1,8 +1,5 @@ package fr.radi3nt.maths.colour.colors; -import fr.radi3nt.maths.colour.colors.Colour; -import fr.radi3nt.maths.colour.colors.Colour; - public class ColorData { private final Colour colour; From b00dd8a9133532553ecf2d39ac9fd83c19d859b0 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 31 Dec 2022 17:15:36 +0100 Subject: [PATCH 004/125] Improved on WaitingVector3fPool (no more busy-waiting) --- .../main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java index 32d9811..18a9b95 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java @@ -9,6 +9,7 @@ public WaitingVector3fPool(int baseObjectAmount) { for (int i = 0; i < baseObjectAmount; i++) { queue.add(create()); } + queue.notifyAll(); } public Vector3f borrow() { @@ -16,9 +17,9 @@ public Vector3f borrow() { if (object == null) while ((object = queue.poll()) == null) { try { - Thread.sleep(1); + queue.wait(); } catch (InterruptedException e) { - throw new RuntimeException(e); + e.printStackTrace(); } } From fbab075dc1e4685db065ca7e51c4fc8af17477dc Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 31 Dec 2022 17:16:26 +0100 Subject: [PATCH 005/125] Using lambda in Easing class --- .../main/java/fr/radi3nt/maths/Easing.java | 266 ++++++------------ 1 file changed, 89 insertions(+), 177 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/Easing.java b/MathsHelper/src/main/java/fr/radi3nt/maths/Easing.java index 8f85e0c..e9d4305 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/Easing.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/Easing.java @@ -34,227 +34,150 @@ public interface Easing { /** * Simple linear tweening - no easing. */ - Easing LINEAR = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*t/d + b; - } - }; + Easing LINEAR = (t, b, c, d) -> c * t / d + b; ///////////// QUADRATIC EASING: t^2 /////////////////// - - /** + + /** * Quadratic easing in - accelerating from zero velocity. */ - Easing QUAD_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*(t/=d)*t + b; - } - }; + Easing QUAD_IN = (t, b, c, d) -> c * (t /= d) * t + b; - /** + /** * Quadratic easing out - decelerating to zero velocity. */ - Easing QUAD_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return -c *(t/=d)*(t-2) + b; - } - }; - + Easing QUAD_OUT = (t, b, c, d) -> -c * (t /= d) * (t - 2) + b; + /** * Quadratic easing in/out - acceleration until halfway, then deceleration */ - Easing QUAD_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - } + Easing QUAD_IN_OUT = (t, b, c, d) -> { + if ((t /= d / 2) < 1) return c / 2 * t * t + b; + return -c / 2 * ((--t) * (t - 2) - 1) + b; }; - - + + ///////////// CUBIC EASING: t^3 /////////////////////// - /** + /** * Cubic easing in - accelerating from zero velocity. */ - Easing CUBIC_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*(t/=d)*t*t + b; - } - }; - + Easing CUBIC_IN = (t, b, c, d) -> c * (t /= d) * t * t + b; + /** * Cubic easing out - decelerating to zero velocity. */ - Easing CUBIC_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*((t=t/d-1)*t*t + 1) + b; - } - }; - - /** + Easing CUBIC_OUT = (t, b, c, d) -> c * ((t = t / d - 1) * t * t + 1) + b; + + /** * Cubic easing in/out - acceleration until halfway, then deceleration. */ - Easing CUBIC_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d/2) < 1) return c/2*t*t*t + b; - return c/2*((t-=2)*t*t + 2) + b; - } + Easing CUBIC_IN_OUT = (t, b, c, d) -> { + if ((t /= d / 2) < 1) return c / 2 * t * t * t + b; + return c / 2 * ((t -= 2) * t * t + 2) + b; }; - + ///////////// QUARTIC EASING: t^4 ///////////////////// /** * Quartic easing in - accelerating from zero velocity. */ - Easing QUARTIC_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*(t/=d)*t*t*t + b; - } - }; - - /** + Easing QUARTIC_IN = (t, b, c, d) -> c * (t /= d) * t * t * t + b; + + /** * Quartic easing out - decelerating to zero velocity. */ - Easing QUARTIC_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return -c * ((t=t/d-1)*t*t*t - 1) + b; - } - }; + Easing QUARTIC_OUT = (t, b, c, d) -> -c * ((t = t / d - 1) * t * t * t - 1) + b; - /** + /** * Quartic easing in/out - acceleration until halfway, then deceleration. */ - Easing QUARTIC_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t + b; - return -c/2 * ((t-=2)*t*t*t - 2) + b; - } + Easing QUARTIC_IN_OUT = (t, b, c, d) -> { + if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b; + return -c / 2 * ((t -= 2) * t * t * t - 2) + b; }; - + ///////////// QUINTIC EASING: t^5 //////////////////// - /** + /** * Quintic easing in - accelerating from zero velocity. */ - Easing QUINTIC_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*(t/=d)*t*t*t*t + b; - } - }; + Easing QUINTIC_IN = (t, b, c, d) -> c * (t /= d) * t * t * t * t + b; - /** + /** * Quintic easing out - decelerating to zero velocity. */ - Easing QUINTIC_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return c*((t=t/d-1)*t*t*t*t + 1) + b; - } - }; - - /** + Easing QUINTIC_OUT = (t, b, c, d) -> c * ((t = t / d - 1) * t * t * t * t + 1) + b; + + /** * Quintic easing in/out - acceleration until halfway, then deceleration. */ - Easing QUINTIC_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; - return c/2*((t-=2)*t*t*t*t + 2) + b; - } + Easing QUINTIC_IN_OUT = (t, b, c, d) -> { + if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b; + return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; }; - - - + + ///////////// SINUSOIDAL EASING: sin(t) /////////////// - /** + /** * Sinusoidal easing in - accelerating from zero velocity. */ - Easing SINE_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return -c * (float)FastTrig.cos(t/d * (Math.PI/2)) + c + b; - } - }; + Easing SINE_IN = (t, b, c, d) -> -c * (float) FastTrig.cos(t / d * (Math.PI / 2)) + c + b; - /** + /** * Sinusoidal easing out - decelerating to zero velocity. */ - Easing SINE_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return c * (float)FastTrig.sin(t/d * (Math.PI/2)) + b; - } - }; - - /** + Easing SINE_OUT = (t, b, c, d) -> c * (float) FastTrig.sin(t / d * (Math.PI / 2)) + b; + + /** * Sinusoidal easing in/out - accelerating until halfway, then decelerating. */ - Easing SINE_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return -c/2 * ((float)FastTrig.cos(Math.PI*t/d) - 1) + b; - } - }; - - ///////////// EXPONENTIAL EASING: 2^t ///////////////// + Easing SINE_IN_OUT = (t, b, c, d) -> -c / 2 * ((float) FastTrig.cos(Math.PI * t / d) - 1) + b; + + ///////////// EXPONENTIAL EASING: 2^t ///////////////// - /** + /** * Exponential easing in - accelerating from zero velocity. */ - Easing EXPO_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return (t==0) ? b : c * (float)Math.pow(2, 10 * (t/d - 1)) + b; - } - }; + Easing EXPO_IN = (t, b, c, d) -> (t == 0) ? b : c * (float) Math.pow(2, 10 * (t / d - 1)) + b; - /** + /** * Exponential easing out - decelerating to zero velocity. */ - Easing EXPO_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return (t==d) ? b+c : c * (-(float)Math.pow(2, -10 * t/d) + 1) + b; - } - }; - - /** + Easing EXPO_OUT = (t, b, c, d) -> (t == d) ? b + c : c * (-(float) Math.pow(2, -10 * t / d) + 1) + b; + + /** * Exponential easing in/out - accelerating until halfway, then decelerating. */ - Easing EXPO_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if (t==0) return b; - if (t==d) return b+c; - if ((t/=d/2) < 1) return c/2 * (float)Math.pow(2, 10 * (t - 1)) + b; - return c/2 * (-(float)Math.pow(2, -10 * --t) + 2) + b; - } + Easing EXPO_IN_OUT = (t, b, c, d) -> { + if (t == 0) return b; + if (t == d) return b + c; + if ((t /= d / 2) < 1) return c / 2 * (float) Math.pow(2, 10 * (t - 1)) + b; + return c / 2 * (-(float) Math.pow(2, -10 * --t) + 2) + b; }; - - + + /////////// CIRCULAR EASING: sqrt(1-t^2) ////////////// - /** + /** * Circular easing in - accelerating from zero velocity. */ - Easing CIRC_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return -c * ((float)Math.sqrt(1 - (t/=d)*t) - 1) + b; - } - }; - - /** + Easing CIRC_IN = (t, b, c, d) -> -c * ((float) Math.sqrt(1 - (t /= d) * t) - 1) + b; + + /** * Circular easing out - decelerating to zero velocity. */ - Easing CIRC_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - return c * (float)Math.sqrt(1 - (t=t/d-1)*t) + b; - } - }; - - /** + Easing CIRC_OUT = (t, b, c, d) -> c * (float) Math.sqrt(1 - (t = t / d - 1) * t) + b; + + /** * Circular easing in/out - acceleration until halfway, then deceleration. */ - Easing CIRC_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d/2) < 1) return -c/2 * ((float)Math.sqrt(1 - t*t) - 1) + b; - return c/2 * ((float)Math.sqrt(1 - (t-=2)*t) + 1) + b; - } + Easing CIRC_IN_OUT = (t, b, c, d) -> { + if ((t /= d / 2) < 1) return -c / 2 * ((float) Math.sqrt(1 - t * t) - 1) + b; + return c / 2 * ((float) Math.sqrt(1 - (t -= 2) * t) + 1) + b; }; - + /////////// ELASTIC EASING: exponentially decaying sine wave ////////////// /** @@ -464,34 +387,23 @@ public float ease(float t, float b, float c, float d) { } /////////// BOUNCE EASING: exponentially decaying parabolic bounce ////////////// - - /** Bounce easing in. */ - Easing BOUNCE_IN = new Easing() { - public float ease(float t, float b, float c, float d) { - return c - Easing.BOUNCE_OUT.ease(d-t, 0, c, d) + b; - } - }; - /** Bounce easing out. */ - Easing BOUNCE_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if ((t/=d) < (1/2.75f)) { - return c*(7.5625f*t*t) + b; - } else if (t < (2/2.75f)) { - return c*(7.5625f*(t-=(1.5f/2.75f))*t + .75f) + b; - } else if (t < (2.5f/2.75f)) { - return c*(7.5625f*(t-=(2.25f/2.75f))*t + .9375f) + b; - } else { - return c*(7.5625f*(t-=(2.625f/2.75f))*t + .984375f) + b; - } + Easing BOUNCE_OUT = (t, b, c, d) -> { + if ((t /= d) < (1 / 2.75f)) { + return c * (7.5625f * t * t) + b; + } else if (t < (2 / 2.75f)) { + return c * (7.5625f * (t -= (1.5f / 2.75f)) * t + .75f) + b; + } else if (t < (2.5f / 2.75f)) { + return c * (7.5625f * (t -= (2.25f / 2.75f)) * t + .9375f) + b; + } else { + return c * (7.5625f * (t -= (2.625f / 2.75f)) * t + .984375f) + b; } }; - + /** Bounce easing in. */ + Easing BOUNCE_IN = (t, b, c, d) -> c - Easing.BOUNCE_OUT.ease(d - t, 0, c, d) + b; /** Bounce easing in/out. */ - Easing BOUNCE_IN_OUT = new Easing() { - public float ease(float t, float b, float c, float d) { - if (t < d/2) return Easing.BOUNCE_IN.ease(t*2, 0, c, d) * .5f + b; - return Easing.BOUNCE_OUT.ease(t*2-d, 0, c, d) * .5f + c*.5f + b; - } + Easing BOUNCE_IN_OUT = (t, b, c, d) -> { + if (t < d / 2) return Easing.BOUNCE_IN.ease(t * 2, 0, c, d) * .5f + b; + return Easing.BOUNCE_OUT.ease(t * 2 - d, 0, c, d) * .5f + c * .5f + b; }; } \ No newline at end of file From 6456ee96d52c93c141a2d6a9adc1a1b3f7d9fb8b Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 3 Jan 2023 22:34:43 +0100 Subject: [PATCH 006/125] Now throwing IO exception when querying an InputStream/OutputStream from a file --- .../main/java/fr/radi3nt/file/files/ReadableFile.java | 4 ++-- .../main/java/fr/radi3nt/file/files/WritableFile.java | 4 ++-- .../src/main/java/fr/radi3nt/file/impl/NioFile.java | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/files/ReadableFile.java b/FileHelper/src/main/java/fr/radi3nt/file/files/ReadableFile.java index 34a7cc9..53ec463 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/files/ReadableFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/files/ReadableFile.java @@ -1,10 +1,10 @@ package fr.radi3nt.file.files; -import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; public interface ReadableFile extends File { - InputStream getInputStream() throws FileNotFoundException; + InputStream getInputStream() throws IOException; } diff --git a/FileHelper/src/main/java/fr/radi3nt/file/files/WritableFile.java b/FileHelper/src/main/java/fr/radi3nt/file/files/WritableFile.java index f969a65..3e14b6c 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/files/WritableFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/files/WritableFile.java @@ -1,12 +1,12 @@ package fr.radi3nt.file.files; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; public interface WritableFile extends File { - OutputStream getOutputSteam() throws FileNotFoundException; + OutputStream getOutputSteam() throws IOException; + void create() throws IOException; void delete() throws IOException; diff --git a/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java b/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java index 5adfa1e..72a8228 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java @@ -1,7 +1,7 @@ package fr.radi3nt.file.impl; -import fr.radi3nt.file.files.CompleteFile; import fr.radi3nt.file.FileAccess; +import fr.radi3nt.file.files.CompleteFile; import java.io.*; import java.nio.file.Files; @@ -32,13 +32,13 @@ public boolean isCreated() { } @Override - public InputStream getInputStream() throws FileNotFoundException { - return new FileInputStream(path.toFile()); + public InputStream getInputStream() throws IOException { + return Files.newInputStream(path.toFile().toPath()); } @Override - public OutputStream getOutputSteam() throws FileNotFoundException { - return new FileOutputStream(path.toFile()); + public OutputStream getOutputSteam() throws IOException { + return Files.newOutputStream(path.toFile().toPath()); } @Override From c10aed64723faf4ad0fb6951a84cbf619827783f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 3 Jan 2023 22:38:23 +0100 Subject: [PATCH 007/125] Refactoring --- .../java/fr/radi3nt/file/files/CompleteFile.java | 1 - .../java/fr/radi3nt/file/impl/ResourceFile.java | 4 +--- .../src/main/java/fr/radi3nt/json/JsonArray.java | 4 ++-- .../src/main/java/fr/radi3nt/json/JsonObject.java | 8 ++++---- .../main/java/fr/radi3nt/lang/util/FileUtils_.java | 13 +++++++------ .../fr/radi3nt/loghelper/archiving/LogArchiver.java | 13 +++++++++---- .../fr/radi3nt/loghelper/archiving/LogFilter.java | 1 - .../formatters/comp/DateFormatterComponent.java | 1 - .../comp/type/TypeFormatterComponent.java | 1 - .../radi3nt/loghelper/examples/MainLogExample.java | 5 ----- .../loghelper/logs/actions/type/InfoLogAction.java | 2 -- .../logs/logs/implementations/PrintStreamLog.java | 3 +-- .../java/fr/radi3nt/maths/components/Vector2D.java | 12 ------------ 13 files changed, 24 insertions(+), 44 deletions(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/files/CompleteFile.java b/FileHelper/src/main/java/fr/radi3nt/file/files/CompleteFile.java index 1c285ca..06c490e 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/files/CompleteFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/files/CompleteFile.java @@ -3,7 +3,6 @@ import fr.radi3nt.file.FileAccess; import java.io.FileNotFoundException; -import java.io.IOException; import java.io.RandomAccessFile; public interface CompleteFile extends WritableFile, ReadableFile { diff --git a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java index e4fa5d2..22ccafb 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java @@ -2,10 +2,8 @@ import fr.radi3nt.file.files.ReadableFile; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; public class ResourceFile implements ReadableFile { @@ -24,7 +22,7 @@ public ResourceFile(String path) { public ResourceFile(String... paths) { this.path = BASE_PATH; for (final String part : paths) { - this.path = this.path + FILE_SEPARATOR + part; + this.path += FILE_SEPARATOR + part; } final String[] dirs = this.path.split(FILE_SEPARATOR); this.name = dirs[dirs.length - 1]; diff --git a/JsonHelper/src/main/java/fr/radi3nt/json/JsonArray.java b/JsonHelper/src/main/java/fr/radi3nt/json/JsonArray.java index 49807d6..ddc7c72 100644 --- a/JsonHelper/src/main/java/fr/radi3nt/json/JsonArray.java +++ b/JsonHelper/src/main/java/fr/radi3nt/json/JsonArray.java @@ -11,7 +11,7 @@ public class JsonArray extends JsonValue implements Iterable { private final List values; public JsonArray() { - this.values = new ArrayList(); + this.values = new ArrayList<>(); } public JsonArray(final JsonArray array) { @@ -25,7 +25,7 @@ private JsonArray(final JsonArray array, final boolean unmodifiable) { if (unmodifiable) { this.values = Collections.unmodifiableList(array.values); } else { - this.values = new ArrayList(array.values); + this.values = new ArrayList<>(array.values); } } diff --git a/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java b/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java index dce42a8..40a5900 100644 --- a/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java +++ b/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java @@ -14,8 +14,8 @@ public class JsonObject extends JsonValue implements Iterable private transient HashIndexTable table; public JsonObject() { - this.names = new ArrayList(); - this.values = new ArrayList(); + this.names = new ArrayList<>(); + this.values = new ArrayList<>(); this.table = new HashIndexTable(); } @@ -31,8 +31,8 @@ private JsonObject(final JsonObject object, final boolean unmodifiable) { this.names = Collections.unmodifiableList(object.names); this.values = Collections.unmodifiableList(object.values); } else { - this.names = new ArrayList(object.names); - this.values = new ArrayList(object.values); + this.names = new ArrayList<>(object.names); + this.values = new ArrayList<>(object.values); } this.table = new HashIndexTable(); this.updateHashIndex(); diff --git a/LanguageHelper/src/main/java/fr/radi3nt/lang/util/FileUtils_.java b/LanguageHelper/src/main/java/fr/radi3nt/lang/util/FileUtils_.java index 5c14005..19e1376 100644 --- a/LanguageHelper/src/main/java/fr/radi3nt/lang/util/FileUtils_.java +++ b/LanguageHelper/src/main/java/fr/radi3nt/lang/util/FileUtils_.java @@ -5,6 +5,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; @@ -37,7 +38,7 @@ public static void saveJson(final File file, final JsonObject jsonObject) { } catch (IOException e) { e.printStackTrace(); } - try (final Writer fw = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) { + try (final Writer fw = new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8)) { jsonObject.writeTo(fw, WriterConfig.PRETTY_PRINT); fw.flush(); } catch (IOException e) { @@ -54,7 +55,7 @@ public static void copy(final InputStream source, final String destination) { e.printStackTrace(); } if (source != null) { - try (final OutputStream out = new FileOutputStream(file)) { + try (final OutputStream out = Files.newOutputStream(file.toPath())) { final byte[] buf = new byte[1024]; int len; while ((len = source.read(buf)) > 0) { @@ -88,7 +89,7 @@ public static String convert(final InputStream inputStream) { public static String loadContent(final File file) { if (file.exists()) { - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8))) { final StringBuilder text = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { @@ -103,11 +104,11 @@ public static String loadContent(final File file) { } public static String loadContent(List stringList) { - String line = ""; + StringBuilder line = new StringBuilder(); for (String s : stringList) { - line+=s; + line.append(s); } - return line; + return line.toString(); } public static String loadResourceContent(final Path path) { diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogArchiver.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogArchiver.java index 23a2f69..e0cfa2e 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogArchiver.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogArchiver.java @@ -2,12 +2,17 @@ import fr.radi3nt.file.files.WritableFile; import fr.radi3nt.loghelper.archiving.formatters.LogFormatter; -import fr.radi3nt.loghelper.logs.logs.Log; import fr.radi3nt.loghelper.logs.actions.LogAction; +import fr.radi3nt.loghelper.logs.logs.Log; -import java.io.*; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; public class LogArchiver { @@ -48,7 +53,7 @@ private void writeLogs(List logs) throws IOException { outputStreamWriter.close(); } - private OutputStreamWriter getWriter() throws FileNotFoundException { + private OutputStreamWriter getWriter() throws IOException { OutputStream outputStream = writableFile.getOutputSteam(); return new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); } diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogFilter.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogFilter.java index 0680040..63c7496 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogFilter.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/LogFilter.java @@ -3,7 +3,6 @@ import fr.radi3nt.loghelper.logs.actions.LogAction; import java.util.Collection; -import java.util.Iterator; import java.util.function.Predicate; public class LogFilter { diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/DateFormatterComponent.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/DateFormatterComponent.java index 76587df..7d2f13f 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/DateFormatterComponent.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/DateFormatterComponent.java @@ -1,6 +1,5 @@ package fr.radi3nt.loghelper.archiving.formatters.comp; -import fr.radi3nt.loghelper.archiving.formatters.LogFormatter; import fr.radi3nt.loghelper.logs.actions.LogAction; import java.time.Instant; diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/type/TypeFormatterComponent.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/type/TypeFormatterComponent.java index 7bd8e62..d4fe2c2 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/type/TypeFormatterComponent.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/archiving/formatters/comp/type/TypeFormatterComponent.java @@ -1,6 +1,5 @@ package fr.radi3nt.loghelper.archiving.formatters.comp.type; -import fr.radi3nt.loghelper.archiving.formatters.LogFormatter; import fr.radi3nt.loghelper.archiving.formatters.comp.FormatComponent; import fr.radi3nt.loghelper.archiving.formatters.comp.type.handler.UnknownTypeFormatHandler; import fr.radi3nt.loghelper.logs.actions.LogAction; diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/examples/MainLogExample.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/examples/MainLogExample.java index 61a0c21..7d9640f 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/examples/MainLogExample.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/examples/MainLogExample.java @@ -9,10 +9,7 @@ import fr.radi3nt.loghelper.archiving.formatters.comp.DateFormatterComponent; import fr.radi3nt.loghelper.archiving.formatters.comp.type.TypeFormatterComponent; import fr.radi3nt.loghelper.archiving.formatters.comp.type.handler.EmptyUnknownTypeFormatHandler; -import fr.radi3nt.loghelper.logs.actions.TemplateLogAction; -import fr.radi3nt.loghelper.logs.actions.type.EnumLogType; import fr.radi3nt.loghelper.logs.actions.type.InfoLogAction; -import fr.radi3nt.loghelper.logs.actions.type.TemplateTypeLogAction; import fr.radi3nt.loghelper.logs.logs.WritableLog; import fr.radi3nt.loghelper.logs.logs.implementations.PrintStreamLog; @@ -20,8 +17,6 @@ import java.io.IOException; import java.nio.file.Paths; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collection; public class MainLogExample { diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/actions/type/InfoLogAction.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/actions/type/InfoLogAction.java index f43bbc3..8264eac 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/actions/type/InfoLogAction.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/actions/type/InfoLogAction.java @@ -1,7 +1,5 @@ package fr.radi3nt.loghelper.logs.actions.type; -import fr.radi3nt.loghelper.logs.actions.TemplateLogAction; - public class InfoLogAction extends TemplateTypeLogAction { public InfoLogAction(String log, long timeStamp) { diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/PrintStreamLog.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/PrintStreamLog.java index eca3b68..8d05831 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/PrintStreamLog.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/PrintStreamLog.java @@ -1,13 +1,12 @@ package fr.radi3nt.loghelper.logs.logs.implementations; import fr.radi3nt.loghelper.archiving.formatters.LogFormatter; -import fr.radi3nt.loghelper.logs.logs.ConsoleLog; import fr.radi3nt.loghelper.logs.actions.LogAction; +import fr.radi3nt.loghelper.logs.logs.ConsoleLog; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; import java.nio.charset.StandardCharsets; public class PrintStreamLog extends TemplateLog implements ConsoleLog { diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector2D.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector2D.java index 230596a..e426e9e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector2D.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector2D.java @@ -1,12 +1,9 @@ package fr.radi3nt.maths.components; -import java.util.LinkedHashMap; import java.util.Map; public class Vector2D implements Cloneable { - private static final long serialVersionUID = 12973187389L; - private static final double epsilon = 0.000001; protected double x; @@ -459,15 +456,6 @@ public boolean equals(Object obj) { return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && (this.getClass().equals(obj.getClass())); } - public Map serialize() { - Map result = new LinkedHashMap(); - - result.put("x", getX()); - result.put("y", getY()); - - return result; - } - /** * Get a new vector. * From ea9a058527cf1e0ca8eaeb1fe32f59a62df1283e Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 10 Jan 2023 22:49:47 +0100 Subject: [PATCH 008/125] Added and fixed methods in Matrix class --- .../advanced/matrix/ArrayMatrix4x4.java | 64 ++++++++++--------- .../components/advanced/matrix/Matrix.java | 2 + 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 07007c0..a263bdb 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -1,7 +1,6 @@ package fr.radi3nt.maths.components.advanced.matrix; import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; -import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; import fr.radi3nt.maths.components.vectors.Vector3f; @@ -65,6 +64,15 @@ public void transpose() { m[2][3] = m[3][2]; } + @Override + public void negate() { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + m[i][j] =-m[i][j]; + } + } + } + @Override public void invert() { float s0 = get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1); @@ -263,35 +271,31 @@ public void quaternionRotation(Quaternion quaternion) { @Override public void directionRotation(Vector3f direction, Vector3f up) { - Vector3f xaxis = direction.duplicate().cross(up.duplicate()); - if (xaxis.getX() == 0 && xaxis.getY() == 0 && xaxis.getZ() == 0) { - return; - } - xaxis.normalize(); - float phi = (float) Math.acos(direction.dot(up)); - - /* - float u = xaxis.getX(); - float w = xaxis.getY(); - float v = xaxis.getZ(); - - - float rcos = (float) Math.cos(phi); - float rsin = (float) Math.sin(phi); - m[0][0] = rcos + u*u*(1-rcos); - m[0][1] = w * rsin + v*u*(1-rcos); - m[0][2] = -v * rsin + w*u*(1-rcos); - m[1][0] = -w * rsin + u*v*(1-rcos); - m[1][1] = rcos + v*v*(1-rcos); - m[1][2] = u * rsin + w*v*(1-rcos); - m[2][0] = v * rsin + u*w*(1-rcos); - m[2][1] = -u * rsin + v*w*(1-rcos); - m[2][2] = rcos + w*w*(1-rcos); - - - */ - Quaternion quaternion = ComponentsQuaternion.fromAxisAndAngle(xaxis, JavaMathAngle.fromRadiant(phi)); - quaternionRotation(quaternion); + Vector3f z = direction.duplicate(); + z.normalize(); + Vector3f y = up.duplicate(); + Vector3f x = y.duplicate().cross(z); + y = z.duplicate().cross(x); + + x.normalize(); + y.normalize(); + + m[0][0] = x.getX(); + m[1][0] = x.getY(); + m[2][0] = x.getZ(); + m[3][0] = -x.dot(direction); + m[0][1] = y.getX(); + m[1][1] = y.getY(); + m[2][1] = y.getZ(); + m[3][1] = -y.dot(direction); + m[0][2] = z.getX(); + m[1][2] = z.getY(); + m[2][2] = z.getZ(); + m[3][2] = -z.dot(direction); + m[0][3] = 0; + m[1][3] = 0; + m[2][3] = 0; + m[3][3] = 1.0f; } @Override diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix.java index e33b51c..78f60fe 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix.java @@ -8,6 +8,8 @@ public interface Matrix { void transpose(); + void negate(); + void invert(); float get(int x, int y); From 4e5e1bcf1c0b40224dbdb86bffda82b1430ba7f1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 10 Jan 2023 22:50:22 +0100 Subject: [PATCH 009/125] Create orthographic projection matrix --- .../matrices/PerspectiveMatrix.java | 7 ---- .../components/matrices/ProjectionMatrix.java | 8 +++++ .../matrices/implementation/ArrayMatrix.java | 36 ++++++++++++++++--- .../implementation/MatrixCreator.java | 4 +-- 4 files changed, 41 insertions(+), 14 deletions(-) delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java deleted file mode 100644 index 8676010..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.maths.components.matrices; - -public interface PerspectiveMatrix extends Matrix { - - Matrix perspective(float fov, float aspect, float near, float far); - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java new file mode 100644 index 0000000..a59ba17 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java @@ -0,0 +1,8 @@ +package fr.radi3nt.maths.components.matrices; + +public interface ProjectionMatrix extends Matrix { + + Matrix perspective(float fov, float aspect, float near, float far); + Matrix orthographic(float right, float left, float top, float bottom, float near, float far); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java index b6bfd10..29f0683 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java @@ -1,8 +1,8 @@ package fr.radi3nt.maths.components.matrices.implementation; -import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; import fr.radi3nt.maths.components.matrices.Matrix; -import fr.radi3nt.maths.components.matrices.PerspectiveMatrix; +import fr.radi3nt.maths.components.matrices.ProjectionMatrix; import fr.radi3nt.maths.components.matrices.ViewMatrix; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector4f; @@ -12,7 +12,7 @@ import java.nio.FloatBuffer; import java.util.Arrays; -public class ArrayMatrix implements Matrix, PerspectiveMatrix, ViewMatrix { +public class ArrayMatrix implements Matrix, ProjectionMatrix, ViewMatrix { private float[][] m; @@ -25,7 +25,7 @@ public class ArrayMatrix implements Matrix, PerspectiveMatrix, ViewMatrix { identity(); } - public static Matrix from(ArrayMatrix4x4 arrayMatrix4x4) { + public static Matrix from(Matrix4x4 arrayMatrix4x4) { ArrayMatrix arrayMatrix = new ArrayMatrix(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -35,7 +35,7 @@ public static Matrix from(ArrayMatrix4x4 arrayMatrix4x4) { return arrayMatrix; } - public static Matrix fromTransposing(ArrayMatrix4x4 arrayMatrix4x4) { + public static Matrix fromTransposing(Matrix4x4 arrayMatrix4x4) { ArrayMatrix arrayMatrix = new ArrayMatrix(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -367,6 +367,32 @@ public Matrix perspective(float fov, float aspect, float near, float far) { return this; } + public Matrix orthographic(float right, float left, float top, float bottom, float near, float far) { + identity(); + + m[0][0] = 2 / (right - left); + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + + m[1][0] = 0; + m[1][1] = 2 / (top - bottom); + m[1][2] = 0; + m[1][3] = 0; + + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = -2 / (far - near); + m[2][3] = 0; + + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far - near); + m[3][3] = 1; + + return this; + } + @Override public ViewMatrix view(Vector3f position, Vector3f rotation) { //todo rotation no need to negate ? diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java index 20461a2..1f057fb 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java @@ -1,7 +1,7 @@ package fr.radi3nt.maths.components.matrices.implementation; import fr.radi3nt.maths.components.matrices.Matrix; -import fr.radi3nt.maths.components.matrices.PerspectiveMatrix; +import fr.radi3nt.maths.components.matrices.ProjectionMatrix; import fr.radi3nt.maths.components.matrices.ViewMatrix; public class MatrixCreator { @@ -10,7 +10,7 @@ public static Matrix createMatrix() { return new ArrayMatrix(); } - public static PerspectiveMatrix createProjection() { + public static ProjectionMatrix createProjection() { return new ArrayMatrix(); } From 083ccd9df7e71b0bd433f36749b035d77cdcdf35 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 10 Jan 2023 22:50:40 +0100 Subject: [PATCH 010/125] Made div in SimpleVector4f public --- .../main/java/fr/radi3nt/maths/components/vectors/Vector4f.java | 2 ++ .../components/vectors/implementations/SimpleVector4f.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index 319e986..36b9f3b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -11,6 +11,8 @@ public interface Vector4f extends Vector { float getW(); void setW(float w); + void div(float div); + void normalize(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 2f45f54..1630322 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -64,7 +64,7 @@ public void normalize() { div(length()); } - private void div(float length) { + public void div(float length) { this.setX(getX()/length); this.setY(getY()/length); this.setZ(getZ()/length); From 61d30a48c31825ae66084f40df4f31be11d804b3 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 11 Jan 2023 22:40:18 +0100 Subject: [PATCH 011/125] Fixed transpose() method --- .../advanced/matrix/ArrayMatrix4x4.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index a263bdb..ba87936 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -50,18 +50,31 @@ public void zero() { @Override public void transpose() { - m[1][0] = m[0][1]; - m[2][0] = m[0][2]; - m[3][0] = m[0][3]; - m[0][1] = m[1][0]; - m[2][1] = m[1][2]; - m[3][1] = m[1][3]; - m[0][2] = m[2][0]; - m[1][2] = m[2][1]; - m[3][2] = m[2][3]; - m[0][3] = m[3][0]; - m[1][3] = m[3][1]; - m[2][3] = m[3][2]; + float m10 = m[0][1]; + float m20 = m[0][2]; + float m30 = m[0][3]; + float m01 = m[1][0]; + float m21 = m[1][2]; + float m31 = m[1][3]; + float m02 = m[2][0]; + float m12 = m[2][1]; + float m32 = m[2][3]; + float m03 = m[3][0]; + float m13 = m[3][1]; + float m23 = m[3][2]; + + m[1][0] = m10; + m[2][0] = m20; + m[3][0] = m30; + m[0][1] = m01; + m[2][1] = m21; + m[3][1] = m31; + m[0][2] = m02; + m[1][2] = m12; + m[3][2] = m32; + m[0][3] = m03; + m[1][3] = m13; + m[2][3] = m23; } @Override From 28139f38cc937a78526f3b934b5dd33dfeb38a3f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 11 Jan 2023 22:40:56 +0100 Subject: [PATCH 012/125] Added set() for Vector4f --- .../fr/radi3nt/maths/components/vectors/Vector4f.java | 3 ++- .../vectors/implementations/SimpleVector4f.java | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index 36b9f3b..8ee29c5 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -14,5 +14,6 @@ public interface Vector4f extends Vector { void div(float div); void normalize(); - + + void set(Vector3f vector3f, int w); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 1630322..38f10c3 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -1,5 +1,6 @@ package fr.radi3nt.maths.components.vectors.implementations; +import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector4f; public class SimpleVector4f implements Vector4f { @@ -64,6 +65,14 @@ public void normalize() { div(length()); } + @Override + public void set(Vector3f vector3f, int w) { + setX(vector3f.getX()); + setY(vector3f.getY()); + setZ(vector3f.getZ()); + setW(w); + } + public void div(float length) { this.setX(getX()/length); this.setY(getY()/length); From 121c0ab3900813c0e17d94d05d66928ca5a48e08 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 11 Jan 2023 22:41:08 +0100 Subject: [PATCH 013/125] Added clamp method for integers --- MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java index d9b16f0..44d0bc1 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java @@ -16,6 +16,10 @@ public static long clamp(long value, long min, long max) { return Math.max(Math.min(value, max), min); } + public static int clamp(int value, int min, int max) { + return Math.max(Math.min(value, max), min); + } + public static double clamp(double value, double min, double max) { return Math.max(Math.min(value, max), min); } From 0bc369fdcb74cb16f55b4ba7f9b78b382a5c50be Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 21 Jan 2023 19:34:50 +0100 Subject: [PATCH 014/125] Added lerp method in Maths --- MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java index 44d0bc1..ef9ea9a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java @@ -93,4 +93,9 @@ public static byte[] intToByteArray(Collection value) { } return bytes; } + + public static float lerp(float a, float b, float f) + { + return a + f * (b - a); + } } From 4c3d044faefb86c96139a7b95226d6535b01e0b6 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 7 Feb 2023 22:33:57 +0100 Subject: [PATCH 015/125] Refactoring --- .../quaternions/ComponentsQuaternion.java | 10 +- .../radi3nt/noise/SeededFastSimplexNoise.java | 6 +- .../radi3nt/noise/simplex/SimplexNoise.java | 455 ++++++++++++++++++ 3 files changed, 464 insertions(+), 7 deletions(-) create mode 100644 NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index b653dcf..6421d6f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -22,7 +22,7 @@ public ComponentsQuaternion(float x, float y, float z, float w) { public static Quaternion fromVectorToAnother(Vector3f v1, Vector3f v2) { Vector3f vector = v1.duplicate().cross(v2); float w = (float) (Math.sqrt((v1.lengthSquared()) * (v2.lengthSquared())) + v1.dot(v2)); - ComponentsQuaternion componentsQuaternion = new ComponentsQuaternion(vector.getX(), vector.getY(), vector.getZ(), w); + Quaternion componentsQuaternion = new ComponentsQuaternion(vector.getX(), vector.getY(), vector.getZ(), w); componentsQuaternion.normalise(); return componentsQuaternion; } @@ -94,10 +94,10 @@ public void multiply(Quaternion quaternion) { float otherY = quaternion.getY(); float otherZ = quaternion.getZ(); - float w = this.w * otherW - this.x * otherX - this.y * otherY - this.z * otherZ; - float x = this.w * otherX + this.x * otherW + this.y * otherZ - this.z * otherY; - float y = this.w * otherY + this.y * otherW + this.z * otherX - this.x * otherZ; - float z = this.w * otherZ + this.z * otherW + this.x * otherY - this.y * otherX; + float w = -this.x * otherW + this.y * otherZ - this.z * otherY + this.w * otherX; + float x = this.x * otherZ + this.y * otherW + this.z * otherX + this.w * otherY; + float y = -this.x * otherY - this.y * otherX + this.z * otherW + this.w * otherZ; + float z = this.x * otherX - this.y * otherY - this.z * otherZ + this.w * otherW; this.x = x; this.y = y; diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java index da474de..c3315f0 100644 --- a/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java @@ -1,5 +1,7 @@ package fr.radi3nt.noise; +import fr.radi3nt.noise.simplex.SimplexNoise; + import java.util.Random; public class SeededFastSimplexNoise { @@ -16,10 +18,10 @@ public SeededFastSimplexNoise(long seed) { } public double noise(double x, double y, double z) { - return FastSimplexNoise.noise(x + xOffset, y + yOffset, z + zOffset); + return SimplexNoise.noise((float) (x + xOffset), (float) (y + yOffset), (float) (z + zOffset)); } public double noise(double x, double z) { - return FastSimplexNoise.noise(x + xOffset, z + zOffset); + return SimplexNoise.noise((float) (x + xOffset), (float) (z + zOffset)); } } diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java new file mode 100644 index 0000000..0f1eb85 --- /dev/null +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java @@ -0,0 +1,455 @@ +package fr.radi3nt.noise.simplex; + +public class SimplexNoise { + + private static class Vector3b { + byte x, y, z; + Vector3b(int x, int y, int z) { + super(); + this.x = (byte) x; + this.y = (byte) y; + this.z = (byte) z; + } + } + private static class Vector4b { + byte x, y, z, w; + Vector4b(int x, int y, int z, int w) { + super(); + this.x = (byte) x; + this.y = (byte) y; + this.z = (byte) z; + this.w = (byte) w; + } + } + + // Kai Burjack: + // Use a three-component vector here to save memory. (instead of using 4-component 'Grad' class) + // And as the original author mentioned on the 'Grad' class, using a class to store the gradient components + // is indeed faster compared to using a simple int[] array... + private static final Vector3b[] grad3 = { new Vector3b(1, 1, 0), new Vector3b(-1, 1, 0), new Vector3b(1, -1, 0), new Vector3b(-1, -1, 0), + new Vector3b(1, 0, 1), new Vector3b(-1, 0, 1), new Vector3b(1, 0, -1), new Vector3b(-1, 0, -1), new Vector3b(0, 1, 1), new Vector3b(0, -1, 1), + new Vector3b(0, 1, -1), new Vector3b(0, -1, -1) }; + + // Kai Burjack: + // As the original author mentioned on the 'Grad' class, using a class to store the gradient components + // is indeed faster compared to using a simple int[] array... + private static final Vector4b[] grad4 = { new Vector4b(0, 1, 1, 1), new Vector4b(0, 1, 1, -1), new Vector4b(0, 1, -1, 1), new Vector4b(0, 1, -1, -1), + new Vector4b(0, -1, 1, 1), new Vector4b(0, -1, 1, -1), new Vector4b(0, -1, -1, 1), new Vector4b(0, -1, -1, -1), new Vector4b(1, 0, 1, 1), + new Vector4b(1, 0, 1, -1), new Vector4b(1, 0, -1, 1), new Vector4b(1, 0, -1, -1), new Vector4b(-1, 0, 1, 1), new Vector4b(-1, 0, 1, -1), + new Vector4b(-1, 0, -1, 1), new Vector4b(-1, 0, -1, -1), new Vector4b(1, 1, 0, 1), new Vector4b(1, 1, 0, -1), new Vector4b(1, -1, 0, 1), + new Vector4b(1, -1, 0, -1), new Vector4b(-1, 1, 0, 1), new Vector4b(-1, 1, 0, -1), new Vector4b(-1, -1, 0, 1), new Vector4b(-1, -1, 0, -1), + new Vector4b(1, 1, 1, 0), new Vector4b(1, 1, -1, 0), new Vector4b(1, -1, 1, 0), new Vector4b(1, -1, -1, 0), new Vector4b(-1, 1, 1, 0), + new Vector4b(-1, 1, -1, 0), new Vector4b(-1, -1, 1, 0), new Vector4b(-1, -1, -1, 0) }; + + // Kai Burjack: + // Use a byte[] instead of a short[] to save memory + private static final byte[] p = { -105, -96, -119, 91, 90, 15, -125, 13, -55, 95, 96, 53, -62, -23, 7, -31, -116, 36, 103, 30, 69, -114, 8, 99, 37, -16, + 21, 10, 23, -66, 6, -108, -9, 120, -22, 75, 0, 26, -59, 62, 94, -4, -37, -53, 117, 35, 11, 32, 57, -79, 33, 88, -19, -107, 56, 87, -82, 20, 125, + -120, -85, -88, 68, -81, 74, -91, 71, -122, -117, 48, 27, -90, 77, -110, -98, -25, 83, 111, -27, 122, 60, -45, -123, -26, -36, 105, 92, 41, 55, 46, + -11, 40, -12, 102, -113, 54, 65, 25, 63, -95, 1, -40, 80, 73, -47, 76, -124, -69, -48, 89, 18, -87, -56, -60, -121, -126, 116, -68, -97, 86, -92, + 100, 109, -58, -83, -70, 3, 64, 52, -39, -30, -6, 124, 123, 5, -54, 38, -109, 118, 126, -1, 82, 85, -44, -49, -50, 59, -29, 47, 16, 58, 17, -74, + -67, 28, 42, -33, -73, -86, -43, 119, -8, -104, 2, 44, -102, -93, 70, -35, -103, 101, -101, -89, 43, -84, 9, -127, 22, 39, -3, 19, 98, 108, 110, + 79, 113, -32, -24, -78, -71, 112, 104, -38, -10, 97, -28, -5, 34, -14, -63, -18, -46, -112, 12, -65, -77, -94, -15, 81, 51, -111, -21, -7, 14, -17, + 107, 49, -64, -42, 31, -75, -57, 106, -99, -72, 84, -52, -80, 115, 121, 50, 45, 127, 4, -106, -2, -118, -20, -51, 93, -34, 114, 67, 29, 24, 72, + -13, -115, -128, -61, 78, 66, -41, 61, -100, -76 }; + // To remove the need for index wrapping, float the permutation table length + private static final byte[] perm = new byte[512]; + private static final byte[] permMod12 = new byte[512]; + static { + for (int i = 0; i < 512; i++) { + perm[i] = p[i & 255]; + permMod12[i] = (byte) ((perm[i]&0xFF) % 12); + } + } + + // Skewing and unskewing factors for 2, 3, and 4 dimensions + private static final float F2 = 0.3660254037844386f; // <- (float) (0.5f * (Math.sqrt(3.0f) - 1.0f)); + private static final float G2 = 0.21132486540518713f; // <- (float) ((3.0f - Math.sqrt(3.0f)) / 6.0f); + private static final float F3 = 1.0f / 3.0f; + private static final float G3 = 1.0f / 6.0f; + private static final float F4 = 0.30901699437494745f; // <- (float) ((Math.sqrt(5.0f) - 1.0f) / 4.0f); + private static final float G4 = 0.1381966011250105f; // <- (float) ((5.0f - Math.sqrt(5.0f)) / 20.0f); + + // This method is a *lot* faster than using (int)Math.floor(x) + private static int fastfloor(float x) { + int xi = (int) x; + return x < xi ? xi - 1 : xi; + } + + private static float dot(Vector3b g, float x, float y) { + return g.x * x + g.y * y; + } + + private static float dot(Vector3b g, float x, float y, float z) { + return g.x * x + g.y * y + g.z * z; + } + + private static float dot(Vector4b g, float x, float y, float z, float w) { + return g.x * x + g.y * y + g.z * z + g.w * w; + } + + /** + * Compute 2D simplex noise for the given input vector (x, y). + *

+ * The result is in the range [-1..+1]. + * + * @param x + * the x coordinate + * @param y + * the y coordinate + * @return the noise value (within [-1..+1]) + */ + public static float noise(float x, float y) { + float n0, n1, n2; // Noise contributions from the three corners + // Skew the input space to determine which simplex cell we're in + float s = (x + y) * F2; // Hairy factor for 2D + int i = fastfloor(x + s); + int j = fastfloor(y + s); + float t = (i + j) * G2; + float X0 = i - t; // Unskew the cell origin back to (x,y) space + float Y0 = j - t; + float x0 = x - X0; // The x,y distances from the cell origin + float y0 = y - Y0; + // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + if (x0 > y0) { + i1 = 1; + j1 = 0; + } // lower triangle, XY order: (0,0)->(1,0)->(1,1) + else { + i1 = 0; + j1 = 1; + } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + float y1 = y0 - j1 + G2; + float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords + float y2 = y0 - 1.0f + 2.0f * G2; + // Work out the hashed gradient indices of the three simplex corners + int ii = i & 255; + int jj = j & 255; + int gi0 = permMod12[ii + perm[jj]&0xFF]&0xFF; + int gi1 = permMod12[ii + i1 + perm[jj + j1]&0xFF]&0xFF; + int gi2 = permMod12[ii + 1 + perm[jj + 1]&0xFF]&0xFF; + // Calculate the contribution from the three corners + float t0 = 0.5f - x0 * x0 - y0 * y0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient + } + float t1 = 0.5f - x1 * x1 - y1 * y1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = t1 * t1 * dot(grad3[gi1], x1, y1); + } + float t2 = 0.5f - x2 * x2 - y2 * y2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = t2 * t2 * dot(grad3[gi2], x2, y2); + } + // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + return 70.0f * (n0 + n1 + n2); + } + + /** + * Compute 3D simplex noise for the given input vector (x, y, z). + *

+ * The result is in the range [-1..+1]. + * + * @param x + * the x coordinate + * @param y + * the y coordinate + * @param z + * the z coordinate + * @return the noise value (within [-1..+1]) + */ + public static float noise(float x, float y, float z) { + float n0, n1, n2, n3; // Noise contributions from the four corners + // Skew the input space to determine which simplex cell we're in + float s = (x + y + z) * F3; // Very nice and simple skew factor for 3D + int i = fastfloor(x + s); + int j = fastfloor(y + s); + int k = fastfloor(z + s); + float t = (i + j + k) * G3; + float X0 = i - t; // Unskew the cell origin back to (x,y,z) space + float Y0 = j - t; + float Z0 = k - t; + float x0 = x - X0; // The x,y,z distances from the cell origin + float y0 = y - Y0; + float z0 = z - Z0; + // For the 3D case, the simplex shape is a slightly irregular tetrahedron. + // Determine which simplex we are in. + int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords + int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords + if (x0 >= y0) { + if (y0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } // X Y Z order + else if (x0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } // X Z Y order + else { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } // Z X Y order + } else { // x0(x, y, z, w). + *

+ * The result is in the range [-1..+1]. + * + * @param x + * the x coordinate + * @param y + * the y coordinate + * @param z + * the z coordinate + * @param w + * the w coordinate + * @return the noise value (within [-1..+1]) + */ + public static float noise(float x, float y, float z, float w) { + float n0, n1, n2, n3, n4; // Noise contributions from the five corners + // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in + float s = (x + y + z + w) * F4; // Factor for 4D skewing + int i = fastfloor(x + s); + int j = fastfloor(y + s); + int k = fastfloor(z + s); + int l = fastfloor(w + s); + float t = (i + j + k + l) * G4; // Factor for 4D unskewing + float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space + float Y0 = j - t; + float Z0 = k - t; + float W0 = l - t; + float x0 = x - X0; // The x,y,z,w distances from the cell origin + float y0 = y - Y0; + float z0 = z - Z0; + float w0 = w - W0; + // For the 4D case, the simplex is a 4D shape I won't even try to describe. + // To find out which of the 24 possible simplices we're in, we need to + // determine the magnitude ordering of x0, y0, z0 and w0. + // Six pair-wise comparisons are performed between each possible pair + // of the four coordinates, and the results are used to rank the numbers. + int rankx = 0; + int ranky = 0; + int rankz = 0; + int rankw = 0; + if (x0 > y0) + rankx++; + else + ranky++; + if (x0 > z0) + rankx++; + else + rankz++; + if (x0 > w0) + rankx++; + else + rankw++; + if (y0 > z0) + ranky++; + else + rankz++; + if (y0 > w0) + ranky++; + else + rankw++; + if (z0 > w0) + rankz++; + else + rankw++; + int i1, j1, k1, l1; // The integer offsets for the second simplex corner + int i2, j2, k2, l2; // The integer offsets for the third simplex corner + int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner + // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. + // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0; + j1 = ranky >= 3 ? 1 : 0; + k1 = rankz >= 3 ? 1 : 0; + l1 = rankw >= 3 ? 1 : 0; + // Rank 2 denotes the second largest coordinate. + i2 = rankx >= 2 ? 1 : 0; + j2 = ranky >= 2 ? 1 : 0; + k2 = rankz >= 2 ? 1 : 0; + l2 = rankw >= 2 ? 1 : 0; + // Rank 1 denotes the second smallest coordinate. + i3 = rankx >= 1 ? 1 : 0; + j3 = ranky >= 1 ? 1 : 0; + k3 = rankz >= 1 ? 1 : 0; + l3 = rankw >= 1 ? 1 : 0; + // The fifth corner has all coordinate offsets = 1, so no need to compute that. + float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords + float y1 = y0 - j1 + G4; + float z1 = z0 - k1 + G4; + float w1 = w0 - l1 + G4; + float x2 = x0 - i2 + 2.0f * G4; // Offsets for third corner in (x,y,z,w) coords + float y2 = y0 - j2 + 2.0f * G4; + float z2 = z0 - k2 + 2.0f * G4; + float w2 = w0 - l2 + 2.0f * G4; + float x3 = x0 - i3 + 3.0f * G4; // Offsets for fourth corner in (x,y,z,w) coords + float y3 = y0 - j3 + 3.0f * G4; + float z3 = z0 - k3 + 3.0f * G4; + float w3 = w0 - l3 + 3.0f * G4; + float x4 = x0 - 1.0f + 4.0f * G4; // Offsets for last corner in (x,y,z,w) coords + float y4 = y0 - 1.0f + 4.0f * G4; + float z4 = z0 - 1.0f + 4.0f * G4; + float w4 = w0 - 1.0f + 4.0f * G4; + // Work out the hashed gradient indices of the five simplex corners + int ii = i & 255; + int jj = j & 255; + int kk = k & 255; + int ll = l & 255; + int gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]&0xFF]&0xFF]&0xFF]&0xFF) % 32; + int gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]&0xFF]&0xFF]&0xFF]&0xFF) % 32; + int gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]&0xFF]&0xFF]&0xFF]&0xFF) % 32; + int gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]&0xFF]&0xFF]&0xFF]&0xFF) % 32; + int gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]&0xFF]&0xFF]&0xFF]&0xFF) % 32; + // Calculate the contribution from the five corners + float t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0); + } + float t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1); + } + float t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2); + } + float t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; + if (t3 < 0.0f) + n3 = 0.0f; + else { + t3 *= t3; + n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3); + } + float t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; + if (t4 < 0.0f) + n4 = 0.0f; + else { + t4 *= t4; + n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4); + } + // Sum up and scale the result to cover the range [-1,1] + return 27.0f * (n0 + n1 + n2 + n3 + n4); + } + +} \ No newline at end of file From 7a4ea82abb863d81b7025989be0d3df0d457c7cf Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 10 Feb 2023 13:00:51 +0100 Subject: [PATCH 016/125] Added VaryingSeedNoise --- .../fr/radi3nt/noise/VaryingSeedNoise.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java new file mode 100644 index 0000000..7218155 --- /dev/null +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java @@ -0,0 +1,24 @@ +package fr.radi3nt.noise; + +import fr.radi3nt.noise.simplex.SimplexNoise; + +import java.util.Random; + +public class VaryingSeedNoise { + + public static float noise(int seed, float x, float y, float z, float size) { + Random random = new Random(seed); + float xOffset = random.nextFloat()+random.nextInt(); + float yOffset = random.nextFloat()+random.nextInt(); + float zOffset = random.nextFloat()+random.nextInt(); + return SimplexNoise.noise(xOffset+x/size, yOffset+y/size, zOffset+z/size); + } + + public static float noise(int seed, float x, float y, float size) { + Random random = new Random(seed); + float xOffset = random.nextFloat()+random.nextInt(); + float yOffset = random.nextFloat()+random.nextInt(); + return SimplexNoise.noise(xOffset+x/size, yOffset+y/size); + } + +} From c53b7d9e6e0dc7cbae395796dd73e9c1c17dfd95 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 17 Feb 2023 00:18:13 +0100 Subject: [PATCH 017/125] Fixed VaryingSeedNoise issue (overflow) --- .../fr/radi3nt/noise/VaryingSeedNoise.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java index 7218155..aac5ed9 100644 --- a/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java @@ -6,19 +6,21 @@ public class VaryingSeedNoise { - public static float noise(int seed, float x, float y, float z, float size) { - Random random = new Random(seed); - float xOffset = random.nextFloat()+random.nextInt(); - float yOffset = random.nextFloat()+random.nextInt(); - float zOffset = random.nextFloat()+random.nextInt(); + public static float noise(Random random, float x, float y, float z, float size) { + float xOffset = offsetBasedOnSeed(random); + float yOffset = offsetBasedOnSeed(random); + float zOffset = offsetBasedOnSeed(random); return SimplexNoise.noise(xOffset+x/size, yOffset+y/size, zOffset+z/size); } - public static float noise(int seed, float x, float y, float size) { - Random random = new Random(seed); - float xOffset = random.nextFloat()+random.nextInt(); - float yOffset = random.nextFloat()+random.nextInt(); + public static float noise(Random random, float x, float y, float size) { + float xOffset = offsetBasedOnSeed(random); + float yOffset = offsetBasedOnSeed(random); return SimplexNoise.noise(xOffset+x/size, yOffset+y/size); } + private static float offsetBasedOnSeed(Random random) { + return random.nextFloat(); + } + } From 1e5bd88ac27d6e91fd9fdd6e116ed66ef39785e9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Mon, 20 Feb 2023 02:55:16 +0100 Subject: [PATCH 018/125] Added additional constructor in BasicColour for convenience --- .../java/fr/radi3nt/maths/colour/colors/BasicColour.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java index 0760a95..f673a1d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java @@ -6,6 +6,9 @@ public class BasicColour implements Colour { + public static final BasicColour WHITE = new BasicColour(1f, 1f, 1f); + public static final BasicColour BLACK = new BasicColour(0f, 0f, 0f); + private final float red; private final float green; private final float blue; @@ -20,6 +23,10 @@ public BasicColour(float red, float green, float blue) { this.blue = blue; } + public BasicColour(float color) { + this(color, color, color); + } + public BasicColour(int red, int green, int blue) { this.red = red/255f; this.green = green/255f; From 4f365d1dfef1a655811e368a802b7779f0801bb9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 25 Feb 2023 12:18:21 +0100 Subject: [PATCH 019/125] getCrossProduct can now write its result to a set vector, without creating a new one --- .../java/fr/radi3nt/maths/components/Vector3D.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java index 9ed411b..5270f5c 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java @@ -156,6 +156,16 @@ public Vector3D getCrossProduct(Vector3D o) { return new Vector3D(x, y, z); } + public Vector3D getCrossProduct(Vector3D o, Vector3D result) { + double x = this.y * o.z - o.y * this.z; + double y = this.z * o.x - o.z * this.x; + double z = this.x * o.y - o.x * this.y; + result.setX(x); + result.setY(y); + result.setZ(z); + return result; + } + public Vector3D normalize() { double length = this.length(); this.x /= length; From 552340e734634d76a3987b1ec8c15d51ac013f7c Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 25 Feb 2023 18:58:30 +0100 Subject: [PATCH 020/125] Moved SAT lib to MathsHelper --- .../main/java/fr/radi3nt/maths/sat/MTV.java | 22 +++ .../fr/radi3nt/maths/sat/SatResolver.java | 63 +++++++ .../radi3nt/maths/sat/components/SatAxis.java | 33 ++++ .../radi3nt/maths/sat/components/SatEdge.java | 20 +++ .../projection/NewSatProjectionManager.java | 13 ++ .../projection/ReuseSatProjectionManager.java | 18 ++ .../maths/sat/projection/SatProjection.java | 62 +++++++ .../sat/projection/SatProjectionProvider.java | 8 + .../fr/radi3nt/maths/sat/shape/BoxSAT.java | 50 ++++++ .../fr/radi3nt/maths/sat/shape/ObbSAT.java | 54 ++++++ .../fr/radi3nt/maths/sat/shape/SATShape.java | 16 ++ .../maths/sat/shape/VerticesSATShape.java | 29 ++++ .../shape/triangles/ComputingTriangleSAT.java | 51 ++++++ .../shape/triangles/StoringTriangleSAT.java | 47 ++++++ .../sat/shape/triangles/TriangleSAT.java | 8 + .../sat/swept/CheepSweptSatResolver.java | 154 ++++++++++++++++++ .../sat/swept/EconomicSweptSatResolver.java | 119 ++++++++++++++ .../radi3nt/maths/sat/swept/SweptResult.java | 45 +++++ .../maths/sat/swept/SweptSatResolver.java | 115 +++++++++++++ 19 files changed, 927 insertions(+) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java new file mode 100644 index 0000000..d202aeb --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.sat; + +import fr.radi3nt.maths.sat.components.SatAxis; + +public class MTV { + + private final SatAxis smallest; + private final double overlap; + + public MTV(SatAxis smallest, double overlap) { + this.smallest = smallest; + this.overlap = overlap; + } + + public SatAxis getSmallest() { + return smallest; + } + + public double getOverlap() { + return overlap; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java new file mode 100644 index 0000000..8ef9c32 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java @@ -0,0 +1,63 @@ +package fr.radi3nt.maths.sat; + +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; +import fr.radi3nt.maths.sat.shape.SATShape; + +public class SatResolver { + + private final SatProjectionProvider provider0; + private final SatProjectionProvider provider1; + private final SATShape shape1; + private final SATShape shape2; + + public SatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2) { + this.provider0 = provider; + this.provider1 = provider.duplicate(); + this.shape1 = shape1; + this.shape2 = shape2; + } + + public boolean resolve() { + SatAxis[] axes1 = shape1.getAxes(); + SatAxis[] axes2 = shape2.getAxes(); + // loop over the axes1 + if (testOverlapOnAxes(axes1)) return false; + // loop over the axes2 + if (testOverlapOnAxes(axes2)) return false; + + SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); + return !testOverlapOnAxes(edgeAxis); + + // if we get here then we know that every axis had overlap on it, so we can guarantee an intersection + } + + private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { + int size = edges.length * others.length; + SatAxis[] axes = new SatAxis[size]; + int i = 0; + for (SatEdge edge : edges) { + for (SatEdge other : others) { + axes[i] = edge.axis(other); + i++; + } + } + return axes; + } + + private boolean testOverlapOnAxes(SatAxis[] axes) { + for (SatAxis axis : axes) { + // project both shapes onto the axis + SatProjection p1 = shape1.project(provider0, axis); + SatProjection p2 = shape2.project(provider1, axis); + // do the projections overlap? + if (p1.noOverlap(p2)) { + // then we can guarantee that the shapes do not overlap + return true; + } + } + return false; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java new file mode 100644 index 0000000..5a458a9 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java @@ -0,0 +1,33 @@ +package fr.radi3nt.maths.sat.components; + +import fr.radi3nt.maths.components.Vector3D; + +public class SatAxis { + + private Vector3D normal; + + public SatAxis(Vector3D normal) { + this.normal = normal; + } + + public void set(Vector3D normal) { + this.normal = normal; + } + + public double dot(Vector3D dotted) { + return normal.dot(dotted); + } + + @Deprecated + public Vector3D getNormal() { + return normal; + } + + public SatAxis useNewNormalVector(Vector3D newNormal) { + newNormal.setX(this.normal.getX()); + newNormal.setY(this.normal.getY()); + newNormal.setZ(this.normal.getZ()); + this.normal = newNormal; + return this; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java new file mode 100644 index 0000000..17603d5 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java @@ -0,0 +1,20 @@ +package fr.radi3nt.maths.sat.components; + +import fr.radi3nt.maths.components.Vector3D; + +public class SatEdge { + + private final Vector3D edge; + + public SatEdge(Vector3D edge) { + this.edge = edge; + } + + public SatAxis axis(SatEdge other) { + return new SatAxis(other.edge.getCrossProduct(edge)); + } + + public SatAxis axis(SatEdge other, Vector3D result) { + return new SatAxis(other.edge.getCrossProduct(edge, result)); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java new file mode 100644 index 0000000..190b806 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java @@ -0,0 +1,13 @@ +package fr.radi3nt.maths.sat.projection; + +public class NewSatProjectionManager implements SatProjectionProvider { + @Override + public SatProjection project(double min, double max) { + return new SatProjection(min, max); + } + + @Override + public SatProjectionProvider duplicate() { + return new NewSatProjectionManager(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java new file mode 100644 index 0000000..ab24ada --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java @@ -0,0 +1,18 @@ +package fr.radi3nt.maths.sat.projection; + +public class ReuseSatProjectionManager implements SatProjectionProvider { + + private final SatProjection satProjection = new SatProjection(0, 0); + + @Override + public SatProjection project(double min, double max) { + satProjection.setMin(min); + satProjection.setMax(max); + return satProjection; + } + + @Override + public SatProjectionProvider duplicate() { + return new ReuseSatProjectionManager(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java new file mode 100644 index 0000000..c98b8e8 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java @@ -0,0 +1,62 @@ +package fr.radi3nt.maths.sat.projection; + +import fr.radi3nt.maths.sat.swept.SweptResult; + +public class SatProjection { + + private double min; + private double max; + + public SatProjection(double min, double max) { + this.min = min; + this.max = max; + } + + public boolean noOverlap(SatProjection p2) { + return !overlap(p2); + } + + private boolean overlap(SatProjection p2) { + if (this.min <= p2.min) { + return this.max >= p2.min; + } else { + return p2.max >= this.min; + } + } + + public void sweptOverlap(SatProjection p2, double speed, SweptResult resultPassing) { + double tEnter; + double tLeave; + + + tEnter = (p2.min - this.max) / speed; + tLeave = (p2.max - this.min) / speed; + + if (tEnter > tLeave) { + double oldTEnter = tEnter; + tEnter = tLeave; + tLeave = oldTEnter; + } + + resultPassing.set(tEnter, tLeave, null); + } + + public double getOverlap(SatProjection p2) { + if (this.min <= p2.min) { + if (this.max >= p2.min) + return p2.min - this.max; + } else { + if (p2.max >= this.min) + return p2.max - this.min; + } + return -1d; + } + + public void setMin(double min) { + this.min = min; + } + + public void setMax(double max) { + this.max = max; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java new file mode 100644 index 0000000..9555a00 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java @@ -0,0 +1,8 @@ +package fr.radi3nt.maths.sat.projection; + +public interface SatProjectionProvider { + + SatProjection project(double min, double max); + SatProjectionProvider duplicate(); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java new file mode 100644 index 0000000..d33d754 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java @@ -0,0 +1,50 @@ +package fr.radi3nt.maths.sat.shape; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; + +public class BoxSAT implements VerticesSATShape { + + private static final SatAxis[] SAT_AXES = new SatAxis[]{ + new SatAxis(new Vector3D(1, 0, 0)), + new SatAxis(new Vector3D(0, 1, 0)), + new SatAxis(new Vector3D(0, 0, 1)) + }; + + private static final SatEdge[] SAT_EDGES = new SatEdge[]{ + new SatEdge(new Vector3D(1, 0, 0)), + new SatEdge(new Vector3D(0, 1, 0)), + new SatEdge(new Vector3D(0, 0, 1)) + }; + + private final Vector3D[] vertices; + + public BoxSAT(Vector3D min, Vector3D max) { + vertices = new Vector3D[]{ + min.clone(), + max.clone(), + new Vector3D(max.getX(), min.getY(), min.getZ()), + new Vector3D(max.getX(), max.getY(), min.getZ()), + new Vector3D(min.getX(), max.getY(), min.getZ()), + new Vector3D(min.getX(), max.getY(), max.getZ()), + new Vector3D(min.getX(), min.getY(), max.getZ()), + new Vector3D(max.getX(), min.getY(), max.getZ()) + }; + } + + @Override + public SatAxis[] getAxes() { + return SAT_AXES; + } + + @Override + public SatEdge[] getEdges() { + return SAT_EDGES; + } + + @Override + public Vector3D[] getVertices() { + return vertices; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java new file mode 100644 index 0000000..608c2f0 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java @@ -0,0 +1,54 @@ +package fr.radi3nt.maths.sat.shape; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; + +@Deprecated +public class ObbSAT implements VerticesSATShape { //todo does it work ? + + private final Vector3D point; + + private final Vector3D xSide; + private final Vector3D ySide; + private final Vector3D zSide; + + public ObbSAT(Vector3D point, Vector3D xSide, Vector3D ySide, Vector3D zSide) { + this.point = point; + this.xSide = xSide; + this.ySide = ySide; + this.zSide = zSide; + } + + @Override + public SatAxis[] getAxes() { + return new SatAxis[]{ + new SatAxis(xSide.clone().normalize()), + new SatAxis(ySide.clone().normalize()), + new SatAxis(zSide.clone().normalize()) + }; + } + + @Override + public SatEdge[] getEdges() { + return new SatEdge[]{ + new SatEdge(xSide), + new SatEdge(ySide), + new SatEdge(zSide) + }; + } + + @Override + public Vector3D[] getVertices() { + return new Vector3D[]{ + point.clone(), + point.clone().add(xSide), + point.clone().add(xSide).add(ySide), + point.clone().add(xSide).add(ySide).add(zSide), + point.clone().add(xSide).add(zSide), + point.clone().add(zSide), + point.clone().add(ySide), + point.clone().add(ySide).add(zSide), + }; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java new file mode 100644 index 0000000..8c9aff4 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java @@ -0,0 +1,16 @@ +package fr.radi3nt.maths.sat.shape; + +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; + +public interface SATShape { + + SatAxis[] getAxes(); + + SatEdge[] getEdges(); + + SatProjection project(SatProjectionProvider provider, SatAxis axis); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java new file mode 100644 index 0000000..ddfb6fd --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java @@ -0,0 +1,29 @@ +package fr.radi3nt.maths.sat.shape; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; + +public interface VerticesSATShape extends SATShape { + + @Override + default SatProjection project(SatProjectionProvider provider, SatAxis axis) { + Vector3D[] vertices = getVertices(); + + double min = axis.dot(vertices[0]); + double max = min; + for (int i = 1; i < vertices.length; i++) { + double p = axis.dot(vertices[i]); + if (p < min) { + min = p; + } else if (p > max) { + max = p; + } + } + + return provider.project(min, max); + } + + Vector3D[] getVertices(); +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java new file mode 100644 index 0000000..f82ebc0 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java @@ -0,0 +1,51 @@ +package fr.radi3nt.maths.sat.shape.triangles; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; + +public class ComputingTriangleSAT implements TriangleSAT { + + private final Vector3f vert1; + private final Vector3f vert2; + private final Vector3f vert3; + private final Vector3f triNormal; + + public ComputingTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { + this.vert1 = vert1; + this.vert2 = vert2; + this.vert3 = vert3; + this.triNormal = triNormal; + } + + @Override + public Vector3D[] getVertices() { + Vector3D[] vertices = new Vector3D[3]; + for (int i = 0; i < 3; i++) { + Vector3f position = i == 0 ? vert1 : i==1 ? vert2 : vert3; + vertices[i] = new Vector3D(position.getX(), position.getY(), position.getZ()); + } + return vertices; + } + + @Override + public SatAxis[] getAxes() { + Vector3D normal = new Vector3D(triNormal.getX(), triNormal.getY(), triNormal.getZ()); + SatAxis faceAxis = new SatAxis(normal); + return new SatAxis[]{faceAxis}; + } + + @Override + public SatEdge[] getEdges() { + return new SatEdge[]{ + new SatEdge(sub(vert1, vert2)), + new SatEdge(sub(vert2, vert3)), + new SatEdge(sub(vert3, vert1)), + }; + } + + private Vector3D sub(Vector3f vert1, Vector3f vert2) { + return new Vector3D(vert1.getX()-vert2.getX(), vert1.getY()-vert2.getY(), vert1.getZ()-vert2.getZ()); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java new file mode 100644 index 0000000..b3a0906 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java @@ -0,0 +1,47 @@ +package fr.radi3nt.maths.sat.shape.triangles; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; + +public class StoringTriangleSAT implements TriangleSAT { + + private final Vector3D[] vertices = new Vector3D[3]; + private final SatAxis[] satAxes; + private final SatEdge[] edges; + + public StoringTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { + for (int i = 0; i < 3; i++) { + Vector3f position = i == 0 ? vert1 : i==1 ? vert2 : vert3; + vertices[i] = new Vector3D(position.getX(), position.getY(), position.getZ()); + } + + Vector3D normal = new Vector3D(triNormal.getX(), triNormal.getY(), triNormal.getZ()); + SatAxis faceAxis = new SatAxis(normal); + + satAxes = new SatAxis[]{faceAxis}; + + Vector3D[] vertices = getVertices(); + edges = new SatEdge[]{ + new SatEdge(vertices[0].clone().subtract(vertices[1])), + new SatEdge(vertices[1].clone().subtract(vertices[2])), + new SatEdge(vertices[2].clone().subtract(vertices[0])), + }; + } + + @Override + public Vector3D[] getVertices() { + return vertices; + } + + @Override + public SatAxis[] getAxes() { + return satAxes; + } + + @Override + public SatEdge[] getEdges() { + return edges; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java new file mode 100644 index 0000000..6c96d67 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java @@ -0,0 +1,8 @@ +package fr.radi3nt.maths.sat.shape.triangles; + +import fr.radi3nt.maths.sat.shape.VerticesSATShape; + +public interface TriangleSAT extends VerticesSATShape { + + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java new file mode 100644 index 0000000..a8dacde --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java @@ -0,0 +1,154 @@ +package fr.radi3nt.maths.sat.swept; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; +import fr.radi3nt.maths.sat.shape.SATShape; + +public class CheepSweptSatResolver { + + private final SatProjectionProvider provider0; + private final SatProjectionProvider provider1; + private SATShape shape1; + private SATShape shape2; + + private Vector3D velocity; + private final Vector3D cacheCross = new Vector3D(); + private final Vector3D cacheCrossResult = new Vector3D(); + + public CheepSweptSatResolver(SatProjectionProvider provider) { + this.provider0 = provider; + this.provider1 = provider.duplicate(); + } + + public void set(SATShape shape1, SATShape shape2, Vector3D velocity) { + this.shape1 = shape1; + this.shape2 = shape2; + this.velocity = velocity; + } + + public SweptResult resolve() { + SatAxis[] axes1 = shape1.getAxes(); + SatAxis[] axes2 = shape2.getAxes(); + // loop over the axes1 + + SweptResult shapeOne = testOverlapOnAxes(axes1); + if (shapeOne == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + // loop over the axes2 + SweptResult shapeTwo = testOverlapOnAxes(axes2); + if (shapeTwo == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + + SweptResult edges = testOverlapOnAxes(shape1.getEdges(), shape2.getEdges()); + if (edges == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + if (tEnter < shapeOne.getTEnter()) { + enterAxis = shapeOne.getEnterAxis(); + tEnter = shapeOne.getTEnter(); + } + + tLeave = Math.min(shapeOne.getTLeave(), tLeave); + + if (tEnter < shapeTwo.getTEnter()) { + enterAxis = shapeTwo.getEnterAxis(); + tEnter = shapeTwo.getTEnter(); + } + tLeave = Math.min(shapeTwo.getTLeave(), tLeave); + + if (tEnter < edges.getTEnter()) { + enterAxis = edges.getEnterAxis(); + tEnter = edges.getTEnter(); + } + tLeave = Math.min(edges.getTLeave(), tLeave); + + if (tEnter > tLeave) { + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } + + private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + SweptResult resultPassing = new SweptResult(); + + for (SatEdge edge : edges) { + for (SatEdge other : others) { + SatAxis axis = edge.axis(other, cacheCross); + + // project both shapes onto the axis + SatProjection p1 = shape1.project(provider0, axis); + SatProjection p2 = shape2.project(provider1, axis); + // do the projections overlap? + + double speed = axis.dot(velocity); + if (speed == 0) { + if (p1.noOverlap(p2)) { + return null; + } + continue; + } + + p1.sweptOverlap(p2, speed, resultPassing); + if (tEnter < resultPassing.getTEnter()) { + enterAxis = axis.useNewNormalVector(cacheCrossResult); + tEnter = resultPassing.getTEnter(); + if (tEnter > 1) + return null; + } + tLeave = Math.min(resultPassing.getTLeave(), tLeave); + if (tLeave < 0) + return null; + } + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } + + private SweptResult testOverlapOnAxes(SatAxis... axes) { + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + SweptResult resultPassing = new SweptResult(); + for (SatAxis axis : axes) { + // project both shapes onto the axis + SatProjection p1 = shape1.project(provider0, axis); + SatProjection p2 = shape2.project(provider1, axis); + // do the projections overlap? + + double speed = axis.dot(velocity); + if (speed == 0) { + if (p1.noOverlap(p2)) { + return null; + } + continue; + } + + p1.sweptOverlap(p2, speed, resultPassing); + if (tEnter < resultPassing.getTEnter()) { + enterAxis = axis; + tEnter = resultPassing.getTEnter(); + if (tEnter > 1) + return null; + } + tLeave = Math.min(resultPassing.getTLeave(), tLeave); + if (tLeave < 0) + return null; + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java new file mode 100644 index 0000000..62f4b3c --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java @@ -0,0 +1,119 @@ +package fr.radi3nt.maths.sat.swept; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; +import fr.radi3nt.maths.sat.shape.SATShape; + +public class EconomicSweptSatResolver { + + private final SatProjectionProvider provider0; + private final SatProjectionProvider provider1; + private final SATShape shape1; + private final SATShape shape2; + + private final Vector3D velocity; + + public EconomicSweptSatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2, Vector3D velocity) { + this.provider0 = provider; + this.provider1 = provider.duplicate(); + this.shape1 = shape1; + this.shape2 = shape2; + this.velocity = velocity; + } + + public SweptResult resolve() { + SatAxis[] axes1 = shape1.getAxes(); + SatAxis[] axes2 = shape2.getAxes(); + // loop over the axes1 + + SweptResult shapeOne = testOverlapOnAxes(axes1); + if (shapeOne == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + // loop over the axes2 + SweptResult shapeTwo = testOverlapOnAxes(axes2); + if (shapeTwo == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + + SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); + SweptResult edges = testOverlapOnAxes(edgeAxis); + if (edges == null) + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + if (tEnter < shapeOne.getTEnter()) { + enterAxis = shapeOne.getEnterAxis(); + tEnter = shapeOne.getTEnter(); + } + + tLeave = Math.min(shapeOne.getTLeave(), tLeave); + + if (tEnter < shapeTwo.getTEnter()) { + enterAxis = shapeTwo.getEnterAxis(); + tEnter = shapeTwo.getTEnter(); + } + tLeave = Math.min(shapeTwo.getTLeave(), tLeave); + + if (tEnter < edges.getTEnter()) { + enterAxis = edges.getEnterAxis(); + tEnter = edges.getTEnter(); + } + tLeave = Math.min(edges.getTLeave(), tLeave); + + if (tEnter > tLeave) { + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } + + private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { + int size = edges.length * others.length; + SatAxis[] axes = new SatAxis[size]; + int i = 0; + for (SatEdge edge : edges) { + for (SatEdge other : others) { + axes[i] = edge.axis(other); + i++; + } + } + return axes; + } + + private SweptResult testOverlapOnAxes(SatAxis... axes) { + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + SweptResult resultPassing = new SweptResult(); + for (SatAxis axis : axes) { + // project both shapes onto the axis + SatProjection p1 = shape1.project(provider0, axis); + SatProjection p2 = shape2.project(provider1, axis); + // do the projections overlap? + + double speed = axis.dot(velocity); + if (speed == 0) { + if (p1.noOverlap(p2)) { + return null; + } + continue; + } + + p1.sweptOverlap(p2, speed, resultPassing); + if (tEnter < resultPassing.getTEnter()) { + enterAxis = axis; + tEnter = resultPassing.getTEnter(); + } + tLeave = Math.min(resultPassing.getTLeave(), tLeave); + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java new file mode 100644 index 0000000..8ab0639 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java @@ -0,0 +1,45 @@ +package fr.radi3nt.maths.sat.swept; + +import fr.radi3nt.maths.sat.components.SatAxis; + +public class SweptResult { + + private double tEnter; + private double tLeave; + private SatAxis enterAxis; + + public SweptResult() { + } + + public SweptResult(double tEnter, double tLeave, SatAxis enterAxis) { + this.tEnter = tEnter; + this.tLeave = tLeave; + this.enterAxis = enterAxis; + } + + public void set(double tEnter, double tLeave, SatAxis enterAxis) { + this.tEnter = tEnter; + this.tLeave = tLeave; + this.enterAxis = enterAxis; + } + + public double getTEnter() { + return tEnter; + } + + public double getTLeave() { + return tLeave; + } + + public SatAxis getEnterAxis() { + return enterAxis; + } + + @Override + public String toString() { + return "SweptResult{" + + "tEnter=" + tEnter + + ", tLeave=" + tLeave + + '}'; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java new file mode 100644 index 0000000..2ac9eaf --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java @@ -0,0 +1,115 @@ +package fr.radi3nt.maths.sat.swept; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; +import fr.radi3nt.maths.sat.projection.SatProjection; +import fr.radi3nt.maths.sat.projection.SatProjectionProvider; +import fr.radi3nt.maths.sat.shape.SATShape; + +public class SweptSatResolver { + + private final SatProjectionProvider provider0; + private final SatProjectionProvider provider1; + + private final SATShape shape1; + private final SATShape shape2; + + private final Vector3D velocity; + + public SweptSatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2, Vector3D velocity) { + this.provider0 = provider; + this.provider1 = provider.duplicate(); + this.shape1 = shape1; + this.shape2 = shape2; + this.velocity = velocity; + } + + public SweptResult resolve() { + SatAxis[] axes1 = shape1.getAxes(); + SatAxis[] axes2 = shape2.getAxes(); + // loop over the axes1 + + SweptResult shapeOne = testOverlapOnAxes(axes1); + // loop over the axes2 + SweptResult shapeTwo = testOverlapOnAxes(axes2); + + SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); + SweptResult edges = testOverlapOnAxes(edgeAxis); + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + if (tEnter < shapeOne.getTEnter()) { + enterAxis = shapeOne.getEnterAxis(); + tEnter = shapeOne.getTEnter(); + } + + tLeave = Math.min(shapeOne.getTLeave(), tLeave); + + if (tEnter < shapeTwo.getTEnter()) { + enterAxis = shapeTwo.getEnterAxis(); + tEnter = shapeTwo.getTEnter(); + } + tLeave = Math.min(shapeTwo.getTLeave(), tLeave); + + if (tEnter < edges.getTEnter()) { + enterAxis = edges.getEnterAxis(); + tEnter = edges.getTEnter(); + } + tLeave = Math.min(edges.getTLeave(), tLeave); + + if (tEnter > tLeave) { + return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } + + private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { + int size = edges.length * others.length; + SatAxis[] axes = new SatAxis[size]; + int i = 0; + for (SatEdge edge : edges) { + for (SatEdge other : others) { + axes[i] = edge.axis(other); + i++; + } + } + return axes; + } + + private SweptResult testOverlapOnAxes(SatAxis... axes) { + + double tEnter = -Double.MAX_VALUE; + double tLeave = Double.MAX_VALUE; + SatAxis enterAxis = null; + + SweptResult resultPassing = new SweptResult(); + for (SatAxis axis : axes) { + // project both shapes onto the axis + SatProjection p1 = shape1.project(provider0, axis); + SatProjection p2 = shape2.project(provider1, axis); + // do the projections overlap? + + double speed = axis.dot(velocity); + if (speed == 0) { + if (p1.noOverlap(p2)) { + tEnter = Double.MAX_VALUE; + tLeave = -Double.MAX_VALUE; + } + continue; + } + + p1.sweptOverlap(p2, speed, resultPassing); + if (tEnter < resultPassing.getTEnter()) { + enterAxis = axis; + tEnter = resultPassing.getTEnter(); + } + tLeave = Math.min(resultPassing.getTLeave(), tLeave); + } + + return new SweptResult(tEnter, tLeave, enterAxis); + } +} From 9074d87d91b5d09d05d7b6a70d91e2c438b640df Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 1 Mar 2023 22:18:57 +0100 Subject: [PATCH 021/125] Fixed weird physics issue --- .../java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java index a8dacde..dfb6f24 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java @@ -16,7 +16,6 @@ public class CheepSweptSatResolver { private Vector3D velocity; private final Vector3D cacheCross = new Vector3D(); - private final Vector3D cacheCrossResult = new Vector3D(); public CheepSweptSatResolver(SatProjectionProvider provider) { this.provider0 = provider; @@ -102,7 +101,7 @@ private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { p1.sweptOverlap(p2, speed, resultPassing); if (tEnter < resultPassing.getTEnter()) { - enterAxis = axis.useNewNormalVector(cacheCrossResult); + enterAxis = axis.useNewNormalVector(new Vector3D()); tEnter = resultPassing.getTEnter(); if (tEnter > 1) return null; From 859c8f17ffceb98e583bb5ee0d9a1fbe418a137a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 4 Mar 2023 14:45:25 +0100 Subject: [PATCH 022/125] Added useful methods like copy() on Vector3f --- .../java/fr/radi3nt/maths/components/vectors/Vector3f.java | 2 ++ .../components/vectors/implementations/SimpleVector3f.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java index cc6e63f..f36a8e6 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java @@ -47,4 +47,6 @@ public interface Vector3f extends Vector { Vector3f negate(); float lengthSquared(); + + void copy(Vector3f vert1); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index d02e2c6..5783d6d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -173,6 +173,11 @@ public float lengthSquared() { return x * x + y * y + z * z; } + @Override + public void copy(Vector3f vert1) { + this.set(vert1.getX(), vert1.getY(), vert1.getZ()); + } + @Override public float length() { return (float) Math.sqrt(x * x + y * y + z * z); From f687e2159e393f4d515bcef99ffd3997b62ba02f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 4 Mar 2023 14:45:43 +0100 Subject: [PATCH 023/125] Made ComputingTriangleSAT reusable --- .../shape/triangles/ComputingTriangleSAT.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java index f82ebc0..8f412f2 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java @@ -2,15 +2,18 @@ import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; +import java.util.function.Consumer; + public class ComputingTriangleSAT implements TriangleSAT { - private final Vector3f vert1; - private final Vector3f vert2; - private final Vector3f vert3; - private final Vector3f triNormal; + private Vector3f vert1; + private Vector3f vert2; + private Vector3f vert3; + private Vector3f triNormal; public ComputingTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { this.vert1 = vert1; @@ -19,6 +22,34 @@ public ComputingTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vect this.triNormal = triNormal; } + public ComputingTriangleSAT() { + } + + public void set(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { + this.vert1 = copyOrSet(this.vert1, vert1); + this.vert2 = copyOrSet(this.vert2, vert2); + this.vert3 = copyOrSet(this.vert3, vert3); + this.triNormal = copyOrSet(this.triNormal, triNormal); + } + + public void set(Vector3f vert1, Vector3f vert2, Vector3f vert3, Consumer normal) { + this.vert1 = copyOrSet(this.vert1, vert1); + this.vert2 = copyOrSet(this.vert2, vert2); + this.vert3 = copyOrSet(this.vert3, vert3); + + if (triNormal==null) + triNormal = new SimpleVector3f(); + normal.accept(triNormal); + } + + private static Vector3f copyOrSet(Vector3f vert1, Vector3f vert11) { + if (vert1!=null) + vert1.copy(vert11); + else + return vert11; + return vert1; + } + @Override public Vector3D[] getVertices() { Vector3D[] vertices = new Vector3D[3]; From f68369cc9543448886cb9a2a932b76aeac0bb408 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 10 Mar 2023 12:46:49 +0100 Subject: [PATCH 024/125] Added constructor to create color with intensity field --- .../java/fr/radi3nt/maths/colour/colors/BasicColour.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java index f673a1d..8945b8a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java @@ -23,6 +23,12 @@ public BasicColour(float red, float green, float blue) { this.blue = blue; } + public BasicColour(float red, float green, float blue, float intensity) { + this.red = red*intensity; + this.green = green*intensity; + this.blue = blue*intensity; + } + public BasicColour(float color) { this(color, color, color); } From c8a907ce42af2f29c0f73be9b75e607b8e3ff127 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 11 Mar 2023 23:28:05 +0100 Subject: [PATCH 025/125] Fixed directionRotation() method in ArrayMatrix4x4 not behaving as intended --- .../advanced/matrix/ArrayMatrix4x4.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index ba87936..b79ceef 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -284,30 +284,27 @@ public void quaternionRotation(Quaternion quaternion) { @Override public void directionRotation(Vector3f direction, Vector3f up) { - Vector3f z = direction.duplicate(); - z.normalize(); - Vector3f y = up.duplicate(); - Vector3f x = y.duplicate().cross(z); - y = z.duplicate().cross(x); + Vector3f x = up.duplicate().cross(direction); + Vector3f y = direction.duplicate().cross(x); x.normalize(); y.normalize(); m[0][0] = x.getX(); - m[1][0] = x.getY(); - m[2][0] = x.getZ(); - m[3][0] = -x.dot(direction); m[0][1] = y.getX(); - m[1][1] = y.getY(); - m[2][1] = y.getZ(); - m[3][1] = -y.dot(direction); - m[0][2] = z.getX(); - m[1][2] = z.getY(); - m[2][2] = z.getZ(); - m[3][2] = -z.dot(direction); + m[0][2] = direction.getX(); m[0][3] = 0; + m[1][0] = x.getY(); + m[1][1] = y.getY(); + m[1][2] = direction.getY(); m[1][3] = 0; + m[2][0] = x.getZ(); + m[2][1] = y.getZ(); + m[2][2] = direction.getZ(); m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; m[3][3] = 1.0f; } From 7b4610b7ce8f174c828a09ac8b728479456af2e4 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 15 Mar 2023 22:17:56 +0100 Subject: [PATCH 026/125] Added set method to Vector3D and refactored Vector3D --- .../fr/radi3nt/maths/components/Vector3D.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java index 5270f5c..f0f7b1f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java @@ -1,5 +1,7 @@ package fr.radi3nt.maths.components; +import static fr.radi3nt.maths.Maths.EPSILON; + public class Vector3D implements Cloneable { protected double x; @@ -72,6 +74,13 @@ public Vector3D divide(double div) { return this; } + public Vector3D set(double x, double y, double z) { + this.setX(x); + this.setY(y); + this.setZ(z); + return this; + } + public Vector3D copy(Vector3D vec) { this.x = vec.x; this.y = vec.y; @@ -101,16 +110,16 @@ public float angle(Vector3D other) { } public Vector3D midpoint(Vector3D other) { - this.x = (this.x + other.x) / 2.0D; - this.y = (this.y + other.y) / 2.0D; - this.z = (this.z + other.z) / 2.0D; + this.x = (this.x + other.x) / 2; + this.y = (this.y + other.y) / 2; + this.z = (this.z + other.z) / 2; return this; } public Vector3D getMidpoint(Vector3D other) { - double x = (this.x + other.x) / 2.0D; - double y = (this.y + other.y) / 2.0D; - double z = (this.z + other.z) / 2.0D; + double x = (this.x + other.x) / 2; + double y = (this.y + other.y) / 2; + double z = (this.z + other.z) / 2; return new Vector3D(x, y, z); } @@ -272,7 +281,7 @@ public String toString() { } public static double getEpsilon() { - return 1.0E-6D; + return EPSILON; } public static Vector3D getMinimum(Vector3D v1, Vector3D v2) { From 03e948064efae13e09f6c760c7b683ce5f09421a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Mon, 3 Apr 2023 21:57:22 +0200 Subject: [PATCH 027/125] Added maths methods --- .../advanced/matrix/ArrayMatrix4x4.java | 9 +++++ .../components/advanced/matrix/Matrix4x4.java | 3 +- .../quaternions/ComponentsQuaternion.java | 40 +++++++++++++++++++ .../advanced/quaternions/Quaternion.java | 10 +++++ .../implementations/SimpleVector3f.java | 5 +++ .../implementations/SimpleVector4f.java | 7 ++++ 6 files changed, 73 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index b79ceef..a156773 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -188,6 +188,15 @@ public void translation(Vector3f translation) { m[3][2] = translation.getZ(); } + @Override + public void add(Matrix4x4 rotation) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + this.m[i][j]+=rotation.get(i, j); + } + } + } + @Override public void scale(Vector3f scale) { m[0][0] = scale.getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index e971e4f..c385a9a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -15,6 +15,8 @@ public interface Matrix4x4 extends Matrix { void translation(Vector3f translation); + void add(Matrix4x4 rotation); + void scale(Vector3f scale); void rotationX(Angle angle); @@ -36,5 +38,4 @@ public interface Matrix4x4 extends Matrix { void copy(Matrix result); Matrix4x4 duplicate(); - } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 6421d6f..e6cac92 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -105,6 +105,38 @@ public void multiply(Quaternion quaternion) { this.w = w; } + @Override + public void multiply(Vector3f vec) { + float wRes = -(x*vec.getX() + y*vec.getY() + z*vec.getZ()); + float xRes = w*vec.getX() + y*vec.getZ() - z*vec.getY(); + float yRes = w* vec.getY() + z* vec.getX() - x* vec.getZ(); + float zRes = w* vec.getZ() + x*vec.getY() - y*vec.getX(); + x = xRes; + y = yRes; + z = zRes; + w = wRes; + } + + @Override + public void multiplyInv(Vector3f vec) { + float wRes = -(x*vec.getX() + y*vec.getY() + z*vec.getZ()); + float xRes = w*vec.getX() + z*vec.getY() - y*vec.getZ(); + float yRes = w* vec.getY() + x* vec.getZ() - z* vec.getX(); + float zRes = w* vec.getZ() + y*vec.getX() - x*vec.getY(); + x = xRes; + y = yRes; + z = zRes; + w = wRes; + } + + @Override + public void multiply(float s) { + this.x*=s; + this.y*=s; + this.z*=s; + this.w*=s; + } + @Override public void interpolate(Quaternion quaternionEnd, float ease) { double cosHalfTheta = dot(quaternionEnd); @@ -154,6 +186,14 @@ public Quaternion duplicate() { return new ComponentsQuaternion(x, y, z, w); } + @Override + public void add(Quaternion quaternion) { + this.x += quaternion.getX(); + this.y += quaternion.getY(); + this.z += quaternion.getZ(); + this.w += quaternion.getW(); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index 218b6dc..af35a9f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -1,5 +1,7 @@ package fr.radi3nt.maths.components.advanced.quaternions; +import fr.radi3nt.maths.components.vectors.Vector3f; + public interface Quaternion { float getX(); @@ -12,8 +14,16 @@ public interface Quaternion { void normalise(); + void add(Quaternion quaternion); + void multiply(Quaternion quaternion); + void multiply(Vector3f vec); + + void multiplyInv(Vector3f vec); + + void multiply(float s); + void interpolate(Quaternion quaternionEnd, float ease); float dot(Quaternion other); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index 5783d6d..211a907 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -3,6 +3,7 @@ import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector3i; +import fr.radi3nt.maths.components.vectors.Vector4f; import java.util.Objects; @@ -33,6 +34,10 @@ public SimpleVector3f(Vector3D multiply) { this((float) multiply.getX(), (float) multiply.getY(), (float) multiply.getZ()); } + public SimpleVector3f(Vector4f vector4f) { + this(vector4f.getX(), vector4f.getY(), vector4f.getZ()); + } + @Override public float getX() { return x; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 38f10c3..ec60cd6 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -17,6 +17,13 @@ public SimpleVector4f(float x, float y, float z, float w) { this.w = w; } + public SimpleVector4f(Vector3f vec, float w) { + this.x = vec.getX(); + this.y = vec.getY(); + this.z = vec.getZ(); + this.w = w; + } + public SimpleVector4f() { } From 220634e67a48445af2bf270f57e807532fd9f3a5 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Mon, 17 Apr 2023 23:19:00 +0200 Subject: [PATCH 028/125] Improved matrix creation performance by not filling the *empty* array with zeros --- .../advanced/matrix/ArrayMatrix4x4.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index a156773..224e98a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -14,7 +14,6 @@ public class ArrayMatrix4x4 implements Matrix4x4 { private final float[][] m = new float[4][4]; public ArrayMatrix4x4(fr.radi3nt.maths.components.matrices.Matrix copy) { - zero(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { set(i, j, copy.get(i, j)); @@ -23,7 +22,15 @@ public ArrayMatrix4x4(fr.radi3nt.maths.components.matrices.Matrix copy) { } public ArrayMatrix4x4() { - zero(); + + } + + public ArrayMatrix4x4(ArrayMatrix4x4 copy) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + set(i, j, copy.get(i, j)); + } + } } public static ArrayMatrix4x4 newIdentity() { @@ -146,9 +153,7 @@ public void set(int x, int y, float value) { @Override public Matrix4x4 duplicate() { - ArrayMatrix4x4 arrayMatrix = new ArrayMatrix4x4(); - arrayMatrix.copy(this); - return arrayMatrix; + return new ArrayMatrix4x4(this); } @Override From 99ba54d7de16e4ddd56cb86e26aea28e5187b96f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Mon, 17 Apr 2023 23:19:19 +0200 Subject: [PATCH 029/125] Added useful methods in Vector3D --- .../main/java/fr/radi3nt/maths/components/Vector3D.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java index f0f7b1f..30fb179 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java @@ -1,5 +1,7 @@ package fr.radi3nt.maths.components; +import fr.radi3nt.maths.components.vectors.Vector3f; + import static fr.radi3nt.maths.Maths.EPSILON; public class Vector3D implements Cloneable { @@ -32,6 +34,12 @@ public Vector3D(float x, float y, float z) { this.z = z; } + public Vector3D(Vector3f vector) { + this.x = vector.getX(); + this.y = vector.getX(); + this.z = vector.getX(); + } + public Vector3D add(Vector3D vec) { this.x += vec.x; this.y += vec.y; From a3e046701550956e642b0e1419ef6d075a08681c Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 23 Apr 2023 00:49:34 +0200 Subject: [PATCH 030/125] Added copy method to Quaternion --- .../advanced/quaternions/ComponentsQuaternion.java | 8 ++++++++ .../maths/components/advanced/quaternions/Quaternion.java | 2 ++ 2 files changed, 10 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index e6cac92..7916a71 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -186,6 +186,14 @@ public Quaternion duplicate() { return new ComponentsQuaternion(x, y, z, w); } + @Override + public void copy(Quaternion rotation) { + this.x = rotation.getX(); + this.y = rotation.getY(); + this.z = rotation.getZ(); + this.w = rotation.getW(); + } + @Override public void add(Quaternion quaternion) { this.x += quaternion.getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index af35a9f..1dd107b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -33,4 +33,6 @@ public interface Quaternion { Quaternion getConjugate(); Quaternion duplicate(); + + void copy(Quaternion rotation); } From f451c85ef573c06c4409e5c55425a9476038e500 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 23 Apr 2023 00:49:53 +0200 Subject: [PATCH 031/125] Added preset angles to JavaMathAngle --- .../maths/components/advanced/matrix/angle/JavaMathAngle.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java index d853289..b29399f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java @@ -2,6 +2,9 @@ public class JavaMathAngle implements Angle { + public static final Angle POSITIVE_RIGHT_ANGLE = JavaMathAngle.fromDegree(90); + public static final Angle NEAGTIVE_RIGHT_ANGLE = JavaMathAngle.fromDegree(-90); + private double angleValueInRadiant; private JavaMathAngle(double angleValueInRadiant) { From 3049a91648f1aede8943281345a0be2773f31350 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 23 Apr 2023 00:51:40 +0200 Subject: [PATCH 032/125] Fixed quaternion multiplication --- .../advanced/quaternions/ComponentsQuaternion.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 7916a71..86bfe52 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -94,10 +94,10 @@ public void multiply(Quaternion quaternion) { float otherY = quaternion.getY(); float otherZ = quaternion.getZ(); - float w = -this.x * otherW + this.y * otherZ - this.z * otherY + this.w * otherX; - float x = this.x * otherZ + this.y * otherW + this.z * otherX + this.w * otherY; - float y = -this.x * otherY - this.y * otherX + this.z * otherW + this.w * otherZ; - float z = this.x * otherX - this.y * otherY - this.z * otherZ + this.w * otherW; + float w = -this.x * otherX - this.y * otherY - this.z * otherZ + this.w * otherW; + float x = this.x * otherW + this.y * otherZ + this.z * otherY + this.w * otherX; + float y = -this.x * otherZ - this.y * otherW + this.z * otherX + this.w * otherY; + float z = this.x * otherY - this.y * otherX - this.z * otherW + this.w * otherZ; this.x = x; this.y = y; From 30bfa462e430b5d957fa99d789864d572cbc7420 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 May 2023 17:41:30 +0200 Subject: [PATCH 033/125] Added DataStructures module --- DataStructures/.gitignore | 38 ++++++++++++++++++++++++++++++++++++++ DataStructures/pom.xml | 20 ++++++++++++++++++++ pom.xml | 1 + 3 files changed, 59 insertions(+) create mode 100644 DataStructures/.gitignore create mode 100644 DataStructures/pom.xml diff --git a/DataStructures/.gitignore b/DataStructures/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/DataStructures/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/DataStructures/pom.xml b/DataStructures/pom.xml new file mode 100644 index 0000000..adb58a6 --- /dev/null +++ b/DataStructures/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + DataStructures + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index ae7bb1b..8ecf03c 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ NoiseHelper BehaviorTree LanguageHelperV2 + DataStructures From f45ccaa0af0577d23648125f446f473da047076f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 May 2023 17:41:50 +0200 Subject: [PATCH 034/125] Added SparseArray to DataStructures module --- .../radi3nt/data/collections/SparseArray.java | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java diff --git a/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java b/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java new file mode 100644 index 0000000..f362e91 --- /dev/null +++ b/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java @@ -0,0 +1,219 @@ +package fr.radi3nt.data.collections; + +public class SparseArray { + + private static final Object DELETED = new Object(); + private static final int DEFAULT_CAPACITY = 10; + private boolean garbage = false; + + private int[] keys; + private Object[] values; + private int size; + + public SparseArray() { + this(DEFAULT_CAPACITY); + } + + public SparseArray(int initialCapacity) { + if (initialCapacity == 0) { + keys = new int[0]; + values = new Object[0]; + } else { + values = new Object[initialCapacity]; + keys = new int[values.length]; + } + size = 0; + } + + public T get(int key) { + return getOrDefault(key, null); + } + + @SuppressWarnings("unchecked") + public T getOrDefault(int key, T valueIfKeyNotFound) { + int i = binarySearch(keys, size, key); + if (i < 0 || values[i] == DELETED) { + return valueIfKeyNotFound; + } else { + return (T) values[i]; + } + } + + public void put(int key, T value) { + int i = binarySearch(keys, size, key); + if (i >= 0) { + values[i] = value; + } else { + i = ~i; + if (i < size && values[i] == DELETED) { + keys[i] = key; + values[i] = value; + return; + } + if (garbage && size >= keys.length) { + performGC(); + i = ~binarySearch(keys, size, key); + } + keys = insert(keys, size, i, key); + values = insert(values, size, i, value); + size++; + } + } + + public void remove(int key) { + int i = binarySearch(keys, size, key); + if (i >= 0) { + if (values[i] != DELETED) { + values[i] = DELETED; + garbage = true; + } + } + } + + public void removeAt(int index) { + if (values[index] != DELETED) { + values[index] = DELETED; + garbage = true; + } + } + + public int keyAt(int index) { + if (garbage) { + performGC(); + } + return keys[index]; + } + + @SuppressWarnings("unchecked") + public T valueAt(int index) { + if (garbage) { + performGC(); + } + return (T) values[index]; + } + + public void setValueAt(int index, T value) { + if (garbage) { + performGC(); + } + values[index] = value; + } + + public void clear() { + int n = size; + Object[] valArray = values; + for (int i = 0; i < n; i++) { + valArray[i] = null; + } + size = 0; + garbage = false; + } + + public int size() { + if (garbage) { + performGC(); + } + return size; + } + + public boolean isEmpty() { + return size() == 0; + } + + /** + * Method to perform GC + */ + private void performGC() { + int n = size; + int position = 0; + int[] keyArray = keys; + Object[] valArray = values; + + for (int i = 0; i < n; i++) { + Object val = valArray[i]; + if (val != DELETED) { + if (i != position) { + keyArray[position] = keyArray[i]; + valArray[position] = val; + valArray[i] = null; + } + position++; + } + garbage = false; + size = position; + } + + } + + /** + * Method to insert an element at a given index + * + * @param array + * @param currentSize + * @param index + * @param element + * @return {@link Object[]} + */ + private Object[] insert(Object[] array, int currentSize, int index, T element) { + assert currentSize <= array.length; + if (currentSize + 1 <= array.length) { + System.arraycopy(array, index, array, index + 1, currentSize - index); + array[index] = element; + return array; + } + Object[] newArray = new Object[currentSize * 2]; + System.arraycopy(array, 0, newArray, 0, index); + newArray[index] = element; + System.arraycopy(array, index, newArray, index + 1, array.length - index); + return newArray; + } + + /** + * Method to insert an integer at given index + * + * @param array + * @param currentSize + * @param index + * @param element + * @return {@link int[]} + */ + private static int[] insert(int[] array, int currentSize, int index, int element) { + assert currentSize <= array.length; + if (currentSize + 1 <= array.length) { + System.arraycopy(array, index, array, index + 1, currentSize - index); + array[index] = element; + return array; + } + int[] newArray = new int[currentSize * 2]; + System.arraycopy(array, 0, newArray, 0, index); + newArray[index] = element; + System.arraycopy(array, index, newArray, index + 1, array.length - index); + return newArray; + } + + /** + * Method to do a binary search on int array + * + * @param array + * @param size + * @param value + * @return {@link int} + */ + public static int binarySearch(int[] array, int size, int value) { + int lo = 0; + int hi = size - 1; + while (lo <= hi) { + final int mid = (lo + hi) >>> 1; + final int midVal = array[mid]; + if (midVal < value) { + lo = mid + 1; + } else if (midVal > value) { + hi = mid - 1; + } else { + return mid; + } + } + return ~lo; + } + +} \ No newline at end of file From aa3c650e608722459430009673acb88f3fdd2d04 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 May 2023 17:47:10 +0200 Subject: [PATCH 035/125] Added components of arbitrary size --- .../maths/components/arbitrary/MatrixNxN.java | 29 +++ .../maths/components/arbitrary/VectorNf.java | 19 ++ .../arbitrary/matrix/ArrayMatrixNxN.java | 162 +++++++++++++ .../arbitrary/matrix/sparse/SparseBlock.java | 47 ++++ .../arbitrary/matrix/sparse/SparseMatrix.java | 218 ++++++++++++++++++ .../arbitrary/vector/ArrayVectorNf.java | 51 ++++ .../arbitrary/vector/ExtensibleVectorNf.java | 63 +++++ 7 files changed, 589 insertions(+) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java new file mode 100644 index 0000000..eff3530 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java @@ -0,0 +1,29 @@ +package fr.radi3nt.maths.components.arbitrary; + +import java.util.BitSet; + +public interface MatrixNxN { + + float get(int x, int y); + + void set(int x, int y, float value); + + int getWidth(); + + int getHeight(); + + BitSet nonZero(); + + float[] getM(); + + MatrixNxN multiply(MatrixNxN matrixNxN); + + MatrixNxN multiplyTransposed(MatrixNxN matrixNxN); + + MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN); + + VectorNf transform(VectorNf vec); + + MatrixNxN duplicate(); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java new file mode 100644 index 0000000..c2cb5ee --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java @@ -0,0 +1,19 @@ +package fr.radi3nt.maths.components.arbitrary; + +import fr.radi3nt.maths.components.vectors.Vector; + +public interface VectorNf extends Vector { + + float get(int row); + + void set(int row, float v); + + void add(int row, float v); + + void div(int row, float v); + + void clamp(int row, float min, float max); + + int size(); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java new file mode 100644 index 0000000..27c2946 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java @@ -0,0 +1,162 @@ +package fr.radi3nt.maths.components.arbitrary.matrix; + +import fr.radi3nt.maths.components.arbitrary.MatrixNxN; +import fr.radi3nt.maths.components.arbitrary.VectorNf; +import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNf; + +import java.util.Arrays; +import java.util.BitSet; + +public class ArrayMatrixNxN implements MatrixNxN { + + private final int width; + private final int height; + private final float[] m; + private final BitSet zeroSet; + + public ArrayMatrixNxN(int width, int height) { + this.width = width; + this.height = height; + m = new float[width * height]; + zeroSet = new BitSet(this.width * this.height); + } + + protected ArrayMatrixNxN(int width, int height, float[] m) { + this.width = width; + this.height = height; + this.m = m; + zeroSet = new BitSet(this.width * this.height); + } + + @Override + public ArrayMatrixNxN multiply(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getHeight()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); + + int resultWidth = matrixNxN.getWidth(); + int resultHeight = this.height; + + BitSet nonZero = matrixNxN.nonZero(); + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int y = 0; y < result.height; y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + if (nonZero.get(x + i * matrixNxN.getWidth())) + total += this.get(i, y) * matrixNxN.get(x, i); + } + result.set(x, y, total); + } + } + + return result; + } + + @Override + public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = this.height; + int resultHeight = matrixNxN.getHeight(); + + BitSet nonZero = matrixNxN.nonZero(); + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int y = 0; y < result.height; y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + if (nonZero.get(i + y * matrixNxN.getWidth())) + total += this.get(i, x) * matrixNxN.get(i, y); + } + result.set(x, y, total); + } + } + + return result; + } + + @Override + public MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = matrixNxN.getHeight(); + int resultHeight = this.getHeight(); + + BitSet nonZero = this.nonZero(); + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int y = 0; y < result.height; y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + if (nonZero.get(i + y * this.getWidth())) + total += matrixNxN.get(i, x) * this.get(i, y); + } + result.set(x, y, total); + } + } + + return result; + } + + @Override + public float get(int x, int y) { + return m[x + y * width]; + } + + @Override + public void set(int x, int y, float value) { + m[x + y * width] = value; + zeroSet.set(x + y * width, value != 0); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + @Override + public BitSet nonZero() { + return zeroSet; + } + + @Override + public ArrayMatrixNxN duplicate() { + return new ArrayMatrixNxN(width, height, Arrays.copyOf(m, m.length)); + } + + public float[] getM() { + return m; + } + + @Override + public VectorNf transform(VectorNf vec) { + VectorNf result = new ArrayVectorNf(height); + + for (int y = 0; y < height; y++) { + float yi = 0; + for (int x = 0; x < width; x++) { + yi += get(x, y) * vec.get(x); + } + result.set(y, yi); + } + + return result; + } + + @Override + public String toString() { + return "ArrayMatrixNxN{" + + "width=" + width + + ", height=" + height + + ", m=" + Arrays.toString(m) + + '}'; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java new file mode 100644 index 0000000..8756626 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java @@ -0,0 +1,47 @@ +package fr.radi3nt.maths.components.arbitrary.matrix.sparse; + +public class SparseBlock { + + private final int startI; + private final int startJ; + private final int lengthI; + private final int lengthJ; + + private final float[] values; + + public SparseBlock(int startI, int startJ, int lengthI, int lengthJ, float[] values) { + this.startI = startI; + this.startJ = startJ; + this.lengthI = lengthI; + this.lengthJ = lengthJ; + this.values = values; + } + + public float get(int i, int j) { + return values[(i - startI) + (j - startJ) * lengthI]; + } + + public int getStartI() { + return startI; + } + + public int getStartJ() { + return startJ; + } + + public int getLengthI() { + return lengthI; + } + + public int getLengthJ() { + return lengthJ; + } + + public float[] getValues() { + return values; + } + + public boolean isInBound(int x, int y) { + return x >= startI && y >= startJ && x < startI + lengthI && y < startJ + lengthJ; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java new file mode 100644 index 0000000..bce5c85 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java @@ -0,0 +1,218 @@ +package fr.radi3nt.maths.components.arbitrary.matrix.sparse; + +import fr.radi3nt.maths.components.arbitrary.MatrixNxN; +import fr.radi3nt.maths.components.arbitrary.VectorNf; +import fr.radi3nt.maths.components.arbitrary.matrix.ArrayMatrixNxN; +import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNf; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; + +public class SparseMatrix implements MatrixNxN { + + private final Collection sparseBlocks; + private int width; + private int height; + + public SparseMatrix(Collection sparseBlocks, int width, int height) { + this.sparseBlocks = sparseBlocks; + this.width = width; + this.height = height; + } + + + public SparseMatrix() { + this(new ArrayList<>(), 0, 0); + } + + public void add(SparseBlock sparseBlock) { + sparseBlocks.add(sparseBlock); + computeCursors(sparseBlock); + } + + private void computeCursors(SparseBlock sparseBlock) { + width = Math.max(width, sparseBlock.getStartI() + sparseBlock.getLengthI()); + height = Math.max(height, sparseBlock.getStartJ() + sparseBlock.getLengthJ()); + } + + @Override + public float get(int x, int y) { + for (SparseBlock sparseBlock : sparseBlocks) { + if (sparseBlock.isInBound(x, y)) { + return sparseBlock.get(x, y); + } + } + return 0; + } + + @Override + public void set(int x, int y, float value) { + throw new UnsupportedOperationException(); + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public BitSet nonZero() { + BitSet bitSet = new BitSet(width * height); + //bitSet.set(0, width*height); + + for (SparseBlock sparseBlock : sparseBlocks) { + for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { + int row = j * width; + bitSet.set(sparseBlock.getStartI() + row, sparseBlock.getStartI() + sparseBlock.getLengthI() + row); + } + } + + return bitSet; + } + + @Override + public float[] getM() { + throw new UnsupportedOperationException(); + } + + public VectorNf transform(VectorNf vector) { + VectorNf result = new ArrayVectorNf(height); + for (SparseBlock sparseBlock : sparseBlocks) { + for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { + for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { + float value = sparseBlock.get(i, j); + result.add(j, value * vector.get(i)); + } + } + } + return result; + } + + public VectorNf transformTransposed(VectorNf vector) { + VectorNf result = new ArrayVectorNf(width); + for (SparseBlock sparseBlock : sparseBlocks) { + for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { + for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { + float value = sparseBlock.get(i, j); + result.add(i, value * vector.get(j)); + } + } + } + return result; + } + + @Override + public MatrixNxN duplicate() { + return new SparseMatrix(new ArrayList<>(sparseBlocks), width, height); + } + + @Override + public MatrixNxN multiply(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getHeight()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); + + int resultWidth = matrixNxN.getWidth(); + int resultHeight = this.height; + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + + for (SparseBlock sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { + for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { + float total = 0; + for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { + total += sparseBlock.get(i, y) * matrixNxN.get(x, i); + } + result.set(x, y, total); + } + } + } + + /* + + for (int x = 0; x < result.getWidth(); x++) { + for (int y = 0; y < result.getHeight(); y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + total+=this.get(i, y) * matrixNxN.get(x, i); + } + result.set(x, y, total); + } + } + */ + + return result; + } + + @Override + public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = this.height; + int resultHeight = matrixNxN.getHeight(); + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + + for (SparseBlock sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { + for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { + float total = 0; + for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { + total += sparseBlock.get(i, x) * + matrixNxN.get(i, y); + } + result.set(x, y, total); + } + } + } + + /* + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + for (int x = 0; x < result.getWidth(); x++) { + for (int y = 0; y < result.getHeight(); y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + total+=this.get(i, x) * + matrixNxN.get(i, y); + } + result.set(x, y, total); + } + } + + */ + + return result; + } + + @Override + public MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = matrixNxN.getHeight(); + int resultHeight = this.getHeight(); + + ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + + + for (SparseBlock sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { + for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { + for (int i = 0; i < matrixNxN.getHeight(); i++) { + float total = matrixNxN.get(x, i) * sparseBlock.get(x, y); + result.set(y, i, result.get(y, i) + total); + } + } + } + } + + return result; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java new file mode 100644 index 0000000..2ce89e0 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java @@ -0,0 +1,51 @@ +package fr.radi3nt.maths.components.arbitrary.vector; + +import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.VectorNf; + +import java.util.Arrays; + +public class ArrayVectorNf implements VectorNf { + + private final float[] vector; + + public ArrayVectorNf(int size) { + vector = new float[size]; + } + + @Override + public float length() { + throw new UnsupportedOperationException("Not implemented"); + } + + public int size() { + return vector.length; + } + + public float get(int row) { + return vector[row]; + } + + public void set(int row, float v) { + vector[row] = v; + } + + public void add(int row, float v) { + vector[row] += v; + } + + public void div(int row, float v) { + vector[row] /= v; + } + + public void clamp(int row, float min, float max) { + vector[row] = Maths.clamp(vector[row], min, max); + } + + @Override + public String toString() { + return "VectorNf{" + + "vector=" + Arrays.toString(vector) + + '}'; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java new file mode 100644 index 0000000..20c7924 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java @@ -0,0 +1,63 @@ +package fr.radi3nt.maths.components.arbitrary.vector; + +import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.VectorNf; + +import java.util.ArrayList; +import java.util.List; + +public class ExtensibleVectorNf implements VectorNf { + + private final List vector; + + public ExtensibleVectorNf() { + vector = new ArrayList<>(); + } + + @Override + public float length() { + throw new UnsupportedOperationException("Not implemented"); + } + + public int size() { + return vector.size(); + } + + public float get(int row) { + return vector.get(row); + } + + public void set(int row, float v) { + if (row >= vector.size()) + vector.add(row, v); + else + vector.set(row, v); + } + + public void add(float v) { + vector.add(v); + } + + public void add(int row, float v) { + vector.set(row, getOrZero(row) + v); + } + + private Float getOrZero(int row) { + return row < vector.size() ? get(row) : 0; + } + + public void div(int row, float v) { + vector.set(row, getOrZero(row) / v); + } + + public void clamp(int row, float min, float max) { + vector.set(row, Maths.clamp(getOrZero(row), min, max)); + } + + @Override + public String toString() { + return "ExtensibleVectorNf{" + + "vector=" + vector + + '}'; + } +} From 649af9a1ac707adeabd3a6c827e9fe0a70a7fd64 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 May 2023 18:28:51 +0200 Subject: [PATCH 036/125] Added Matrix3x3 --- .../advanced/matrix/ArrayMatrix3x3.java | 310 ++++++++++++++++++ .../components/advanced/matrix/Matrix3x3.java | 34 ++ 2 files changed, 344 insertions(+) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java new file mode 100644 index 0000000..5fbed2a --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -0,0 +1,310 @@ +package fr.radi3nt.maths.components.advanced.matrix; + +import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +import java.util.Arrays; + +public class ArrayMatrix3x3 implements Matrix3x3 { + + private final float[][] m = new float[3][3]; + + public ArrayMatrix3x3() { + + } + + public ArrayMatrix3x3(ArrayMatrix3x3 copy) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + set(i, j, copy.get(i, j)); + } + } + } + + public static ArrayMatrix3x3 newIdentity() { + ArrayMatrix3x3 arrayMatrix4x4 = new ArrayMatrix3x3(); + arrayMatrix4x4.identity(); + return arrayMatrix4x4; + } + + @Override + public void identity() { + zero(); + m[0][0] = 1; + m[1][1] = 1; + m[2][2] = 1; + } + + @Override + public void zero() { + for (float[] floats : m) { + Arrays.fill(floats, 0); + } + } + + @Override + public void transpose() { + float m10 = m[0][1]; + float m20 = m[0][2]; + float m01 = m[1][0]; + float m21 = m[1][2]; + float m02 = m[2][0]; + float m12 = m[2][1]; + + m[1][0] = m10; + m[2][0] = m20; + m[0][1] = m01; + m[2][1] = m21; + m[0][2] = m02; + m[1][2] = m12; + } + + @Override + public void negate() { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + m[i][j] = -m[i][j]; + } + } + } + + @Override + public void invert() { + float det = get(0, 0) * (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)) - + get(0, 1) * (get(1, 0) * get(2, 2) - get(1, 2) * get(2, 0)) + + get(0, 2) * (get(1, 0) * get(2, 1) - get(1, 1) * get(2, 0)); + + if (det == 0) + throw new IllegalStateException("Matrix isn't invertible"); + + float invdet = 1.0f / det; + + ArrayMatrix3x3 invM = new ArrayMatrix3x3(); + + set(0, 0, (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)) * invdet); + set(0, 1, (get(0, 2) * get(2, 1) - get(0, 1) * get(2, 2)) * invdet); + set(0, 2, (get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1)) * invdet); + set(1, 0, (get(1, 2) * get(2, 0) - get(1, 0) * get(2, 2)) * invdet); + set(1, 1, (get(0, 0) * get(2, 2) - get(0, 2) * get(2, 0)) * invdet); + set(1, 2, (get(1, 0) * get(0, 2) - get(0, 0) * get(1, 2)) * invdet); + set(2, 0, (get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1)) * invdet); + set(2, 1, (get(2, 0) * get(0, 1) - get(0, 0) * get(2, 1)) * invdet); + set(2, 2, (get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1)) * invdet); + + this.copy(invM); + } + + @Override + public float get(int x, int y) { + return m[x][y]; + } + + @Override + public void set(int x, int y, float value) { + m[x][y] = value; + } + + @Override + public Matrix3x3 duplicate() { + return new ArrayMatrix3x3(this); + } + + @Override + public Quaternion getRotation() { + return getCopySignRotation(); + } + + private Quaternion getCopySignRotation() { + float w = (float) (Math.sqrt(Math.max(0, 1 + m[0][0] + m[1][1] + m[2][2])) / 2); + float x = (float) (Math.sqrt(Math.max(0, 1 + m[0][0] - m[1][1] - m[2][2])) / 2); + float y = (float) (Math.sqrt(Math.max(0, 1 - m[0][0] + m[1][1] - m[2][2])) / 2); + float z = (float) (Math.sqrt(Math.max(0, 1 - m[0][0] - m[1][1] + m[2][2])) / 2); + x *= Math.signum(m[2][1] - m[1][2]); + y *= Math.signum(m[0][2] - m[2][0]); + z *= Math.signum(m[1][0] - m[0][1]); + return new ComponentsQuaternion(x, y, z, w); + } + + @Override + public void add(Matrix3x3 other) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + this.m[i][j] += other.get(i, j); + } + } + } + + @Override + public void scale(Vector3f scale) { + m[0][0] = scale.getX(); + m[1][1] = scale.getY(); + m[2][2] = scale.getZ(); + } + + @Override + public void rotationX(Angle angle) { + m[1][1] = angle.cos(); + m[1][2] = angle.sin(); + m[2][1] = -angle.sin(); + m[2][2] = angle.cos(); + } + + @Override + public void rotationY(Angle angle) { + m[0][0] = angle.cos(); + m[2][0] = angle.sin(); + m[0][2] = -angle.sin(); + m[2][2] = angle.cos(); + } + + @Override + public void rotationZ(Angle angle) { + m[0][0] = angle.cos(); + m[0][1] = angle.sin(); + m[1][0] = -angle.sin(); + m[1][1] = angle.cos(); + } + + @Override + public void eulerRotation(Angle x, Angle y, Angle z) { + float cosX = x.cos(); + float sinX = x.sin(); + float cosY = y.cos(); + float sinY = y.sin(); + float cosZ = z.cos(); + float sinZ = z.sin(); + + float cosXsinY = cosX * sinY; + float sinXsinY = sinX * sinY; + + m[0][0] = cosY * cosZ; + m[0][1] = -cosY * sinZ; + m[0][2] = sinY; + m[1][0] = sinXsinY * cosZ + cosX * sinZ; + m[1][1] = -sinXsinY * sinZ + cosX * cosZ; + m[1][2] = -sinX * cosY; + m[2][0] = -cosXsinY * cosZ + sinX * sinZ; + m[2][1] = cosXsinY * sinZ + sinX * cosZ; + m[2][2] = cosX * cosY; + } + + @Override + public void quaternionRotation(Quaternion quaternion) { + float x = quaternion.getX(); + float y = quaternion.getY(); + float z = quaternion.getZ(); + + float rotationValue = quaternion.getW(); + + float xx = x * x; + float xy = x * y; + float xz = x * z; + float xw = x * rotationValue; + + float yy = y * y; + float yz = y * z; + float yw = y * rotationValue; + + float zz = z * z; + float zw = z * rotationValue; + + + m[0][0] = 1 - 2 * (yy + zz); + m[0][1] = 2 * (xy - zw); + m[0][2] = 2 * (xz + yw); + + m[1][0] = 2 * (xy + zw); + m[1][1] = 1 - 2 * (xx + zz); + m[1][2] = 2 * (yz - xw); + + m[2][0] = 2 * (xz - yw); + m[2][1] = 2 * (yz + xw); + m[2][2] = 1 - 2 * (xx + yy); + } + + @Override + public void directionRotation(Vector3f direction, Vector3f up) { + Vector3f x = up.duplicate().cross(direction); + Vector3f y = direction.duplicate().cross(x); + + x.normalize(); + y.normalize(); + + m[0][0] = x.getX(); + m[0][1] = y.getX(); + m[0][2] = direction.getX(); + m[0][3] = 0; + m[1][0] = x.getY(); + m[1][1] = y.getY(); + m[1][2] = direction.getY(); + m[1][3] = 0; + m[2][0] = x.getZ(); + m[2][1] = y.getZ(); + m[2][2] = direction.getZ(); + } + + @Override + public void transform(Vector3f toTransform) { + float x = m[0][0] * toTransform.getX() + m[1][0] * toTransform.getY() + m[2][0] * toTransform.getZ(); + float y = m[0][1] * toTransform.getX() + m[1][1] * toTransform.getY() + m[2][1] * toTransform.getZ(); + float z = m[0][2] * toTransform.getX() + m[1][2] * toTransform.getY() + m[2][2] * toTransform.getZ(); + toTransform.setX(x); + toTransform.setY(y); + toTransform.setZ(z); + } + + @Override + public void multiply(Matrix matrix) { + Matrix result = new ArrayMatrix3x3(); + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + result.set(x, y, this.get(0, y) * matrix.get(x, 0) + + this.get(1, y) * matrix.get(x, 1) + + this.get(2, y) * matrix.get(x, 2)); + } + } + + this.copy(result); + } + + @Override + public void copy(Matrix result) { + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + set(x, y, result.get(x, y)); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ArrayMatrix3x3 that = (ArrayMatrix3x3) o; + return Arrays.deepEquals(m, that.m); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(m); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder("ArrayMatrix3x3{" + + "\n"); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + stringBuilder.append(m[i][j]).append(" "); + } + stringBuilder.append("\n"); + } + + stringBuilder.append("}"); + + return stringBuilder.toString(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java new file mode 100644 index 0000000..21165a5 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java @@ -0,0 +1,34 @@ +package fr.radi3nt.maths.components.advanced.matrix; + +import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface Matrix3x3 extends Matrix { + + Quaternion getRotation(); + + void add(Matrix3x3 rotation); + + void scale(Vector3f scale); + + void rotationX(Angle angle); + + void rotationY(Angle angle); + + void rotationZ(Angle angle); + + void eulerRotation(Angle x, Angle y, Angle z); + + void quaternionRotation(Quaternion quaternion); + + void directionRotation(Vector3f direction, Vector3f up); + + void transform(Vector3f toTransform); + + void multiply(Matrix matrix); + + void copy(Matrix result); + + Matrix3x3 duplicate(); +} From b7d9705c1c9755932cb54ad94dd158a591e3abca Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 11 May 2023 23:28:10 +0200 Subject: [PATCH 037/125] Added format to toString() for better readability in console --- .../arbitrary/matrix/ArrayMatrixNxN.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java index 27c2946..452d81c 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java @@ -153,10 +153,20 @@ public VectorNf transform(VectorNf vec) { @Override public String toString() { - return "ArrayMatrixNxN{" + - "width=" + width + - ", height=" + height + - ", m=" + Arrays.toString(m) + - '}'; + StringBuilder stringBuilder = new StringBuilder("ArrayMatrixNxN{" + + "\n"); + stringBuilder.append("width=").append(width).append("\n"); + stringBuilder.append("height=").append(height).append("\n"); + + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + stringBuilder.append(get(i, j)).append(" "); + } + stringBuilder.append("\n"); + } + + stringBuilder.append("}"); + + return stringBuilder.toString(); } } From 2bc21e6ff6be9e5f5f19e8ee4af437f7c5e32978 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 11 May 2023 23:28:24 +0200 Subject: [PATCH 038/125] Added SparseArray constructor for duplication --- .../java/fr/radi3nt/data/collections/SparseArray.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java b/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java index f362e91..71588ab 100644 --- a/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java +++ b/DataStructures/src/main/java/fr/radi3nt/data/collections/SparseArray.java @@ -1,5 +1,7 @@ package fr.radi3nt.data.collections; +import java.util.Arrays; + public class SparseArray { private static final Object DELETED = new Object(); @@ -25,6 +27,12 @@ public SparseArray(int initialCapacity) { size = 0; } + public SparseArray(SparseArray array) { + this.keys = Arrays.copyOf(array.keys, array.keys.length); + this.values = Arrays.copyOf(array.values, array.values.length); + this.size = array.size; + } + public T get(int key) { return getOrDefault(key, null); } From 6b4e3ed882fd47e313866ffa1c32e1b0f90a00eb Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 11 Aug 2023 18:41:01 +0200 Subject: [PATCH 039/125] Feature merge (#3) * Added subtract method to Matrix3x3 * Created double components and separated from float components (matrices, vectors) * Added new SimpleVector3f constructor that takes in doubles * Created skew method to create a matrix to perform a vector cross product * Added add method to VectorNd * Added missing methods to get values from row id in Vector3f * Fixed methods inside MatrixNxNd * Generalised transform method in ArrayMatrix3x3 * Added scalar method in VectorNd * Added transformed method in Quaternion to avoid going through matrices * Added unit testing for MatrixNxNd * Fixed small error in quaternionRotation() * Cleaned transform method in ComponentsQuaternion * Added copy constructor * Fixed issues within the Matrix classes (notably multiplyTransposedOther() ) * Added nCopies() method * Added nCopies method for array * Fixed issue in Vector3D * Added test to prevent increment of zero * Sat rework (#1) * Started reworking SAT * Fixed an issue where collision wouldn't get detected if the colliding axis was static from the velocity point of view (dot products) * Added clipping object to allow contact point detection * Removed deprecated class that was replaced with TransformedBoxSAT * Implemented clip planes with SATShapes * Removed unused contact point computation from SatProjection * Added toString method to SatProjection * Added zero quaternion * Added set method to Vector4f * Added set method to Vector3D * Allowed reuse of TransformedBoxSAT * Slight improvement to the SAT framework (which will soon be moved to its own module) * Improved SAT normal computing * Using copy() instead of set() * Remove unused variable * Refactored SatResolver * Splines (#2) * Added SplineHelper module * Refactored splines by introducing controllers (either direct or inferred), which allow after creation spline edition * Moved hybrid splines to other package * Optimised identity() method for matrices * Added setters to Quaternion * Added inverse method to Quaternion * Fixed ComponentQuaternion multiplication * Refactored BehaviorTrees * Added AnimationHelper module * Optimising ArrayMatrixNxNd and SparseMatrixd multiply --- AnimationHelper/.gitignore | 38 ++++ AnimationHelper/pom.xml | 40 ++++ .../java/fr/radi3nt/animations/Animation.java | 8 + .../animations/channels/AnimationChannel.java | 7 + .../channels/ChanneledAnimation.java | 33 +++ .../AbstractTransformAnimationChannel.java | 31 +++ ...odularObjectTransformAnimationChannel.java | 64 ++++++ .../ParentTransformAnimationChannel.java | 9 + .../object/TransformAnimationChannel.java | 11 + .../rotation/QuaternionAnimationChannel.java | 24 +++ .../QuaternionObjectInterpolation.java | 22 ++ .../RotationXEulerAnimationChannel.java | 26 +++ .../RotationYEulerAnimationChannel.java | 26 +++ .../RotationZEulerAnimationChannel.java | 26 +++ .../object/scale/ScaleAnimationChannel.java | 21 ++ .../scale/ScaleObjectInterpolation.java | 20 ++ .../scale/ScaleSeparatedAnimationChannel.java | 27 +++ .../TranslationAnimationChannel.java | 25 +++ .../TranslationObjectInterpolation.java | 20 ++ .../TranslationSeparatedAnimationChannel.java | 28 +++ .../channels/single/FloatInterpolation.java | 20 ++ .../anim/AnimFormatAnimationImporter.java | 55 +++++ .../anim/animation/AnimationBody.java | 26 +++ .../anim/animation/AnimationBodyBuilder.java | 10 + .../animation/AnimationChannelBuilder.java | 10 + .../FailureSafeAnimationBodyBuilder.java | 108 ++++++++++ .../anim/animation/data/AnimData.java | 64 ++++++ .../anim/animation/data/ChannelInfo.java | 33 +++ .../anim/animation/data/ChannelType.java | 9 + .../animation/data/key/CurveHandleData.java | 28 +++ .../animation/data/key/InterpolationType.java | 12 ++ .../anim/animation/data/key/KeyData.java | 69 ++++++ .../animation/data/key/KeyframesData.java | 32 +++ .../spline/BezierKeyedSplineBuilder.java | 67 ++++++ .../spline/CurveHandleDataBuilder.java | 13 ++ .../animation/spline/KeyedSplineBuilder.java | 12 ++ .../spline/handle/AutoHandleDataBuilder.java | 11 + .../spline/handle/FixedHandleDataBuilder.java | 19 ++ .../handle/GeneratedHandleDataBuilder.java | 63 ++++++ .../anim/content/AnimFileContent.java | 10 + .../anim/content/ReadableAnimFileContent.java | 59 +++++ .../importing/anim/header/AnimHeader.java | 73 +++++++ .../anim/header/AnimHeaderBuilder.java | 9 + .../header/FailureSafeAnimHeaderBuilder.java | 47 ++++ .../importing/anim/units/AngularUnit.java | 10 + .../importing/anim/units/AnimUnit.java | 4 + .../importing/anim/units/LinearUnit.java | 14 ++ .../importing/anim/units/TimeUnit.java | 27 +++ .../importing/anim/units/UnitType.java | 10 + .../object/ObjectInterpolation.java | 7 + .../timing/EasingInterpolationTiming.java | 17 ++ .../timing/InterpolationTiming.java | 7 + .../timing/ShiftedInterpolationTiming.java | 17 ++ .../timing/Spline2DInterpolationTiming.java | 73 +++++++ .../timing/SplineInterpolationTiming.java | 17 ++ .../timeline/state/AnimatedState.java | 11 + .../timeline/state/SplineAnimatedState.java | 34 +++ .../timeline/state/TypedAnimatedState.java | 39 ++++ .../timeline/time/ChannelTimeline.java | 7 + .../timeline/time/SetAnimationTimeline.java | 15 ++ .../timeline/time/TypedChannelTimeline.java | 66 ++++++ .../behavior/blackboard/Blackboard.java | 9 - .../blackboard/BlackboardContext.java | 7 - .../blackboard/BlackboardVariableId.java | 6 - .../behavior/blackboard/MapBlackboard.java | 19 -- .../blackboard/SetBlackboardContext.java | 15 -- .../{TreeNode.java => BehaviorTreeNode.java} | 2 +- .../tree/nodes/composite/CompositeNode.java | 29 ++- .../tree/nodes/composite/FallbackNode.java | 19 +- .../tree/nodes/composite/SequenceNode.java | 22 +- .../tree/nodes/decoration/DecorationNode.java | 18 +- .../tree/nodes/decoration/FailureNode.java | 11 +- .../tree/nodes/decoration/ForNode.java | 25 --- .../tree/nodes/decoration/InverterNode.java | 11 +- .../tree/nodes/decoration/SuccessNode.java | 8 +- .../tree/nodes/decoration/WhileNode.java | 22 -- .../decoration/loops/WhileFailureNode.java | 23 ++ .../loops/WhileFailureOrLimitNode.java | 26 +++ .../behavior/tree/nodes/leaf/ActionNode.java | 4 +- .../nodes/leaf/condition/ConditionalNode.java | 4 +- .../tree/nodes/types/CollectionNode.java | 14 -- .../variable/CompleteNodeVariable.java | 4 + .../variable/EncapsulatingNodeVariable.java | 15 -- .../behavior/variable/InputNodeVariable.java | 7 + .../behavior/variable/NodeVariable.java | 2 - .../behavior/variable/OutputNodeVariable.java | 7 + .../EncapsulatingInputNodeVariable.java | 17 ++ .../EncapsulatingOutputNodeVariable.java | 17 ++ .../{ => impl}/DirectNodeVariable.java | 9 +- MathsHelper/pom.xml | 8 + .../src/main/java/fr/radi3nt/maths/Maths.java | 38 +++- .../radi3nt/maths/components/MatrixNxNd.java | 31 +++ .../fr/radi3nt/maths/components/Vector3D.java | 6 +- .../advanced/matrix/ArrayMatrix3x3.java | 46 ++-- .../advanced/matrix/ArrayMatrix4x4.java | 22 +- .../components/advanced/matrix/Matrix3x3.java | 2 + .../quaternions/ComponentsQuaternion.java | 79 ++++++- .../advanced/quaternions/Quaternion.java | 12 ++ .../{MatrixNxN.java => MatrixNxNf.java} | 10 +- .../maths/components/arbitrary/VectorNd.java | 24 +++ .../arbitrary/matrix/ArrayMatrixNxNd.java | 201 +++++++++++++++++ ...rayMatrixNxN.java => ArrayMatrixNxNf.java} | 33 ++- .../arbitrary/matrix/sparse/SparseBlockd.java | 69 ++++++ .../{SparseBlock.java => SparseBlockf.java} | 18 +- .../matrix/sparse/SparseMatrixd.java | 202 ++++++++++++++++++ .../{SparseMatrix.java => SparseMatrixf.java} | 46 ++-- .../arbitrary/vector/ArrayVectorNd.java | 79 +++++++ .../arbitrary/vector/ExtensibleVectorNd.java | 84 ++++++++ .../maths/components/vectors/Vector3f.java | 6 + .../maths/components/vectors/Vector4f.java | 2 + .../implementations/SimpleVector3f.java | 30 +++ .../implementations/SimpleVector4f.java | 8 + .../fr/radi3nt/maths/sat/SatResolver.java | 35 ++- .../maths/sat/clip/AxisAndVertexIndex.java | 22 ++ .../fr/radi3nt/maths/sat/clip/ClipPlane.java | 49 +++++ .../fr/radi3nt/maths/sat/clip/ClipPlanes.java | 36 ++++ .../java/fr/radi3nt/maths/sat/clip/Edge.java | 22 ++ .../radi3nt/maths/sat/components/SatAxis.java | 1 - .../radi3nt/maths/sat/components/SatEdge.java | 4 +- .../maths/sat/projection/OverlapInfo.java | 20 ++ .../maths/sat/projection/SatProjection.java | 74 +++++-- .../fr/radi3nt/maths/sat/shape/BoxSAT.java | 48 +++++ .../fr/radi3nt/maths/sat/shape/ObbSAT.java | 54 ----- .../maths/sat/shape/TransformedBoxSAT.java | 143 +++++++++++++ .../maths/sat/shape/VerticesSATShape.java | 14 +- .../shape/triangles/ComputingTriangleSAT.java | 23 ++ .../shape/triangles/StoringTriangleSAT.java | 23 ++ .../sat/swept/CheepSweptSatResolver.java | 49 +++-- .../sat/swept/EconomicSweptSatResolver.java | 21 +- .../radi3nt/maths/sat/swept/SweptResult.java | 38 +++- .../maths/sat/swept/SweptSatResolver.java | 19 +- .../arbitrary/matrix/ArrayMatrixNxNdTest.java | 164 ++++++++++++++ .../matrix/sparse/SparseMatrixdTest.java | 22 ++ SplineHelper/.gitignore | 38 ++++ SplineHelper/pom.xml | 28 +++ .../fr/radi3nt/spline/MainSplineTesting.java | 36 ++++ .../spline/curve/CharacteristicCurve.java | 19 ++ .../java/fr/radi3nt/spline/curve/Curve.java | 8 + .../curve/controller/CurveController.java | 7 + .../radi3nt/spline/curve/curves/BCurve.java | 27 +++ .../spline/curve/curves/CubicBezierCurve.java | 31 +++ .../spline/curve/curves/HermiteCurve.java | 31 +++ .../curve/curves/cardinal/CardinalCurve.java | 27 +++ .../cardinal/CardinalCurveController.java | 14 ++ .../curves/cardinal/CatmullRomCurve.java | 27 +++ .../spline/splines/CollectionSpline.java | 51 +++++ .../fr/radi3nt/spline/splines/Spline.java | 8 + .../builder/PositionnedSplineController.java | 7 + .../spline/splines/builder/SplineBuilder.java | 9 + .../splines/builder/SplineController.java | 4 + .../builder/bezier/dim1/BezierPoint.java | 26 +++ .../dim1/CubicBezierCurveController.java | 11 + .../bezier/dim1/CubicBezierSplineBuilder.java | 34 +++ .../dim1/CubicBezierSplineController.java | 21 ++ .../DirectCubicBezierCurveController.java | 37 ++++ .../InferredCubicBezierCurveController.java | 33 +++ .../builder/bezier/dim2/BezierPoint2D.java | 26 +++ .../dim2/CubicBezierSplineBuilder2D.java | 34 +++ .../dim2/CubicBezierSplineController2D.java | 18 ++ .../cardinal/dim1/CardinalSplineBuilder.java | 34 +++ .../dim1/CardinalSplineController.java | 32 +++ .../dim1/DirectCardinalCurveController.java | 45 ++++ .../dim1/InferredCardinalCurveController.java | 48 +++++ .../dim3/CardinalSplineBuilder3D.java | 36 ++++ .../dim3/CardinalSplineController3D.java | 26 +++ .../dimensions/EncapsulatingSpline2D.java | 46 ++++ .../dimensions/EncapsulatingSpline3D.java | 33 +++ .../spline/splines/dimensions/Spline2D.java | 10 + .../spline/splines/dimensions/Spline3D.java | 10 + .../cardinal/CardinalUsingHermitSpline.java | 43 ++++ .../splines/hybrid/hermite/HermiteSpline.java | 32 +++ pom.xml | 2 + 172 files changed, 4638 insertions(+), 420 deletions(-) create mode 100644 AnimationHelper/.gitignore create mode 100644 AnimationHelper/pom.xml create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/content/AnimFileContent.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/content/ReadableAnimFileContent.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/header/AnimHeader.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/header/AnimHeaderBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/header/FailureSafeAnimHeaderBuilder.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AngularUnit.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AnimUnit.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/LinearUnit.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/TimeUnit.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/UnitType.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java create mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/Blackboard.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardContext.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardVariableId.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/MapBlackboard.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/SetBlackboardContext.java rename BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/{TreeNode.java => BehaviorTreeNode.java} (65%) delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/ForNode.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/WhileNode.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureNode.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureOrLimitNode.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/types/CollectionNode.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/CompleteNodeVariable.java delete mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/EncapsulatingNodeVariable.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/InputNodeVariable.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/OutputNodeVariable.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingInputNodeVariable.java create mode 100644 BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingOutputNodeVariable.java rename BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/{ => impl}/DirectNodeVariable.java (52%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java rename MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/{MatrixNxN.java => MatrixNxNf.java} (55%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNd.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java rename MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/{ArrayMatrixNxN.java => ArrayMatrixNxNf.java} (81%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockd.java rename MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/{SparseBlock.java => SparseBlockf.java} (62%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java rename MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/{SparseMatrix.java => SparseMatrixf.java} (82%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNd.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNd.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java create mode 100644 MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java create mode 100644 MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java create mode 100644 SplineHelper/.gitignore create mode 100644 SplineHelper/pom.xml create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java diff --git a/AnimationHelper/.gitignore b/AnimationHelper/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/AnimationHelper/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/AnimationHelper/pom.xml b/AnimationHelper/pom.xml new file mode 100644 index 0000000..de1ef36 --- /dev/null +++ b/AnimationHelper/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + AnimationHelper + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + fr.radi3nt + SplineHelper + 1.0 + compile + + + fr.radi3nt + FileHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java new file mode 100644 index 0000000..d44ac25 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java @@ -0,0 +1,8 @@ +package fr.radi3nt.animations; + +public interface Animation { + + void transform(float time); + float getAnimationTime(); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java new file mode 100644 index 0000000..16c4843 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.channels; + +public interface AnimationChannel { + + void transformation(float time); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java new file mode 100644 index 0000000..9d69989 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java @@ -0,0 +1,33 @@ +package fr.radi3nt.animations.channels; + +import fr.radi3nt.animations.Animation; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ChanneledAnimation implements Animation { + + private final Iterable channels; + private final float animationTime; + + public ChanneledAnimation(Iterable channels, float animationTime) { + this.channels = channels; + this.animationTime = animationTime; + } + + public ChanneledAnimation(float animationTime, AnimationChannel... channels) { + this(new ArrayList<>(Arrays.asList(channels)), animationTime); + } + + @Override + public void transform(float time) { + for (AnimationChannel channel : channels) { + channel.transformation(time); + } + } + + @Override + public float getAnimationTime() { + return animationTime; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java new file mode 100644 index 0000000..c6ea87e --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java @@ -0,0 +1,31 @@ +package fr.radi3nt.animations.channels.object; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public abstract class AbstractTransformAnimationChannel implements TransformAnimationChannel { + + protected final Matrix4x4 transform = ArrayMatrix4x4.newIdentity(); + protected ParentTransformAnimationChannel parent; + + @Override + public void setParent(ParentTransformAnimationChannel transform) { + parent = transform; + } + + @Override + public void transformation(float time) { + applyLocalToParent(); + } + + private void applyLocalToParent() { + if (parent!=null) { + parent.getCurrentTransform().multiply(transform); + } + } + + @Override + public Matrix4x4 getLocalTransform() { + return transform; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java new file mode 100644 index 0000000..32b39d5 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java @@ -0,0 +1,64 @@ +package fr.radi3nt.animations.channels.object; + +import fr.radi3nt.animations.channels.AnimationChannel; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class ModularObjectTransformAnimationChannel extends AbstractTransformAnimationChannel implements ParentTransformAnimationChannel { + + private final Matrix4x4 current = ArrayMatrix4x4.newIdentity(); + private final Collection channels = new ArrayList<>(); + + public ModularObjectTransformAnimationChannel() { + + } + + public ModularObjectTransformAnimationChannel(Collection channels) { + this.channels.addAll(channels); + setChildTransform(); + } + + public ModularObjectTransformAnimationChannel(TransformAnimationChannel... channels) { + this.channels.addAll(Arrays.asList(channels)); + setChildTransform(); + } + + public void addChannel(TransformAnimationChannel channel) { + channel.setParent(this); + channels.add(channel); + } + + public void addChannels(Collection channels) { + this.channels.addAll(channels); + for (TransformAnimationChannel channel : channels) { + channel.setParent(this); + } + } + + @Override + public void transformation(float time) { + transform.identity(); + for (AnimationChannel channel : channels) { + current.identity(); + channel.transformation(time); + transform.multiply(current); + } + if (parent!=null) + parent.getCurrentTransform().multiply(transform); + } + + private void setChildTransform() { + for (TransformAnimationChannel channel : channels) { + channel.setParent(this); + } + } + + @Override + public Matrix4x4 getCurrentTransform() { + return current; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java new file mode 100644 index 0000000..b2e5979 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java @@ -0,0 +1,9 @@ +package fr.radi3nt.animations.channels.object; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public interface ParentTransformAnimationChannel extends TransformAnimationChannel { + + Matrix4x4 getCurrentTransform(); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java new file mode 100644 index 0000000..b7596f4 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java @@ -0,0 +1,11 @@ +package fr.radi3nt.animations.channels.object; + +import fr.radi3nt.animations.channels.AnimationChannel; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public interface TransformAnimationChannel extends AnimationChannel { + + void setParent(ParentTransformAnimationChannel transform); + Matrix4x4 getLocalTransform(); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java new file mode 100644 index 0000000..843c1ff --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java @@ -0,0 +1,24 @@ +package fr.radi3nt.animations.channels.object.rotation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; + +public class QuaternionAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline quaternionTimeline; + + public QuaternionAnimationChannel(ChannelTimeline quaternionTimeline) { + this.quaternionTimeline = quaternionTimeline; + } + + @Override + public void transformation(float time) { + transform.quaternionRotation(quaternionTimeline.state(time)); + super.transformation(time); + } + + public ChannelTimeline getQuaternionTimeline() { + return quaternionTimeline; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java new file mode 100644 index 0000000..bc740d6 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java @@ -0,0 +1,22 @@ +package fr.radi3nt.animations.channels.object.rotation; + +import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; +import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; + +public class QuaternionObjectInterpolation implements ObjectInterpolation { + + private final InterpolationTiming interpolationTiming; + + public QuaternionObjectInterpolation(InterpolationTiming interpolationTiming) { + this.interpolationTiming = interpolationTiming; + } + + @Override + public Quaternion interpolate(Quaternion start, Quaternion end, float t) { + float time = interpolationTiming.getTransformedTime(t); + Quaternion result = start.duplicate(); + result.interpolate(end, time); + return result; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java new file mode 100644 index 0000000..5cbb9f0 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java @@ -0,0 +1,26 @@ +package fr.radi3nt.animations.channels.object.rotation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class RotationXEulerAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline rotationX; + + public RotationXEulerAnimationChannel(ChannelTimeline rotationX) { + this.rotationX = rotationX; + } + + @Override + public void transformation(float time) { + transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(1, 0, 0), JavaMathAngle.fromDegree(rotationX.state(time)))); + super.transformation(time); + } + + public ChannelTimeline getRotationX() { + return rotationX; + } +} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java new file mode 100644 index 0000000..b07a6a9 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java @@ -0,0 +1,26 @@ +package fr.radi3nt.animations.channels.object.rotation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class RotationYEulerAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline rotationY; + + public RotationYEulerAnimationChannel(ChannelTimeline rotationY) { + this.rotationY = rotationY; + } + + @Override + public void transformation(float time) { + transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.fromDegree(rotationY.state(time)))); + super.transformation(time); + } + + public ChannelTimeline getRotationY() { + return rotationY; + } +} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java new file mode 100644 index 0000000..ad776ca --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java @@ -0,0 +1,26 @@ +package fr.radi3nt.animations.channels.object.rotation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class RotationZEulerAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline rotationZ; + + public RotationZEulerAnimationChannel(ChannelTimeline rotationZ) { + this.rotationZ = rotationZ; + } + + @Override + public void transformation(float time) { + transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 0, 1), JavaMathAngle.fromDegree(rotationZ.state(time)))); + super.transformation(time); + } + + public ChannelTimeline getRotationZ() { + return rotationZ; + } +} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java new file mode 100644 index 0000000..3228b07 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java @@ -0,0 +1,21 @@ +package fr.radi3nt.animations.channels.object.scale; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class ScaleAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline translationsTimeline; + + public ScaleAnimationChannel(ChannelTimeline translationsTimeline) { + this.translationsTimeline = translationsTimeline; + } + + @Override + public void transformation(float time) { + transform.scale(translationsTimeline.state(time)); + super.transformation(time); + } + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java new file mode 100644 index 0000000..6de07ff --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java @@ -0,0 +1,20 @@ +package fr.radi3nt.animations.channels.object.scale; + +import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; +import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class ScaleObjectInterpolation implements ObjectInterpolation { + + private final InterpolationTiming interpolationTiming; + + public ScaleObjectInterpolation(InterpolationTiming interpolationTiming) { + this.interpolationTiming = interpolationTiming; + } + + @Override + public Vector3f interpolate(Vector3f start, Vector3f end, float t) { + float time = interpolationTiming.getTransformedTime(t); + return start.duplicate().mul(1-time).add(end.duplicate().mul(time)); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java new file mode 100644 index 0000000..5477656 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java @@ -0,0 +1,27 @@ +package fr.radi3nt.animations.channels.object.scale; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ScaleSeparatedAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline xTimeline; + private final ChannelTimeline yTimeline; + private final ChannelTimeline zTimeline; + + public ScaleSeparatedAnimationChannel(ChannelTimeline xTimeline, ChannelTimeline yTimeline, ChannelTimeline zTimeline) { + this.xTimeline = xTimeline; + this.yTimeline = yTimeline; + this.zTimeline = zTimeline; + } + + @Override + public void transformation(float time) { + Vector3f scale = new SimpleVector3f(xTimeline.state(time), yTimeline.state(time), zTimeline.state(time)); + transform.scale(scale); + super.transformation(time); + } + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java new file mode 100644 index 0000000..3952bd5 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java @@ -0,0 +1,25 @@ +package fr.radi3nt.animations.channels.object.translation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.channels.object.TransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class TranslationAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline translationsTimeline; + private final Matrix4x4 transform = ArrayMatrix4x4.newIdentity(); + private TransformAnimationChannel parent; + + public TranslationAnimationChannel(ChannelTimeline translationsTimeline) { + this.translationsTimeline = translationsTimeline; + } + + @Override + public void transformation(float time) { + transform.translation(translationsTimeline.state(time)); + super.transformation(time); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java new file mode 100644 index 0000000..226b632 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java @@ -0,0 +1,20 @@ +package fr.radi3nt.animations.channels.object.translation; + +import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; +import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class TranslationObjectInterpolation implements ObjectInterpolation { + + private final InterpolationTiming interpolationTiming; + + public TranslationObjectInterpolation(InterpolationTiming interpolationTiming) { + this.interpolationTiming = interpolationTiming; + } + + @Override + public Vector3f interpolate(Vector3f start, Vector3f end, float t) { + float time = interpolationTiming.getTransformedTime(t); + return start.duplicate().mul(1-time).add(end.duplicate().mul(time)); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java new file mode 100644 index 0000000..85861a1 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java @@ -0,0 +1,28 @@ +package fr.radi3nt.animations.channels.object.translation; + +import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; +import fr.radi3nt.animations.timeline.time.ChannelTimeline; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class TranslationSeparatedAnimationChannel extends AbstractTransformAnimationChannel { + + private final ChannelTimeline xTimeline; + private final ChannelTimeline yTimeline; + private final ChannelTimeline zTimeline; + + public TranslationSeparatedAnimationChannel(ChannelTimeline xTimeline, ChannelTimeline yTimeline, ChannelTimeline zTimeline) { + this.xTimeline = xTimeline; + this.yTimeline = yTimeline; + this.zTimeline = zTimeline; + } + + @Override + public void transformation(float time) { + Vector3f translation = new SimpleVector3f(xTimeline.state(time), yTimeline.state(time), zTimeline.state(time)); + transform.translation(translation); + + super.transformation(time); + } + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java new file mode 100644 index 0000000..ecbce5e --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java @@ -0,0 +1,20 @@ +package fr.radi3nt.animations.channels.single; + +import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; +import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; + +public class FloatInterpolation implements ObjectInterpolation { + + private final InterpolationTiming interpolationTiming; + + public FloatInterpolation(InterpolationTiming interpolationTiming) { + this.interpolationTiming = interpolationTiming; + } + + @Override + public Float interpolate(Float start, Float end, float t) { + float time = interpolationTiming.getTransformedTime(t); + return start*(1-time)+end*time; + } + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java new file mode 100644 index 0000000..88e8797 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java @@ -0,0 +1,55 @@ +package fr.radi3nt.animations.importing.anim; + +import fr.radi3nt.animations.importing.anim.animation.AnimationBody; +import fr.radi3nt.animations.importing.anim.animation.AnimationBodyBuilder; +import fr.radi3nt.animations.importing.anim.content.AnimFileContent; +import fr.radi3nt.animations.importing.anim.header.AnimHeader; +import fr.radi3nt.animations.importing.anim.header.AnimHeaderBuilder; + +public class AnimFormatAnimationImporter { + + private final AnimFileContent animFileContent; + private final AnimHeaderBuilder headerBuilder; + private final AnimationBodyBuilder bodyBuilder; + + public AnimFormatAnimationImporter(AnimFileContent animFileContent, AnimHeaderBuilder headerBuilder, AnimationBodyBuilder bodyBuilder) { + this.animFileContent = animFileContent; + this.headerBuilder = headerBuilder; + this.bodyBuilder = bodyBuilder; + } + + public AnimImportedResult importFromContent() { + AnimHeader animHeader = headerBuilder.build(animFileContent); + AnimationBody animationBody = bodyBuilder.build(animFileContent, animHeader); + + return new AnimImportedResult(animHeader, animationBody); + } + + + public static class AnimImportedResult { + + private final AnimHeader header; + private final AnimationBody animationBody; + + public AnimImportedResult(AnimHeader header, AnimationBody animationBody) { + this.header = header; + this.animationBody = animationBody; + } + + public AnimHeader getHeader() { + return header; + } + + public AnimationBody getAnimationBody() { + return animationBody; + } + + @Override + public String toString() { + return "AnimImportedResult{" + + "header=" + header + + ", animationBody=" + animationBody + + '}'; + } + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java new file mode 100644 index 0000000..edb7c85 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java @@ -0,0 +1,26 @@ +package fr.radi3nt.animations.importing.anim.animation; + +import fr.radi3nt.animations.importing.anim.animation.data.AnimData; +import fr.radi3nt.animations.importing.anim.animation.data.ChannelInfo; + +import java.util.Map; + +public class AnimationBody { + + private final Map animData; + + public AnimationBody(Map animData) { + this.animData = animData; + } + + public Map getAnimData() { + return animData; + } + + @Override + public String toString() { + return "AnimationBody{" + + "animData=" + animData + + '}'; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java new file mode 100644 index 0000000..6693cc0 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java @@ -0,0 +1,10 @@ +package fr.radi3nt.animations.importing.anim.animation; + +import fr.radi3nt.animations.importing.anim.content.AnimFileContent; +import fr.radi3nt.animations.importing.anim.header.AnimHeader; + +public interface AnimationBodyBuilder { + + AnimationBody build(AnimFileContent content, AnimHeader header); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java new file mode 100644 index 0000000..cea8634 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java @@ -0,0 +1,10 @@ +package fr.radi3nt.animations.importing.anim.animation; + +import fr.radi3nt.animations.channels.AnimationChannel; +import fr.radi3nt.animations.importing.anim.animation.data.AnimData; + +public interface AnimationChannelBuilder { + + AnimationChannel create(String inputType, String channelName, String objectName, AnimData animData); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java new file mode 100644 index 0000000..08be077 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java @@ -0,0 +1,108 @@ +package fr.radi3nt.animations.importing.anim.animation; + +import fr.radi3nt.animations.importing.anim.animation.data.AnimData; +import fr.radi3nt.animations.importing.anim.animation.data.ChannelInfo; +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyframesData; +import fr.radi3nt.animations.importing.anim.animation.spline.KeyedSplineBuilder; +import fr.radi3nt.animations.importing.anim.content.AnimFileContent; +import fr.radi3nt.animations.importing.anim.header.AnimHeader; +import fr.radi3nt.animations.importing.anim.units.UnitType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FailureSafeAnimationBodyBuilder implements AnimationBodyBuilder { + + private static final String ANIM_STOP_SEGMENT = "keys"; + private static final String INPUT_YPE_PROPERTY_ID = "input"; + private static final String OUTPUT_TYPE_PROPERTY_ID = "output"; + private static final String WEIGHTED_PROPERTY_ID = "weighted"; + private final KeyedSplineBuilder splineBuilder; + + public FailureSafeAnimationBodyBuilder(KeyedSplineBuilder splineBuilder) { + this.splineBuilder = splineBuilder; + } + + @Override + public AnimationBody build(AnimFileContent content, AnimHeader header) { + Map animDataMap = new HashMap<>(); + while (content.hasLine()) { + String line = content.readLine(); + String[] splitLine = line.split(" "); + + if (splitLine.length<=5) + continue; + + String fullChannelType = splitLine[1]; + String mainChannelType = fullChannelType.split("\\.")[0]; + String leafChannelType = splitLine[2]; + + String objectName = splitLine[3]; + + AnimData animData = buildAnimData(content, header); + animDataMap.put(new ChannelInfo(fullChannelType, mainChannelType, leafChannelType, objectName), animData); + } + + return new AnimationBody(animDataMap); + } + + private AnimData buildAnimData(AnimFileContent content, AnimHeader header) { + Map propertyAndValue = new HashMap<>(); + fillAnimProperties(content, propertyAndValue); + + UnitType inputType = UnitType.valueOf(propertyAndValue.getOrDefault(INPUT_YPE_PROPERTY_ID, "time").toUpperCase()); + UnitType outputType = UnitType.valueOf(propertyAndValue.getOrDefault(OUTPUT_TYPE_PROPERTY_ID, "time").toUpperCase()); + boolean weighted = stringToBool(propertyAndValue.getOrDefault(WEIGHTED_PROPERTY_ID, "0")); + + KeyframesData keyframesData = buildKeysData(content, header); + return new AnimData(inputType, outputType, null, null, weighted, keyframesData); + } + + private static void fillAnimProperties(AnimFileContent content, Map propertyAndValue) { + while (content.hasLine()) { + String peak = content.readLine(); + if (peak.startsWith(ANIM_STOP_SEGMENT)) + break; + String[] propertyAndValueString = peak.split(" "); + propertyAndValue.put(propertyAndValueString[0], propertyAndValueString[1]); + } + } + + private KeyframesData buildKeysData(AnimFileContent content, AnimHeader header) { + List keyData = new ArrayList<>(); + while (content.hasLine()) { + String line = content.readLine(); + if (line.startsWith("}")) + break; + String[] splitLine = line.split(" "); + int in = Integer.parseInt(splitLine[0]); + float out = Float.parseFloat(splitLine[1]); + InterpolationType inInterpolation = InterpolationType.valueOf(splitLine[2].toUpperCase()); + InterpolationType outInterpolation = InterpolationType.valueOf(splitLine[3].toUpperCase()); + boolean tanLocked = stringToBool(splitLine[4]); + boolean weightLocked = stringToBool(splitLine[5]); + + int additionalDataAmount = splitLine.length-7; + int curveHandleDataAmount = Math.floorDiv(additionalDataAmount, 2); + CurveHandleData[] curveHandleData = new CurveHandleData[curveHandleDataAmount]; + for (int i = 0; i < curveHandleDataAmount; i++) { + String tanAngle = splitLine[7+i*2]; + String tanWeight = splitLine[8+i*2]; + curveHandleData[i] = new CurveHandleData(Float.parseFloat(tanAngle), Float.parseFloat(tanWeight)); + } + + keyData.add(new KeyData(in, out, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData)); + } + content.nextLine(); + return new KeyframesData(keyData, splineBuilder.build(keyData, header.getTimeUnit().getFrameEquivalent())); + } + + private boolean stringToBool(String str) { + return str.equals("1"); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java new file mode 100644 index 0000000..464a328 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java @@ -0,0 +1,64 @@ +package fr.radi3nt.animations.importing.anim.animation.data; + +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyframesData; +import fr.radi3nt.animations.importing.anim.header.AnimHeader; +import fr.radi3nt.animations.importing.anim.units.AnimUnit; +import fr.radi3nt.animations.importing.anim.units.UnitType; + +public class AnimData { + + private final UnitType inputType; + private final UnitType outputType; + + private final AnimUnit inputUnit; + private final AnimUnit outputUnit; + + private final boolean weighted; + + private final KeyframesData keyframesData; + + public AnimData(UnitType inputType, UnitType outputType, AnimUnit inputUnit, AnimUnit outputUnit, boolean weighted, KeyframesData keyframesData) { + this.inputType = inputType; + this.outputType = outputType; + this.inputUnit = inputUnit; + this.outputUnit = outputUnit; + this.weighted = weighted; + this.keyframesData = keyframesData; + } + + public UnitType getInputType() { + return inputType; + } + + public UnitType getOutputType() { + return outputType; + } + + public AnimUnit getInputUnit(AnimHeader header) { + return inputUnit==null ? header.getUnitForType(getInputType()) : inputUnit; + } + + public AnimUnit getOutputUnit(AnimHeader header) { + return outputUnit==null ? header.getUnitForType(getOutputType()) : outputUnit; + } + + public boolean isWeighted() { + return weighted; + } + + public KeyframesData getKeyframesData() { + return keyframesData; + } + + @Override + public String toString() { + return "AnimData{" + + "inputType=" + inputType + + ", outputType=" + outputType + + ", inputUnit=" + inputUnit + + ", outputUnit=" + outputUnit + + ", weighted=" + weighted + + ", keyframesData=" + keyframesData + + '}'; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java new file mode 100644 index 0000000..2243c8a --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java @@ -0,0 +1,33 @@ +package fr.radi3nt.animations.importing.anim.animation.data; + +public class ChannelInfo { + + private final String fullChannelType; + private final String mainChannelType; + private final String leafChannelType; + + private final String objectName; + + public ChannelInfo(String fullChannelType, String mainChannelType, String leafChannelType, String objectName) { + this.fullChannelType = fullChannelType; + this.mainChannelType = mainChannelType; + this.leafChannelType = leafChannelType; + this.objectName = objectName; + } + + public String getFullChannelType() { + return fullChannelType; + } + + public String getMainChannelType() { + return mainChannelType; + } + + public String getLeafChannelType() { + return leafChannelType; + } + + public String getObjectName() { + return objectName; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java new file mode 100644 index 0000000..1dc126c --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java @@ -0,0 +1,9 @@ +package fr.radi3nt.animations.importing.anim.animation.data; + +public enum ChannelType { + + SCALE, + ROTATE, + TRANSLATE + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java new file mode 100644 index 0000000..539ac72 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java @@ -0,0 +1,28 @@ +package fr.radi3nt.animations.importing.anim.animation.data.key; + +public class CurveHandleData { + + private final float tangentAngle; + private final float tangentWeight; + + public CurveHandleData(float tangentAngle, float tangentWeight) { + this.tangentAngle = tangentAngle; + this.tangentWeight = tangentWeight; + } + + public float getTangentAngle() { + return tangentAngle; + } + + public float getTangentWeight() { + return tangentWeight; + } + + @Override + public String toString() { + return "CurveHandleData{" + + "tangentAngle=" + tangentAngle + + ", tangentWeight=" + tangentWeight + + '}'; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java new file mode 100644 index 0000000..c341957 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java @@ -0,0 +1,12 @@ +package fr.radi3nt.animations.importing.anim.animation.data.key; + +public enum InterpolationType { + + LINEAR, + AUTO, + SPLINE, + FIXED, + STEP, + FLAT, + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java new file mode 100644 index 0000000..eaa7d23 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java @@ -0,0 +1,69 @@ +package fr.radi3nt.animations.importing.anim.animation.data.key; + +import java.util.Arrays; + +public class KeyData { + + private final int in; + private final float out; + + private final InterpolationType inInterpolation; + private final InterpolationType outInterpolation; + + private final boolean tangentLocked; + private final boolean weightLocked; + + private final CurveHandleData[] curveHandleData; + + + public KeyData(int in, float out, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) { + this.in = in; + this.out = out; + this.inInterpolation = inInterpolation; + this.outInterpolation = outInterpolation; + this.tangentLocked = tangentLocked; + this.weightLocked = weightLocked; + this.curveHandleData = curveHandleData; + } + + public int getIn() { + return in; + } + + public float getOut() { + return out; + } + + public InterpolationType getInInterpolation() { + return inInterpolation; + } + + public InterpolationType getOutInterpolation() { + return outInterpolation; + } + + public boolean isTangentLocked() { + return tangentLocked; + } + + public boolean isWeightLocked() { + return weightLocked; + } + + public CurveHandleData[] getCurveHandleData() { + return curveHandleData; + } + + @Override + public String toString() { + return "KeyData{" + + "in=" + in + + ", out=" + out + + ", inInterpolation=" + inInterpolation + + ", outInterpolation=" + outInterpolation + + ", tangentLocked=" + tangentLocked + + ", weightLocked=" + weightLocked + + ", curveHandleData=" + Arrays.toString(curveHandleData) + + '}'; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java new file mode 100644 index 0000000..ab983e2 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java @@ -0,0 +1,32 @@ +package fr.radi3nt.animations.importing.anim.animation.data.key; + +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.List; + +public class KeyframesData { + + private final List keyData; + private final Spline2D dataSpline; + + public KeyframesData(List keyData, Spline2D dataSpline) { + this.keyData = keyData; + this.dataSpline = dataSpline; + } + + public List getKeyData() { + return keyData; + } + + public Spline2D getDataSpline() { + return dataSpline; + } + + @Override + public String toString() { + return "KeyframesData{" + + "keyData=" + keyData + + ", dataSpline=" + dataSpline + + '}'; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java new file mode 100644 index 0000000..f59ff49 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java @@ -0,0 +1,67 @@ +package fr.radi3nt.animations.importing.anim.animation.spline; + +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.spline.curve.Curve; +import fr.radi3nt.spline.curve.curves.CubicBezierCurve; +import fr.radi3nt.spline.splines.CollectionSpline; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class BezierKeyedSplineBuilder implements KeyedSplineBuilder { + + private final Map curveHandleDataBuilderMap; + + public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap) { + this.curveHandleDataBuilderMap = curveHandleDataBuilderMap; + } + + @Override + public Spline2D build(List keyData, float animFrameRate) { + List xCurves = new ArrayList<>(); + List yCurves = new ArrayList<>(); + Spline xSpline = new CollectionSpline(xCurves); + Spline ySpline = new CollectionSpline(yCurves); + for (int i = 0; i < keyData.size()-1; i++) { + KeyData start = keyData.get(i); + KeyData end = keyData.get(i+1); + + InterpolationType startSplineType = start.getOutInterpolation(); + InterpolationType endSplineType = end.getInInterpolation(); + + CurveHandleData startCurveData = curveHandleDataBuilderMap.get(startSplineType).buildStartHandleData(keyData, i, start, end); + CurveHandleData endCurveData = curveHandleDataBuilderMap.get(endSplineType).buildEndHandleData(keyData, i, start, end); + + CubicBezierCurve curveX = new CubicBezierCurve(new DirectCubicBezierCurveController( + start.getIn()/animFrameRate, + end.getIn()/animFrameRate, + (start.getIn()+calcPosX(startCurveData))/animFrameRate, + (end.getIn()-calcPosX(endCurveData))/animFrameRate)); + CubicBezierCurve curveY = new CubicBezierCurve(new DirectCubicBezierCurveController( + start.getOut(), + end.getOut(), + start.getOut()+calcPosY(startCurveData), + end.getOut()-calcPosY(endCurveData))); + xCurves.add(curveX); + yCurves.add(curveY); + } + + return new EncapsulatingSpline2D(xSpline, ySpline); + } + + + private float calcPosX(CurveHandleData curveHandleData) { + return (float) (Math.cos(Math.toRadians(curveHandleData.getTangentAngle()))*curveHandleData.getTangentWeight()); + } + + private float calcPosY(CurveHandleData curveHandleData) { + return (float) (Math.sin(Math.toRadians(curveHandleData.getTangentAngle()))*curveHandleData.getTangentWeight()); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java new file mode 100644 index 0000000..bb5a544 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java @@ -0,0 +1,13 @@ +package fr.radi3nt.animations.importing.anim.animation.spline; + +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; + +import java.util.List; + +public interface CurveHandleDataBuilder { + + CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end); + CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java new file mode 100644 index 0000000..1219c01 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java @@ -0,0 +1,12 @@ +package fr.radi3nt.animations.importing.anim.animation.spline; + +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.List; + +public interface KeyedSplineBuilder { + + Spline2D build(List keys, float framesPerSeconds); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java new file mode 100644 index 0000000..0083d64 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java @@ -0,0 +1,11 @@ +package fr.radi3nt.animations.importing.anim.animation.spline.handle; + +import fr.radi3nt.maths.components.vectors.Vector2f; + +public class AutoHandleDataBuilder extends GeneratedHandleDataBuilder { + + @Override + protected float getHandleAngle(Vector2f direction, float dirLength) { + return 0f; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java new file mode 100644 index 0000000..db0ea1c --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java @@ -0,0 +1,19 @@ +package fr.radi3nt.animations.importing.anim.animation.spline.handle; + +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.animations.importing.anim.animation.spline.CurveHandleDataBuilder; + +import java.util.List; + +public class FixedHandleDataBuilder implements CurveHandleDataBuilder { + @Override + public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) { + return start.getCurveHandleData()[start.getCurveHandleData().length-1]; + } + + @Override + public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) { + return end.getCurveHandleData()[0]; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java new file mode 100644 index 0000000..9cce199 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java @@ -0,0 +1,63 @@ +package fr.radi3nt.animations.importing.anim.animation.spline.handle; + +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.animations.importing.anim.animation.spline.CurveHandleDataBuilder; +import fr.radi3nt.maths.components.vectors.Vector2f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector2f; + +import java.util.List; + +public class GeneratedHandleDataBuilder implements CurveHandleDataBuilder { + @Override + public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) { + Vector2f endPos = new SimpleVector2f(end.getIn(), end.getOut()); + Vector2f beforeOnePos = new SimpleVector2f(start.getIn(), end.getOut()); + + float closeness = 0.5f; + float lengthMultiplier = 2; + if (i!=0) { + lengthMultiplier = 1f; + KeyData startBefore = keyData.get(i-1); + beforeOnePos = new SimpleVector2f(startBefore.getIn(), startBefore.getOut()); + closeness = (start.getIn()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX()); + } + + Vector2f direction = endPos.clone().sub(beforeOnePos.clone()); + float dirLength = direction.length(); + float angle = getHandleAngle(direction, dirLength); + + return new CurveHandleData(angle, getTangentWeight(1 - closeness, dirLength, lengthMultiplier)); + } + + @Override + public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) { + Vector2f startPos = new SimpleVector2f(start.getIn(), start.getOut()); + Vector2f afterEndPos = new SimpleVector2f(end.getIn(), end.getOut()); + + float closeness = 0.5f; + float lengthMultiplier = 2; + + if (i lines = new ArrayList<>(); + private int lineIndex = 0; + + public ReadableAnimFileContent(ReadableFile readableFile) { + this.readableFile = readableFile; + } + + public void readAll() { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(readableFile.getInputStream()))) { + lines = reader.lines().collect(Collectors.toList()); + lineIndex = 0; + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String peakLine() { + return formatLine(lines.get(lineIndex)); + } + + @Override + public String readLine() { + return formatLine(lines.get(lineIndex++)); + } + + @Override + public void nextLine() { + lineIndex++; + } + + @Override + public boolean hasLine() { + return lineIndex propertyAndValue = new HashMap<>(); + fillHeaderProperties(content, propertyAndValue); + + String version = propertyAndValue.getOrDefault(VERSION_PROPERTY_ID, "1.0"); + TimeUnit timeUnit = TimeUnit.valueOf(propertyAndValue.getOrDefault(TIME_UNIT_PROPERTY_ID, "ntsc").toUpperCase()); + LinearUnit linearUnit = LinearUnit.valueOf(propertyAndValue.getOrDefault(LINEAR_UNIT_PROPERTY_ID, "m").toUpperCase()); + AngularUnit angularUnit = AngularUnit.valueOf(propertyAndValue.getOrDefault(ANGULAR_UNIT_PROPERTY_ID, "rad").toUpperCase()); + int startTime = Integer.parseInt(propertyAndValue.getOrDefault(START_TIME_PROPERTY_ID, "0")); + int endTime = Integer.parseInt(propertyAndValue.getOrDefault(END_TIME_PROPERTY_ID, "0")); + + return new AnimHeader(version, timeUnit, linearUnit, angularUnit, startTime, endTime); + } + + private static void fillHeaderProperties(AnimFileContent content, Map propertyAndValue) { + while (content.hasLine()) { + String peak = content.peakLine(); + if (peak.startsWith(HEADER_STOP_SEGMENT)) + break; + String[] propertyAndValueString = peak.split(" "); + propertyAndValue.put(propertyAndValueString[0], propertyAndValueString[1]); + content.nextLine(); + } + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AngularUnit.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AngularUnit.java new file mode 100644 index 0000000..b62c044 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AngularUnit.java @@ -0,0 +1,10 @@ +package fr.radi3nt.animations.importing.anim.units; + +public enum AngularUnit implements AnimUnit { + + RAD, + DEG, + MIN, + SEC + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AnimUnit.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AnimUnit.java new file mode 100644 index 0000000..64d6840 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/AnimUnit.java @@ -0,0 +1,4 @@ +package fr.radi3nt.animations.importing.anim.units; + +public interface AnimUnit { +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/LinearUnit.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/LinearUnit.java new file mode 100644 index 0000000..127a64a --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/LinearUnit.java @@ -0,0 +1,14 @@ +package fr.radi3nt.animations.importing.anim.units; + +public enum LinearUnit implements AnimUnit { + + MM, + CM, + M, + KM, + IN, + FT, + YD, + MI + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/TimeUnit.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/TimeUnit.java new file mode 100644 index 0000000..4dd7c55 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/TimeUnit.java @@ -0,0 +1,27 @@ +package fr.radi3nt.animations.importing.anim.units; + +public enum TimeUnit implements AnimUnit { + + GAME(15), + FILM(24), + PAL(25), + NTSC(30), + SHOW(48), + PALF(50), + NTSCF(60), + HOUR(1/60f/60f), + MIN(1/60f), + SEC(1), + MILLISEC(1_000); + + + private final float frameEquivalent; + + TimeUnit(float frameEquivalent) { + this.frameEquivalent = frameEquivalent; + } + + public float getFrameEquivalent() { + return frameEquivalent; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/UnitType.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/UnitType.java new file mode 100644 index 0000000..6e4a26e --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/units/UnitType.java @@ -0,0 +1,10 @@ +package fr.radi3nt.animations.importing.anim.units; + +public enum UnitType { + + TIME, + LINEAR, + ANGULAR, + UNITLESS, + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java new file mode 100644 index 0000000..59fee84 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.timeline.interpolation.object; + +public interface ObjectInterpolation { + + T interpolate(T start, T end, float t); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java new file mode 100644 index 0000000..74631cb --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java @@ -0,0 +1,17 @@ +package fr.radi3nt.animations.timeline.interpolation.timing; + +import fr.radi3nt.maths.Easing; + +public class EasingInterpolationTiming implements InterpolationTiming { + + private final Easing easing; + + public EasingInterpolationTiming(Easing easing) { + this.easing = easing; + } + + @Override + public float getTransformedTime(float time) { + return easing.ease(time, 0, 1, 1); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java new file mode 100644 index 0000000..c075c81 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.timeline.interpolation.timing; + +public interface InterpolationTiming { + + float getTransformedTime(float time); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java new file mode 100644 index 0000000..1eac444 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java @@ -0,0 +1,17 @@ +package fr.radi3nt.animations.timeline.interpolation.timing; + +public class ShiftedInterpolationTiming implements InterpolationTiming { + + private final InterpolationTiming encapsulated; + private final float shiftT; + + public ShiftedInterpolationTiming(InterpolationTiming encapsulated, float shiftT) { + this.encapsulated = encapsulated; + this.shiftT = shiftT; + } + + @Override + public float getTransformedTime(float time) { + return encapsulated.getTransformedTime(time+shiftT); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java new file mode 100644 index 0000000..48265db --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java @@ -0,0 +1,73 @@ +package fr.radi3nt.animations.timeline.interpolation.timing; + +import fr.radi3nt.maths.components.vectors.Vector2f; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +public class Spline2DInterpolationTiming implements InterpolationTiming { + + private static final float X_TOLERANCE = 0.001f; + private static final int MAX_LOOP = 10_000; + private final Spline2D spline; + private final float splineLength; + private final int keyAmount; + + private final float startState; + private final float endState; + + public Spline2DInterpolationTiming(Spline2D spline, float splineLength, int keyAmount) { + this.spline = spline; + this.splineLength = splineLength; + this.keyAmount = keyAmount; + endState = spline.interpolate(keyAmount).getY(); + startState = spline.interpolate(0).getY(); + } + + public Spline2DInterpolationTiming(Spline2D spline, float splineLength) { + this(spline, splineLength, 1); + } + + public Spline2DInterpolationTiming(Spline2D spline) { + this(spline, 1f); + } + + @Override + public float getTransformedTime(float time) { + if (time>=1f) + return endState; + if (time<=0f) + return startState; + + Vector2f point = findPointWithX(time*splineLength); + return point.getY(); + } + + private Vector2f findPointWithX(float xTarget) { + + float lower = 0; + float upper = keyAmount; + float percent = (upper + lower) / 2; + + //get initial x + Vector2f result = spline.interpolate(percent); + float x = result.getX(); + + //loop until completion + int loopAmount = 0; + while(Math.abs(xTarget - x) > X_TOLERANCE && loopAmount x) + lower = percent; + else + upper = percent; + + percent = (upper + lower) / 2; + result = spline.interpolate(percent); + x = result.getX(); + loopAmount++; + } + + if (loopAmount==MAX_LOOP) + System.out.println("Exceeding for time " + xTarget); + + return result; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java new file mode 100644 index 0000000..713242f --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java @@ -0,0 +1,17 @@ +package fr.radi3nt.animations.timeline.interpolation.timing; + +import fr.radi3nt.spline.splines.Spline; + +public class SplineInterpolationTiming implements InterpolationTiming { + + private final Spline spline; + + public SplineInterpolationTiming(Spline spline) { + this.spline = spline; + } + + @Override + public float getTransformedTime(float time) { + return spline.interpolate(time); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java new file mode 100644 index 0000000..c08d027 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java @@ -0,0 +1,11 @@ +package fr.radi3nt.animations.timeline.state; + +public interface AnimatedState { + + T getStartState(); + T getEndState(); + + T interpolate(float timeStartingAtBit); + float getTimeLength(); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java new file mode 100644 index 0000000..ec39b12 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java @@ -0,0 +1,34 @@ +package fr.radi3nt.animations.timeline.state; + +import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; + +public class SplineAnimatedState implements AnimatedState { + + private final InterpolationTiming interpolation; + private final float length; + + public SplineAnimatedState(InterpolationTiming interpolation, float length) { + this.interpolation = interpolation; + this.length = length; + } + + @Override + public Float getStartState() { + return interpolation.getTransformedTime(0); + } + + @Override + public Float getEndState() { + return interpolation.getTransformedTime(1f); + } + + @Override + public Float interpolate(float timeStartingAtBit) { + return interpolation.getTransformedTime(timeStartingAtBit/length); + } + + @Override + public float getTimeLength() { + return length; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java new file mode 100644 index 0000000..bea83ec --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java @@ -0,0 +1,39 @@ +package fr.radi3nt.animations.timeline.state; + +import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; + +public class TypedAnimatedState implements AnimatedState { + + private final T start; + private final T end; + + private final ObjectInterpolation interpolation; + private final float length; + + public TypedAnimatedState(T start, T end, ObjectInterpolation interpolation, float length) { + this.start = start; + this.end = end; + this.interpolation = interpolation; + this.length = length; + } + + @Override + public T getStartState() { + return start; + } + + @Override + public T getEndState() { + return end; + } + + @Override + public T interpolate(float timeStartingAtBit) { + return interpolation.interpolate(start, end, timeStartingAtBit/getTimeLength()); + } + + @Override + public float getTimeLength() { + return length; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java new file mode 100644 index 0000000..79a47ef --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.timeline.time; + +public interface ChannelTimeline { + + T state(float time); + +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java new file mode 100644 index 0000000..2533320 --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java @@ -0,0 +1,15 @@ +package fr.radi3nt.animations.timeline.time; + +public class SetAnimationTimeline implements ChannelTimeline { + + private final T value; + + public SetAnimationTimeline(T value) { + this.value = value; + } + + @Override + public T state(float time) { + return value; + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java new file mode 100644 index 0000000..4a2a7da --- /dev/null +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java @@ -0,0 +1,66 @@ +package fr.radi3nt.animations.timeline.time; + +import fr.radi3nt.animations.timeline.state.AnimatedState; + +import java.util.List; + +public class TypedChannelTimeline implements ChannelTimeline { + + private final List> states; + + public TypedChannelTimeline(List> states) { + this.states = states; + } + + @Override + public T state(float time) { + if (time<0) + return states.get(0).getStartState(); + + TimeResult result = getAnimatedStateAtTime(time); + + if (timeIsOutOfAnimation(result)) + return states.get(states.size()-1).getEndState(); + + AnimatedState animatedState = result.animatedState; + + float timeStartingAtBit = time-result.currentTime; + return animatedState.interpolate(timeStartingAtBit); + } + + public float getTimelineLength() { + float currentTime = 0; + for (AnimatedState state : states) { + float stateTime = state.getTimeLength(); + currentTime+=stateTime; + } + return currentTime; + } + + private boolean timeIsOutOfAnimation(TimeResult result) { + return result==null; + } + + private TimeResult getAnimatedStateAtTime(float time) { + float currentTime = 0; + for (AnimatedState state : states) { + float stateTime = state.getTimeLength(); + if (currentTime<=time && time animatedState; + private final float currentTime; + + private TimeResult(AnimatedState animatedState, float currentTime) { + this.animatedState = animatedState; + this.currentTime = currentTime; + } + } +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/Blackboard.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/Blackboard.java deleted file mode 100644 index 164993c..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/Blackboard.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.radi3nt.behavior.blackboard; - -public interface Blackboard { - - void put(BlackboardVariableId blackboardVariableValue, T value); - - T get(BlackboardVariableId type); - -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardContext.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardContext.java deleted file mode 100644 index 53fad01..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardContext.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.behavior.blackboard; - -public interface BlackboardContext { - - Blackboard getBlackboard(); - -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardVariableId.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardVariableId.java deleted file mode 100644 index 201c179..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/BlackboardVariableId.java +++ /dev/null @@ -1,6 +0,0 @@ -package fr.radi3nt.behavior.blackboard; - -public interface BlackboardVariableId { - - -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/MapBlackboard.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/MapBlackboard.java deleted file mode 100644 index ff86118..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/MapBlackboard.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.radi3nt.behavior.blackboard; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class MapBlackboard implements Blackboard { - - private final Map, Object> infoMap = new ConcurrentHashMap<>(); - - @Override - public void put(BlackboardVariableId blackboardVariableValue, T value) { - infoMap.put(blackboardVariableValue, value); - } - - @Override - public T get(BlackboardVariableId type) { - return (T) infoMap.get(type); - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/SetBlackboardContext.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/SetBlackboardContext.java deleted file mode 100644 index 4f1098b..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/blackboard/SetBlackboardContext.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.radi3nt.behavior.blackboard; - -public class SetBlackboardContext implements BlackboardContext { - - private Blackboard blackboard; - - @Override - public Blackboard getBlackboard() { - return blackboard; - } - - public void setBlackboard(Blackboard blackboard) { - this.blackboard = blackboard; - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/TreeNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/BehaviorTreeNode.java similarity index 65% rename from BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/TreeNode.java rename to BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/BehaviorTreeNode.java index bf2abee..1589892 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/TreeNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/BehaviorTreeNode.java @@ -1,6 +1,6 @@ package fr.radi3nt.behavior.tree.nodes; -public interface TreeNode { +public interface BehaviorTreeNode { NodeStatus run(); diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/CompositeNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/CompositeNode.java index 38d1321..66e6dd3 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/CompositeNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/CompositeNode.java @@ -1,25 +1,32 @@ package fr.radi3nt.behavior.tree.nodes.composite; -import fr.radi3nt.behavior.tree.nodes.TreeNode; -import fr.radi3nt.behavior.tree.nodes.types.CollectionNode; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -public abstract class CompositeNode extends CollectionNode { +public abstract class CompositeNode implements BehaviorTreeNode { - public CompositeNode(Collection animationTreeNodes) { - super(animationTreeNodes); + protected final Collection children; + + public CompositeNode(Collection children) { + this.children = children; + } + + public CompositeNode(BehaviorTreeNode... children) { + this(new ArrayList<>(Arrays.asList(children))); } - public void add(TreeNode treeNode) { - treeNodes.add(treeNode); + public void add(BehaviorTreeNode behaviorTreeNode) { + children.add(behaviorTreeNode); } - public void remove(TreeNode treeNode) { - treeNodes.remove(treeNode); + public void remove(BehaviorTreeNode behaviorTreeNode) { + children.remove(behaviorTreeNode); } - public boolean contains(TreeNode treeNode) { - return treeNodes.contains(treeNode); + public boolean contains(BehaviorTreeNode behaviorTreeNode) { + return children.contains(behaviorTreeNode); } } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/FallbackNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/FallbackNode.java index 785cb9f..97f6021 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/FallbackNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/FallbackNode.java @@ -1,23 +1,24 @@ package fr.radi3nt.behavior.tree.nodes.composite; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; -import java.util.ArrayList; +import java.util.Collection; -/** - * This BasicSelectorNode returns the first success or running result in its child. If not found, it returns 'NodeStatus.FAILURE' - */ public class FallbackNode extends CompositeNode { - public FallbackNode() { - super(new ArrayList<>()); + public FallbackNode(Collection nodes) { + super(nodes); + } + + public FallbackNode(BehaviorTreeNode... nodes) { + super(nodes); } @Override public NodeStatus run() { - for (TreeNode treeNode : treeNodes) { - NodeStatus nodeStatus = treeNode.run(); + for (BehaviorTreeNode behaviorTreeNode : children) { + NodeStatus nodeStatus = behaviorTreeNode.run(); if (nodeStatus != NodeStatus.FAILURE) return nodeStatus; } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/SequenceNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/SequenceNode.java index b2b9494..7e39aaf 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/SequenceNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/composite/SequenceNode.java @@ -1,30 +1,24 @@ package fr.radi3nt.behavior.tree.nodes.composite; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; -import java.util.ArrayList; +import java.util.Collection; -/** - * This BasicSelectorNode returns the first failure or running result in its child. If not found, it returns 'NodeStatus.SUCCESS' - */ public class SequenceNode extends CompositeNode { - public SequenceNode() { - super(new ArrayList<>()); + public SequenceNode(Collection nodes) { + super(nodes); } - public SequenceNode(TreeNode... treeNodes) { - this(); - for (TreeNode treeNode : treeNodes) { - add(treeNode); - } + public SequenceNode(BehaviorTreeNode... nodes) { + super(nodes); } @Override public NodeStatus run() { - for (TreeNode treeNode : treeNodes) { - NodeStatus nodeStatus = treeNode.run(); + for (BehaviorTreeNode behaviorTreeNode : children) { + NodeStatus nodeStatus = behaviorTreeNode.run(); if (nodeStatus != NodeStatus.SUCCESS) return nodeStatus; } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/DecorationNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/DecorationNode.java index 28bc7c5..b974c92 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/DecorationNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/DecorationNode.java @@ -1,24 +1,20 @@ package fr.radi3nt.behavior.tree.nodes.decoration; -import fr.radi3nt.behavior.tree.nodes.TreeNode; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; -public abstract class DecorationNode implements TreeNode { +public abstract class DecorationNode implements BehaviorTreeNode { - protected TreeNode treeNode; + protected BehaviorTreeNode child; public DecorationNode() { } - public DecorationNode(TreeNode treeNode) { - this.treeNode = treeNode; + public DecorationNode(BehaviorTreeNode child) { + this.child = child; } - public void set(TreeNode treeNode) { - this.treeNode = treeNode; - } - - public TreeNode get() { - return treeNode; + public void set(BehaviorTreeNode behaviorTreeNode) { + this.child = behaviorTreeNode; } } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/FailureNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/FailureNode.java index 4c986b5..40d08bc 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/FailureNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/FailureNode.java @@ -1,20 +1,17 @@ package fr.radi3nt.behavior.tree.nodes.decoration; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; public class FailureNode extends DecorationNode { - public FailureNode() { - } - - public FailureNode(TreeNode treeNode) { - super(treeNode); + public FailureNode(BehaviorTreeNode node) { + super(node); } @Override public NodeStatus run() { - treeNode.run(); + child.run(); return NodeStatus.FAILURE; } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/ForNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/ForNode.java deleted file mode 100644 index cb49ba6..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/ForNode.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.radi3nt.behavior.tree.nodes.decoration; - -import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; - -public class ForNode extends DecorationNode { - - private final int limit; - - public ForNode(TreeNode treeNode, int limit) { - super(treeNode); - this.limit = limit; - } - - @Override - public NodeStatus run() { - NodeStatus status = NodeStatus.FAILURE; - for (int i = 0; i < limit; i++) { - if ((status = treeNode.run()) != NodeStatus.FAILURE) - break; - } - - return status; - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/InverterNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/InverterNode.java index 1d1429f..bb56bd7 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/InverterNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/InverterNode.java @@ -1,20 +1,17 @@ package fr.radi3nt.behavior.tree.nodes.decoration; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; public class InverterNode extends DecorationNode { - public InverterNode() { - } - - public InverterNode(TreeNode treeNode) { - super(treeNode); + public InverterNode(BehaviorTreeNode node) { + super(node); } @Override public NodeStatus run() { - NodeStatus nodeStatus = treeNode.run(); + NodeStatus nodeStatus = child.run(); switch (nodeStatus) { case SUCCESS: return NodeStatus.FAILURE; diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/SuccessNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/SuccessNode.java index f8773c4..79fc2ff 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/SuccessNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/SuccessNode.java @@ -1,20 +1,20 @@ package fr.radi3nt.behavior.tree.nodes.decoration; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; public class SuccessNode extends DecorationNode { public SuccessNode() { } - public SuccessNode(TreeNode treeNode) { - super(treeNode); + public SuccessNode(BehaviorTreeNode node) { + super(node); } @Override public NodeStatus run() { - treeNode.run(); + child.run(); return NodeStatus.SUCCESS; } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/WhileNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/WhileNode.java deleted file mode 100644 index 9289d84..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/WhileNode.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.radi3nt.behavior.tree.nodes.decoration; - -import fr.radi3nt.behavior.tree.nodes.NodeStatus; -import fr.radi3nt.behavior.tree.nodes.TreeNode; - -public class WhileNode extends DecorationNode { - - public WhileNode(TreeNode treeNode) { - super(treeNode); - } - - @Override - public NodeStatus run() { - NodeStatus status; - while (true) { - if ((status = treeNode.run()) != NodeStatus.FAILURE) - break; - } - - return status; - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureNode.java new file mode 100644 index 0000000..e136b4c --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureNode.java @@ -0,0 +1,23 @@ +package fr.radi3nt.behavior.tree.nodes.decoration.loops; + +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; +import fr.radi3nt.behavior.tree.nodes.NodeStatus; +import fr.radi3nt.behavior.tree.nodes.decoration.DecorationNode; + +public class WhileFailureNode extends DecorationNode { + + public WhileFailureNode(BehaviorTreeNode behaviorTreeNode) { + super(behaviorTreeNode); + } + + @Override + public NodeStatus run() { + NodeStatus status; + while (true) { + if ((status = child.run()) != NodeStatus.FAILURE) + break; + } + + return status; + } +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureOrLimitNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureOrLimitNode.java new file mode 100644 index 0000000..c5fbed0 --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/decoration/loops/WhileFailureOrLimitNode.java @@ -0,0 +1,26 @@ +package fr.radi3nt.behavior.tree.nodes.decoration.loops; + +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; +import fr.radi3nt.behavior.tree.nodes.NodeStatus; +import fr.radi3nt.behavior.tree.nodes.decoration.DecorationNode; + +public class WhileFailureOrLimitNode extends DecorationNode { + + private final int limit; + + public WhileFailureOrLimitNode(BehaviorTreeNode node, int limit) { + super(node); + this.limit = limit; + } + + @Override + public NodeStatus run() { + NodeStatus status = NodeStatus.FAILURE; + for (int i = 0; i < limit; i++) { + if ((status = child.run()) != NodeStatus.FAILURE) + break; + } + + return status; + } +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/ActionNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/ActionNode.java index 1a8f356..2b31359 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/ActionNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/ActionNode.java @@ -1,7 +1,7 @@ package fr.radi3nt.behavior.tree.nodes.leaf; -import fr.radi3nt.behavior.tree.nodes.TreeNode; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; -public interface ActionNode extends TreeNode { +public interface ActionNode extends BehaviorTreeNode { } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/condition/ConditionalNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/condition/ConditionalNode.java index 5394979..eb5bdb3 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/condition/ConditionalNode.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/leaf/condition/ConditionalNode.java @@ -1,7 +1,7 @@ package fr.radi3nt.behavior.tree.nodes.leaf.condition; -import fr.radi3nt.behavior.tree.nodes.TreeNode; +import fr.radi3nt.behavior.tree.nodes.BehaviorTreeNode; -public interface ConditionalNode extends TreeNode { +public interface ConditionalNode extends BehaviorTreeNode { } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/types/CollectionNode.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/types/CollectionNode.java deleted file mode 100644 index 0f8170b..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/tree/nodes/types/CollectionNode.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.radi3nt.behavior.tree.nodes.types; - -import fr.radi3nt.behavior.tree.nodes.TreeNode; - -import java.util.Collection; - -public abstract class CollectionNode implements TreeNode { - - protected final Collection treeNodes; - - public CollectionNode(Collection animationTreeNodes) { - this.treeNodes = animationTreeNodes; - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/CompleteNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/CompleteNodeVariable.java new file mode 100644 index 0000000..789c2de --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/CompleteNodeVariable.java @@ -0,0 +1,4 @@ +package fr.radi3nt.behavior.variable; + +public interface CompleteNodeVariable extends InputNodeVariable, OutputNodeVariable { +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/EncapsulatingNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/EncapsulatingNodeVariable.java deleted file mode 100644 index 2d46fa2..0000000 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/EncapsulatingNodeVariable.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.radi3nt.behavior.variable; - -public class EncapsulatingNodeVariable implements NodeVariable { - - private final NodeVariable variable; - - public EncapsulatingNodeVariable(NodeVariable variable) { - this.variable = variable; - } - - @Override - public T get() { - return variable.get(); - } -} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/InputNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/InputNodeVariable.java new file mode 100644 index 0000000..0c92ad9 --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/InputNodeVariable.java @@ -0,0 +1,7 @@ +package fr.radi3nt.behavior.variable; + +public interface InputNodeVariable extends NodeVariable { + + T get(); + +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/NodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/NodeVariable.java index 1aea95b..685d118 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/NodeVariable.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/NodeVariable.java @@ -2,6 +2,4 @@ public interface NodeVariable { - T get(); - } diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/OutputNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/OutputNodeVariable.java new file mode 100644 index 0000000..f2ce0ad --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/OutputNodeVariable.java @@ -0,0 +1,7 @@ +package fr.radi3nt.behavior.variable; + +public interface OutputNodeVariable extends NodeVariable { + + void set(T set); + +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingInputNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingInputNodeVariable.java new file mode 100644 index 0000000..c9555af --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingInputNodeVariable.java @@ -0,0 +1,17 @@ +package fr.radi3nt.behavior.variable.encapsulation; + +import fr.radi3nt.behavior.variable.InputNodeVariable; + +public class EncapsulatingInputNodeVariable implements InputNodeVariable { + + private final InputNodeVariable variable; + + public EncapsulatingInputNodeVariable(InputNodeVariable variable) { + this.variable = variable; + } + + @Override + public T get() { + return variable.get(); + } +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingOutputNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingOutputNodeVariable.java new file mode 100644 index 0000000..448f2d5 --- /dev/null +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/encapsulation/EncapsulatingOutputNodeVariable.java @@ -0,0 +1,17 @@ +package fr.radi3nt.behavior.variable.encapsulation; + +import fr.radi3nt.behavior.variable.OutputNodeVariable; + +public class EncapsulatingOutputNodeVariable implements OutputNodeVariable { + + private final OutputNodeVariable variable; + + public EncapsulatingOutputNodeVariable(OutputNodeVariable variable) { + this.variable = variable; + } + + @Override + public void set(T set) { + variable.set(set); + } +} diff --git a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/DirectNodeVariable.java b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/impl/DirectNodeVariable.java similarity index 52% rename from BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/DirectNodeVariable.java rename to BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/impl/DirectNodeVariable.java index 3635a66..3f97c99 100644 --- a/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/DirectNodeVariable.java +++ b/BehaviorTree/src/main/java/fr/radi3nt/behavior/variable/impl/DirectNodeVariable.java @@ -1,6 +1,8 @@ -package fr.radi3nt.behavior.variable; +package fr.radi3nt.behavior.variable.impl; -public class DirectNodeVariable implements NodeVariable { +import fr.radi3nt.behavior.variable.CompleteNodeVariable; + +public class DirectNodeVariable implements CompleteNodeVariable { private T value; @@ -16,7 +18,8 @@ public T get() { return value; } - public void setValue(T value) { + @Override + public void set(T value) { this.value = value; } } diff --git a/MathsHelper/pom.xml b/MathsHelper/pom.xml index 87d16fd..8ca8d48 100644 --- a/MathsHelper/pom.xml +++ b/MathsHelper/pom.xml @@ -7,6 +7,14 @@ fr.radi3nt 1.0 + + + org.junit.jupiter + junit-jupiter-api + 5.9.3 + test + + 4.0.0 MathsHelper diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java index ef9ea9a..fb67974 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java @@ -1,7 +1,10 @@ package fr.radi3nt.maths; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix3x3; +import fr.radi3nt.maths.components.advanced.matrix.Matrix3x3; import fr.radi3nt.maths.components.vectors.Vector3f; +import java.util.Arrays; import java.util.Collection; public final class Maths { @@ -94,8 +97,39 @@ public static byte[] intToByteArray(Collection value) { return bytes; } - public static float lerp(float a, float b, float f) - { + public static float lerp(float a, float b, float f) { return a + f * (b - a); } + + public static float fma(float a, float b, float c) { + return a * b + c; + } + + public static Matrix3x3 skew(Vector3f vec) { + Matrix3x3 matrix3x3 = new ArrayMatrix3x3(); + matrix3x3.set(0, 0, 0); + matrix3x3.set(1, 0, -vec.getZ()); + matrix3x3.set(2, 0, vec.getY()); + + matrix3x3.set(0, 1, vec.getZ()); + matrix3x3.set(1, 1, 0); + matrix3x3.set(2, 1, -vec.getX()); + + matrix3x3.set(0, 2, -vec.getY()); + matrix3x3.set(1, 2, vec.getX()); + matrix3x3.set(2, 2, 0); + return matrix3x3; + } + + public static double[] nCopies(int amount, double value) { + double[] array = new double[amount]; + Arrays.fill(array, value); + return array; + } + + public static double[][] nCopies(int amount, double[] values) { + double[][] array = new double[amount][]; + Arrays.fill(array, values); + return array; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java new file mode 100644 index 0000000..06dda55 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java @@ -0,0 +1,31 @@ +package fr.radi3nt.maths.components; + +import fr.radi3nt.maths.components.arbitrary.VectorNd; + +import java.util.BitSet; + +public interface MatrixNxNd { + + double get(int x, int y); + + void set(int x, int y, double value); + + int getWidth(); + + int getHeight(); + + BitSet nonZero(); + + double[] getM(); + + MatrixNxNd multiply(MatrixNxNd matrixNxN); + + MatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN); + + MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN); + + VectorNd transform(VectorNd vec); + + MatrixNxNd duplicate(); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java index 30fb179..f305736 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Vector3D.java @@ -36,8 +36,8 @@ public Vector3D(float x, float y, float z) { public Vector3D(Vector3f vector) { this.x = vector.getX(); - this.y = vector.getX(); - this.z = vector.getX(); + this.y = vector.getY(); + this.z = vector.getZ(); } public Vector3D add(Vector3D vec) { @@ -82,7 +82,7 @@ public Vector3D divide(double div) { return this; } - public Vector3D set(double x, double y, double z) { + public Vector3D copy(double x, double y, double z) { this.setX(x); this.setY(y); this.setZ(z); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java index 5fbed2a..e845b17 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -4,6 +4,7 @@ import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; import java.util.Arrays; @@ -111,6 +112,15 @@ public Matrix3x3 duplicate() { return new ArrayMatrix3x3(this); } + @Override + public void subtract(Matrix3x3 skewRJ) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + this.set(i, j, this.get(i, j) - skewRJ.get(i, j)); + } + } + } + @Override public Quaternion getRotation() { return getCopySignRotation(); @@ -129,8 +139,8 @@ private Quaternion getCopySignRotation() { @Override public void add(Matrix3x3 other) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { this.m[i][j] += other.get(i, j); } } @@ -212,15 +222,15 @@ public void quaternionRotation(Quaternion quaternion) { m[0][0] = 1 - 2 * (yy + zz); - m[0][1] = 2 * (xy - zw); - m[0][2] = 2 * (xz + yw); + m[1][0] = 2 * (xy - zw); + m[2][0] = 2 * (xz + yw); - m[1][0] = 2 * (xy + zw); + m[0][1] = 2 * (xy + zw); m[1][1] = 1 - 2 * (xx + zz); - m[1][2] = 2 * (yz - xw); + m[2][1] = 2 * (yz - xw); - m[2][0] = 2 * (xz - yw); - m[2][1] = 2 * (yz + xw); + m[0][2] = 2 * (xz - yw); + m[1][2] = 2 * (yz + xw); m[2][2] = 1 - 2 * (xx + yy); } @@ -247,12 +257,16 @@ public void directionRotation(Vector3f direction, Vector3f up) { @Override public void transform(Vector3f toTransform) { - float x = m[0][0] * toTransform.getX() + m[1][0] * toTransform.getY() + m[2][0] * toTransform.getZ(); - float y = m[0][1] * toTransform.getX() + m[1][1] * toTransform.getY() + m[2][1] * toTransform.getZ(); - float z = m[0][2] * toTransform.getX() + m[1][2] * toTransform.getY() + m[2][2] * toTransform.getZ(); - toTransform.setX(x); - toTransform.setY(y); - toTransform.setZ(z); + Vector3f result = new SimpleVector3f(); + + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + float value = get(x, y) * toTransform.get(x); + result.add(y, value); + } + } + + toTransform.copy(result); } @Override @@ -307,4 +321,8 @@ public String toString() { return stringBuilder.toString(); } + + public float[][] getM() { + return m; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 224e98a..19a2d51 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -41,11 +41,11 @@ public static ArrayMatrix4x4 newIdentity() { @Override public void identity() { - zero(); - m[0][0] = 1; - m[1][1] = 1; - m[2][2] = 1; - m[3][3] = 1; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + m[i][j] = i==j ? 1 : 0; + } + } } @Override @@ -281,15 +281,15 @@ public void quaternionRotation(Quaternion quaternion) { m[0][0] = 1 - 2 * (yy + zz); - m[0][1] = 2 * (xy - zw); - m[0][2] = 2 * (xz + yw); + m[1][0] = 2 * (xy - zw); + m[2][0] = 2 * (xz + yw); - m[1][0] = 2 * (xy + zw); + m[0][1] = 2 * (xy + zw); m[1][1] = 1 - 2 * (xx + zz); - m[1][2] = 2 * (yz - xw); + m[2][1] = 2 * (yz - xw); - m[2][0] = 2 * (xz - yw); - m[2][1] = 2 * (yz + xw); + m[0][2] = 2 * (xz - yw); + m[1][2] = 2 * (yz + xw); m[2][2] = 1 - 2 * (xx + yy); m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java index 21165a5..46a3114 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java @@ -31,4 +31,6 @@ public interface Matrix3x3 extends Matrix { void copy(Matrix result); Matrix3x3 duplicate(); + + void subtract(Matrix3x3 skewRJ); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 86bfe52..903f003 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -1,7 +1,10 @@ package fr.radi3nt.maths.components.advanced.quaternions; +import fr.radi3nt.maths.Maths; import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; import java.util.Objects; @@ -40,6 +43,18 @@ public static Quaternion fromAxisAndAngle(Vector3f axis, Angle angle) { return new ComponentsQuaternion(x, y, z, cos_a); } + @Override + public Vector3f getAxis() { + float angle = (float) Math.asin(w); + float sin_a = (float) Math.sin(angle / 2); + + float x = this.x / sin_a; + float y = this.y / sin_a; + float z = this.z / sin_a; + + return new SimpleVector3f(x, y, z); + } + public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angleZ) { float sinPitch = (float) Math.sin(angleX.getRadiant() * 0.5F); float cosPitch = (float) Math.cos(angleX.getRadiant() * 0.5F); @@ -58,6 +73,10 @@ public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angle return new ComponentsQuaternion(x, y, z, w); } + public static Quaternion zero() { + return ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.zero()); + } + @Override public float getX() { return x; @@ -78,6 +97,13 @@ public float getW() { return w; } + @Override + public void inverse() { + this.x = -x; + this.y = -y; + this.z = -z; + } + @Override public void normalise() { float magnitude = getMagnitude(); @@ -95,9 +121,9 @@ public void multiply(Quaternion quaternion) { float otherZ = quaternion.getZ(); float w = -this.x * otherX - this.y * otherY - this.z * otherZ + this.w * otherW; - float x = this.x * otherW + this.y * otherZ + this.z * otherY + this.w * otherX; - float y = -this.x * otherZ - this.y * otherW + this.z * otherX + this.w * otherY; - float z = this.x * otherY - this.y * otherX - this.z * otherW + this.w * otherZ; + float x = this.x * otherW + this.y * otherZ - this.z * otherY + this.w * otherX; + float y = -this.x * otherZ + this.y * otherW + this.z * otherX + this.w * otherY; + float z = this.x * otherY - this.y * otherX + this.z * otherW + this.w * otherZ; this.x = x; this.y = y; @@ -107,22 +133,38 @@ public void multiply(Quaternion quaternion) { @Override public void multiply(Vector3f vec) { - float wRes = -(x*vec.getX() + y*vec.getY() + z*vec.getZ()); - float xRes = w*vec.getX() + y*vec.getZ() - z*vec.getY(); - float yRes = w* vec.getY() + z* vec.getX() - x* vec.getZ(); - float zRes = w* vec.getZ() + x*vec.getY() - y*vec.getX(); + float wRes = -(x * vec.getX() + y * vec.getY() + z * vec.getZ()); + float xRes = w * vec.getX() + y * vec.getZ() - z * vec.getY(); + float yRes = w * vec.getY() + z * vec.getX() - x * vec.getZ(); + float zRes = w * vec.getZ() + x * vec.getY() - y * vec.getX(); x = xRes; y = yRes; z = zRes; w = wRes; } + @Override + public void transform(Vector3f vec) { + float xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w; + float xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w; + float zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww); + + vec.set(Maths.fma((xx - yy - zz + ww) * k, vec.getX(), Maths.fma(2 * (xy - zw) * k, vec.getY(), (2 * (xz + yw) * k) * vec.getZ())), + Maths.fma(2 * (xy + zw) * k, vec.getX(), Maths.fma((yy - xx - zz + ww) * k, vec.getY(), (2 * (yz - xw) * k) * vec.getZ())), + Maths.fma(2 * (xz - yw) * k, vec.getX(), Maths.fma(2 * (yz + xw) * k, vec.getY(), ((zz - xx - yy + ww) * k) * vec.getZ()))); + } + + @Override + public void transformUnit(Vector3f vec) { + transform(vec); + } + @Override public void multiplyInv(Vector3f vec) { - float wRes = -(x*vec.getX() + y*vec.getY() + z*vec.getZ()); - float xRes = w*vec.getX() + z*vec.getY() - y*vec.getZ(); - float yRes = w* vec.getY() + x* vec.getZ() - z* vec.getX(); - float zRes = w* vec.getZ() + y*vec.getX() - x*vec.getY(); + float wRes = -(x * vec.getX() + y * vec.getY() + z * vec.getZ()); + float xRes = w * vec.getX() + z * vec.getY() - y * vec.getZ(); + float yRes = w * vec.getY() + x * vec.getZ() - z * vec.getX(); + float zRes = w * vec.getZ() + y * vec.getX() - x * vec.getY(); x = xRes; y = yRes; z = zRes; @@ -194,6 +236,21 @@ public void copy(Quaternion rotation) { this.w = rotation.getW(); } + @Override + public void setX(float x) { + this.x = x; + } + + @Override + public void setY(float y) { + this.y = y; + } + + @Override + public void setZ(float z) { + this.z = z; + } + @Override public void add(Quaternion quaternion) { this.x += quaternion.getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index 1dd107b..964bf45 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -12,6 +12,8 @@ public interface Quaternion { float getW(); + void inverse(); + void normalise(); void add(Quaternion quaternion); @@ -20,6 +22,10 @@ public interface Quaternion { void multiply(Vector3f vec); + void transform(Vector3f vec); + + void transformUnit(Vector3f result); + void multiplyInv(Vector3f vec); void multiply(float s); @@ -35,4 +41,10 @@ public interface Quaternion { Quaternion duplicate(); void copy(Quaternion rotation); + + Vector3f getAxis(); + + void setX(float x); + void setY(float y); + void setZ(float z); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxNf.java similarity index 55% rename from MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxNf.java index eff3530..625433a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxN.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/MatrixNxNf.java @@ -2,7 +2,7 @@ import java.util.BitSet; -public interface MatrixNxN { +public interface MatrixNxNf { float get(int x, int y); @@ -16,14 +16,14 @@ public interface MatrixNxN { float[] getM(); - MatrixNxN multiply(MatrixNxN matrixNxN); + MatrixNxNf multiply(MatrixNxNf matrixNxN); - MatrixNxN multiplyTransposed(MatrixNxN matrixNxN); + MatrixNxNf multiplyTransposed(MatrixNxNf matrixNxN); - MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN); + MatrixNxNf multiplyTransposedOther(MatrixNxNf matrixNxN); VectorNf transform(VectorNf vec); - MatrixNxN duplicate(); + MatrixNxNf duplicate(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNd.java new file mode 100644 index 0000000..74d4298 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNd.java @@ -0,0 +1,24 @@ +package fr.radi3nt.maths.components.arbitrary; + +import fr.radi3nt.maths.components.vectors.Vector; + +public interface VectorNd extends Vector { + + double get(int row); + + void set(int row, double v); + + void add(int row, double v); + + void div(int row, double v); + + void clamp(int row, double min, double max); + + int size(); + + void scalar(VectorNd kd); + + void add(VectorNd damping); + + void scalar(double v); +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java new file mode 100644 index 0000000..48bf1d5 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java @@ -0,0 +1,201 @@ +package fr.radi3nt.maths.components.arbitrary.matrix; + +import fr.radi3nt.maths.components.MatrixNxNd; +import fr.radi3nt.maths.components.arbitrary.VectorNd; +import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNd; + +import java.util.Arrays; +import java.util.BitSet; + +public class ArrayMatrixNxNd implements MatrixNxNd { + + private final int width; + private final int height; + private final double[] m; + private final BitSet zeroSet; + + public ArrayMatrixNxNd(int width, int height) { + this.width = width; + this.height = height; + m = new double[width * height]; + zeroSet = new BitSet(this.width * this.height); + } + + protected ArrayMatrixNxNd(int width, int height, double[] m) { + this.width = width; + this.height = height; + this.m = m; + zeroSet = new BitSet(this.width * this.height); + } + + @Override + public ArrayMatrixNxNd multiply(MatrixNxNd matrixNxN) { + if (this.width != matrixNxN.getHeight()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); + + int resultWidth = matrixNxN.getWidth(); + int resultHeight = this.height; + + BitSet nonZero = matrixNxN.nonZero(); + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int i = 0; i < this.width; i++) { + double cache = matrixNxN.get(x, i); + for (int y = 0; y < result.height; y++) { + if (nonZero.get(x + i * matrixNxN.getWidth())) + result.add(x, y, this.get(i, y) * cache); + } + } + } + result.markAllNonZero(); + + return result; + } + + @Override + public ArrayMatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = matrixNxN.getHeight(); + int resultHeight = this.height; + + BitSet nonZero = matrixNxN.nonZero(); + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int y = 0; y < result.height; y++) { + float total = 0; + for (int i = 0; i < this.width; i++) { + if (nonZero.get(i + x * matrixNxN.getWidth())) + total += this.get(i, y) * matrixNxN.get(i, x); + } + result.add(x, y, total); + } + } + result.markAllNonZero(); + + return result; + } + + @Override + public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { + if (matrixNxN.getWidth() != this.width) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = this.height; + int resultHeight = matrixNxN.getHeight(); + + BitSet nonZero = this.nonZero(); + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (int x = 0; x < result.width; x++) { + for (int y = 0; y < result.height; y++) { + float total = 0; + for (int i = 0; i < matrixNxN.getWidth(); i++) { + if (nonZero.get(i + x * this.getWidth())) + total += matrixNxN.get(i, y) * this.get(i, x); + } + result.add(x, y, total); + } + } + result.markAllNonZero(); + + return result; + } + + @Override + public double get(int x, int y) { + return m[x + y * width]; + } + + @Override + public void set(int x, int y, double value) { + m[x + y * width] = value; + zeroSet.set(x + y * width, value != 0); + } + + public void add(int x, int y, double total) { + m[x + y * width] += total; + } + + public void markAllNonZero() { + zeroSet.set(0, height * width, true); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + @Override + public BitSet nonZero() { + return zeroSet; + } + + @Override + public ArrayMatrixNxNd duplicate() { + return new ArrayMatrixNxNd(width, height, Arrays.copyOf(m, m.length)); + } + + public double[] getM() { + return m; + } + + @Override + public VectorNd transform(VectorNd vec) { + VectorNd result = new ArrayVectorNd(height); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + double value = get(x, y) * vec.get(x); + result.add(y, value); + } + } + + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ArrayMatrixNxNd)) return false; + + ArrayMatrixNxNd that = (ArrayMatrixNxNd) o; + + if (width != that.width) return false; + if (height != that.height) return false; + return Arrays.equals(m, that.m); + } + + @Override + public int hashCode() { + int result = width; + result = 31 * result + height; + result = 31 * result + Arrays.hashCode(m); + return result; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder("ArrayMatrixNxN{" + + "\n"); + stringBuilder.append("width=").append(width).append("\n"); + stringBuilder.append("height=").append(height).append("\n"); + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + stringBuilder.append(get(i, j)).append(" "); + } + stringBuilder.append("\n"); + } + + stringBuilder.append("}"); + + return stringBuilder.toString(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNf.java similarity index 81% rename from MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNf.java index 452d81c..52861b0 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxN.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNf.java @@ -1,27 +1,27 @@ package fr.radi3nt.maths.components.arbitrary.matrix; -import fr.radi3nt.maths.components.arbitrary.MatrixNxN; +import fr.radi3nt.maths.components.arbitrary.MatrixNxNf; import fr.radi3nt.maths.components.arbitrary.VectorNf; import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNf; import java.util.Arrays; import java.util.BitSet; -public class ArrayMatrixNxN implements MatrixNxN { +public class ArrayMatrixNxNf implements MatrixNxNf { private final int width; private final int height; private final float[] m; private final BitSet zeroSet; - public ArrayMatrixNxN(int width, int height) { + public ArrayMatrixNxNf(int width, int height) { this.width = width; this.height = height; m = new float[width * height]; zeroSet = new BitSet(this.width * this.height); } - protected ArrayMatrixNxN(int width, int height, float[] m) { + protected ArrayMatrixNxNf(int width, int height, float[] m) { this.width = width; this.height = height; this.m = m; @@ -29,7 +29,7 @@ protected ArrayMatrixNxN(int width, int height, float[] m) { } @Override - public ArrayMatrixNxN multiply(MatrixNxN matrixNxN) { + public ArrayMatrixNxNf multiply(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getHeight()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); @@ -38,7 +38,7 @@ public ArrayMatrixNxN multiply(MatrixNxN matrixNxN) { BitSet nonZero = matrixNxN.nonZero(); - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { float total = 0; @@ -54,7 +54,7 @@ public ArrayMatrixNxN multiply(MatrixNxN matrixNxN) { } @Override - public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { + public ArrayMatrixNxNf multiplyTransposed(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getWidth()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); @@ -63,7 +63,7 @@ public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { BitSet nonZero = matrixNxN.nonZero(); - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { float total = 0; @@ -79,7 +79,7 @@ public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { } @Override - public MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN) { + public MatrixNxNf multiplyTransposedOther(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getWidth()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); @@ -88,7 +88,7 @@ public MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN) { BitSet nonZero = this.nonZero(); - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { float total = 0; @@ -128,8 +128,8 @@ public BitSet nonZero() { } @Override - public ArrayMatrixNxN duplicate() { - return new ArrayMatrixNxN(width, height, Arrays.copyOf(m, m.length)); + public ArrayMatrixNxNf duplicate() { + return new ArrayMatrixNxNf(width, height, Arrays.copyOf(m, m.length)); } public float[] getM() { @@ -141,11 +141,10 @@ public VectorNf transform(VectorNf vec) { VectorNf result = new ArrayVectorNf(height); for (int y = 0; y < height; y++) { - float yi = 0; for (int x = 0; x < width; x++) { - yi += get(x, y) * vec.get(x); + float value = get(x, y) * vec.get(x); + result.add(y, value); } - result.set(y, yi); } return result; @@ -158,8 +157,8 @@ public String toString() { stringBuilder.append("width=").append(width).append("\n"); stringBuilder.append("height=").append(height).append("\n"); - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { stringBuilder.append(get(i, j)).append(" "); } stringBuilder.append("\n"); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockd.java new file mode 100644 index 0000000..f338907 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockd.java @@ -0,0 +1,69 @@ +package fr.radi3nt.maths.components.arbitrary.matrix.sparse; + +public class SparseBlockd { + + private final int startX; + private final int startY; + private final int width; + private final int height; + + private final double[] values; + + public SparseBlockd(int startX, int startY, int width, int height, double[] values) { + this.startX = startX; + this.startY = startY; + this.width = width; + this.height = height; + this.values = values; + } + + public SparseBlockd(int startX, int startY, int width, int height, double[][] m) { + this.startX = startX; + this.startY = startY; + this.width = width; + this.height = height; + this.values = new double[]{width * height}; + + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + values[i + j * width] = m[i][j]; + } + } + } + + public double get(int i, int j) { + return values[(i - startX) + (j - startY) * width]; + } + + public int getStartX() { + return startX; + } + + public int getStartY() { + return startY; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public double[] getValues() { + return values; + } + + public boolean isInBound(int x, int y) { + return isInBoundX(x) && isInBoundY(y); + } + + protected boolean isInBoundY(int y) { + return y >= startY && y < startY + height; + } + + protected boolean isInBoundX(int x) { + return x >= startX && x < startX + width; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockf.java similarity index 62% rename from MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockf.java index 8756626..08d8741 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlock.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseBlockf.java @@ -1,6 +1,6 @@ package fr.radi3nt.maths.components.arbitrary.matrix.sparse; -public class SparseBlock { +public class SparseBlockf { private final int startI; private final int startJ; @@ -9,7 +9,7 @@ public class SparseBlock { private final float[] values; - public SparseBlock(int startI, int startJ, int lengthI, int lengthJ, float[] values) { + public SparseBlockf(int startI, int startJ, int lengthI, int lengthJ, float[] values) { this.startI = startI; this.startJ = startJ; this.lengthI = lengthI; @@ -17,6 +17,20 @@ public SparseBlock(int startI, int startJ, int lengthI, int lengthJ, float[] val this.values = values; } + public SparseBlockf(int startI, int startJ, int lengthI, int lengthJ, float[][] m) { + this.startI = startI; + this.startJ = startJ; + this.lengthI = lengthI; + this.lengthJ = lengthJ; + this.values = new float[]{lengthI * lengthJ}; + + for (int i = 0; i < lengthI; i++) { + for (int j = 0; j < lengthJ; j++) { + values[i + j * lengthI] = m[i][j]; + } + } + } + public float get(int i, int j) { return values[(i - startI) + (j - startJ) * lengthI]; } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java new file mode 100644 index 0000000..3b5c53b --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java @@ -0,0 +1,202 @@ +package fr.radi3nt.maths.components.arbitrary.matrix.sparse; + +import fr.radi3nt.maths.components.MatrixNxNd; +import fr.radi3nt.maths.components.arbitrary.VectorNd; +import fr.radi3nt.maths.components.arbitrary.matrix.ArrayMatrixNxNd; +import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNd; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; + +public class SparseMatrixd implements MatrixNxNd { + + private final Collection sparseBlocks; + private int width; + private int height; + + public SparseMatrixd(Collection sparseBlocks, int width, int height) { + this.sparseBlocks = sparseBlocks; + this.width = width; + this.height = height; + } + + + public SparseMatrixd() { + this(new ArrayList<>(), 0, 0); + } + + public void add(SparseBlockd sparseBlock) { + sparseBlocks.add(sparseBlock); + computeCursors(sparseBlock); + } + + private void computeCursors(SparseBlockd sparseBlock) { + width = Math.max(width, sparseBlock.getStartX() + sparseBlock.getWidth()); + height = Math.max(height, sparseBlock.getStartY() + sparseBlock.getHeight()); + } + + @Override + public double get(int x, int y) { + for (SparseBlockd sparseBlock : sparseBlocks) { + if (sparseBlock.isInBound(x, y)) { + return sparseBlock.get(x, y); + } + } + return 0; + } + + @Override + public void set(int x, int y, double value) { + throw new UnsupportedOperationException(); + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public BitSet nonZero() { + BitSet bitSet = new BitSet(width * height); + //bitSet.set(0, width*height); + + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + int row = y * width; + bitSet.set(sparseBlock.getStartX() + row, sparseBlock.getStartX() + sparseBlock.getWidth() + row); + } + } + + return bitSet; + } + + @Override + public double[] getM() { + throw new UnsupportedOperationException(); + } + + public VectorNd transform(VectorNd vector) { + VectorNd result = new ArrayVectorNd(height); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + for (int x = sparseBlock.getStartX(); x < sparseBlock.getStartX() + sparseBlock.getWidth(); x++) { + double value = sparseBlock.get(x, y); + result.add(y, value * vector.get(x)); + } + } + } + return result; + } + + public VectorNd transformTransposed(VectorNd vector) { + VectorNd result = new ArrayVectorNd(width); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + for (int x = sparseBlock.getStartX(); x < sparseBlock.getStartX() + sparseBlock.getWidth(); x++) { + double value = sparseBlock.get(x, y); + result.add(x, value * vector.get(y)); + } + } + } + return result; + } + + @Override + public MatrixNxNd duplicate() { + return new SparseMatrixd(new ArrayList<>(sparseBlocks), width, height); + } + + @Override + public MatrixNxNd multiply(MatrixNxNd matrixNxN) { + if (this.width != matrixNxN.getHeight()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); + + int resultWidth = matrixNxN.getWidth(); + int resultHeight = this.height; + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int x = 0; x < resultWidth; x++) { + for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { + double temp = matrixNxN.get(x, i); + if (temp==0) + continue; + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + double adding = temp*sparseBlock.get(i, y); + if (adding==0) + continue; + result.add(x, y, adding); + } + } + } + } + result.markAllNonZero(); + + return result; + } + + @Override + public ArrayMatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN) { + if (this.width != matrixNxN.getWidth()) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = matrixNxN.getHeight(); + int resultHeight = this.height; + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + for (int x = 0; x < resultWidth; x++) { + double total = 0; + for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { + total += sparseBlock.get(i, y) * matrixNxN.get(i, x); + } + result.add(x, y, total); + } + } + } + result.markAllNonZero(); + + return result; + } + + @Override + public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { + if (matrixNxN.getWidth() != this.width) + throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + + int resultWidth = this.height; + int resultHeight = matrixNxN.getHeight(); + + BitSet bitSet = matrixNxN.nonZero(); + + int otherWidth = matrixNxN.getWidth(); + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int x = sparseBlock.getStartY(); x < sparseBlock.getStartY() + sparseBlock.getHeight(); x++) { + for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { + double cache = sparseBlock.get(i, x); + if (cache==0) + continue; + for (int y = 0; y < resultHeight; y++) { + double added = matrixNxN.get(i, y) * cache; + if (added==0) + continue; + result.add(x, y, added); + } + } + } + } + result.markAllNonZero(); + + return result; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixf.java similarity index 82% rename from MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixf.java index bce5c85..21ef1ea 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrix.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixf.java @@ -1,44 +1,44 @@ package fr.radi3nt.maths.components.arbitrary.matrix.sparse; -import fr.radi3nt.maths.components.arbitrary.MatrixNxN; +import fr.radi3nt.maths.components.arbitrary.MatrixNxNf; import fr.radi3nt.maths.components.arbitrary.VectorNf; -import fr.radi3nt.maths.components.arbitrary.matrix.ArrayMatrixNxN; +import fr.radi3nt.maths.components.arbitrary.matrix.ArrayMatrixNxNf; import fr.radi3nt.maths.components.arbitrary.vector.ArrayVectorNf; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; -public class SparseMatrix implements MatrixNxN { +public class SparseMatrixf implements MatrixNxNf { - private final Collection sparseBlocks; + private final Collection sparseBlocks; private int width; private int height; - public SparseMatrix(Collection sparseBlocks, int width, int height) { + public SparseMatrixf(Collection sparseBlocks, int width, int height) { this.sparseBlocks = sparseBlocks; this.width = width; this.height = height; } - public SparseMatrix() { + public SparseMatrixf() { this(new ArrayList<>(), 0, 0); } - public void add(SparseBlock sparseBlock) { + public void add(SparseBlockf sparseBlock) { sparseBlocks.add(sparseBlock); computeCursors(sparseBlock); } - private void computeCursors(SparseBlock sparseBlock) { + private void computeCursors(SparseBlockf sparseBlock) { width = Math.max(width, sparseBlock.getStartI() + sparseBlock.getLengthI()); height = Math.max(height, sparseBlock.getStartJ() + sparseBlock.getLengthJ()); } @Override public float get(int x, int y) { - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { if (sparseBlock.isInBound(x, y)) { return sparseBlock.get(x, y); } @@ -66,7 +66,7 @@ public BitSet nonZero() { BitSet bitSet = new BitSet(width * height); //bitSet.set(0, width*height); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { int row = j * width; bitSet.set(sparseBlock.getStartI() + row, sparseBlock.getStartI() + sparseBlock.getLengthI() + row); @@ -83,7 +83,7 @@ public float[] getM() { public VectorNf transform(VectorNf vector) { VectorNf result = new ArrayVectorNf(height); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { float value = sparseBlock.get(i, j); @@ -96,7 +96,7 @@ public VectorNf transform(VectorNf vector) { public VectorNf transformTransposed(VectorNf vector) { VectorNf result = new ArrayVectorNf(width); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int j = sparseBlock.getStartJ(); j < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); j++) { for (int i = sparseBlock.getStartI(); i < sparseBlock.getStartI() + sparseBlock.getLengthI(); i++) { float value = sparseBlock.get(i, j); @@ -108,21 +108,21 @@ public VectorNf transformTransposed(VectorNf vector) { } @Override - public MatrixNxN duplicate() { - return new SparseMatrix(new ArrayList<>(sparseBlocks), width, height); + public MatrixNxNf duplicate() { + return new SparseMatrixf(new ArrayList<>(sparseBlocks), width, height); } @Override - public MatrixNxN multiply(MatrixNxN matrixNxN) { + public MatrixNxNf multiply(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getHeight()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); int resultWidth = matrixNxN.getWidth(); int resultHeight = this.height; - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { float total = 0; @@ -151,16 +151,16 @@ public MatrixNxN multiply(MatrixNxN matrixNxN) { } @Override - public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { + public ArrayMatrixNxNf multiplyTransposed(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getWidth()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); int resultWidth = this.height; int resultHeight = matrixNxN.getHeight(); - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { float total = 0; @@ -192,17 +192,17 @@ public ArrayMatrixNxN multiplyTransposed(MatrixNxN matrixNxN) { } @Override - public MatrixNxN multiplyTransposedOther(MatrixNxN matrixNxN) { + public MatrixNxNf multiplyTransposedOther(MatrixNxNf matrixNxN) { if (this.width != matrixNxN.getWidth()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); int resultWidth = matrixNxN.getHeight(); int resultHeight = this.getHeight(); - ArrayMatrixNxN result = new ArrayMatrixNxN(resultWidth, resultHeight); + ArrayMatrixNxNf result = new ArrayMatrixNxNf(resultWidth, resultHeight); - for (SparseBlock sparseBlock : sparseBlocks) { + for (SparseBlockf sparseBlock : sparseBlocks) { for (int y = sparseBlock.getStartJ(); y < sparseBlock.getStartJ() + sparseBlock.getLengthJ(); y++) { for (int x = sparseBlock.getStartI(); x < sparseBlock.getStartI() + sparseBlock.getLengthI(); x++) { for (int i = 0; i < matrixNxN.getHeight(); i++) { diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNd.java new file mode 100644 index 0000000..81a5f97 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNd.java @@ -0,0 +1,79 @@ +package fr.radi3nt.maths.components.arbitrary.vector; + +import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.VectorNd; + +import java.util.Arrays; + +public class ArrayVectorNd implements VectorNd { + + private final double[] vector; + + public ArrayVectorNd(int size) { + vector = new double[size]; + } + + public ArrayVectorNd(VectorNd copy) { + vector = new double[copy.size()]; + for (int i = 0; i < copy.size(); i++) { + vector[i] = copy.get(i); + } + } + + @Override + public float length() { + throw new UnsupportedOperationException("Not implemented"); + } + + public int size() { + return vector.length; + } + + @Override + public void scalar(VectorNd kd) { + for (int i = 0; i < vector.length; i++) { + set(i, get(i) * kd.get(i)); + } + } + + @Override + public void add(VectorNd damping) { + for (int i = 0; i < vector.length; i++) { + set(i, get(i) + damping.get(i)); + } + } + + @Override + public void scalar(double v) { + for (int i = 0; i < vector.length; i++) { + set(i, get(i) * v); + } + } + + public double get(int row) { + return vector[row]; + } + + public void set(int row, double v) { + vector[row] = v; + } + + public void add(int row, double v) { + vector[row] += v; + } + + public void div(int row, double v) { + vector[row] /= v; + } + + public void clamp(int row, double min, double max) { + vector[row] = Maths.clamp(vector[row], min, max); + } + + @Override + public String toString() { + return "VectorNd{" + + "vector=" + Arrays.toString(vector) + + '}'; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNd.java new file mode 100644 index 0000000..d3718bb --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNd.java @@ -0,0 +1,84 @@ +package fr.radi3nt.maths.components.arbitrary.vector; + +import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.VectorNd; + +import java.util.ArrayList; +import java.util.List; + +public class ExtensibleVectorNd implements VectorNd { + + private final List vector; + + public ExtensibleVectorNd() { + vector = new ArrayList<>(); + } + + @Override + public float length() { + throw new UnsupportedOperationException("Not implemented"); + } + + public int size() { + return vector.size(); + } + + @Override + public void scalar(VectorNd kd) { + for (int i = 0; i < vector.size(); i++) { + set(i, get(i) * kd.get(i)); + } + } + + @Override + public void add(VectorNd damping) { + for (int i = 0; i < vector.size(); i++) { + set(i, get(i) + damping.get(i)); + } + } + + @Override + public void scalar(double v) { + for (int i = 0; i < vector.size(); i++) { + set(i, get(i) * v); + } + } + + public double get(int row) { + return vector.get(row); + } + + public void set(int row, double v) { + if (row >= vector.size()) + vector.add(row, v); + else + vector.set(row, v); + } + + public void add(double v) { + vector.add(v); + } + + public void add(int row, double v) { + vector.set(row, getOrZero(row) + v); + } + + private Double getOrZero(int row) { + return row < vector.size() ? get(row) : 0; + } + + public void div(int row, double v) { + vector.set(row, getOrZero(row) / v); + } + + public void clamp(int row, double min, double max) { + vector.set(row, Maths.clamp(getOrZero(row), min, max)); + } + + @Override + public String toString() { + return "ExtensibleVectorNd{" + + "vector=" + vector + + '}'; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java index f36a8e6..5319fc4 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java @@ -49,4 +49,10 @@ public interface Vector3f extends Vector { float lengthSquared(); void copy(Vector3f vert1); + + void set(Vector3f set); + + void add(int row, float value); + + float get(int row); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index 8ee29c5..7818cb0 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -16,4 +16,6 @@ public interface Vector4f extends Vector { void normalize(); void set(Vector3f vector3f, int w); + void set(float x, float y, float z, int w); + } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index 211a907..c722050 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -38,6 +38,10 @@ public SimpleVector3f(Vector4f vector4f) { this(vector4f.getX(), vector4f.getY(), vector4f.getZ()); } + public SimpleVector3f(double v, double v1, double v2) { + this((float) v, (float) v1, (float) v2); + } + @Override public float getX() { return x; @@ -183,6 +187,32 @@ public void copy(Vector3f vert1) { this.set(vert1.getX(), vert1.getY(), vert1.getZ()); } + @Override + public void set(Vector3f set) { + this.set(set.getX(), set.getY(), set.getZ()); + } + + @Override + public void add(int row, float value) { + if (row == 0) + x += value; + if (row == 1) + y += value; + if (row == 2) + z += value; + } + + @Override + public float get(int row) { + if (row == 0) + return x; + if (row == 1) + return y; + if (row == 2) + return z; + throw new IllegalArgumentException(); + } + @Override public float length() { return (float) Math.sqrt(x * x + y * y + z * z); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index ec60cd6..6991002 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -80,6 +80,14 @@ public void set(Vector3f vector3f, int w) { setW(w); } + @Override + public void set(float x, float y, float z, int w) { + setX(x); + setY(y); + setZ(z); + setW(w); + } + public void div(float length) { this.setX(getX()/length); this.setY(getY()/length); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java index 8ef9c32..62d7c3c 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java @@ -10,9 +10,13 @@ public class SatResolver { private final SatProjectionProvider provider0; private final SatProjectionProvider provider1; + private final SATShape shape1; private final SATShape shape2; + private SatAxis msa = null; + private double penetration = Double.MAX_VALUE; + public SatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2) { this.provider0 = provider; this.provider1 = provider.duplicate(); @@ -21,17 +25,16 @@ public SatResolver(SatProjectionProvider provider, SATShape shape1, SATShape sha } public boolean resolve() { + penetration = Double.MAX_VALUE; + msa = null; + SatAxis[] axes1 = shape1.getAxes(); SatAxis[] axes2 = shape2.getAxes(); - // loop over the axes1 if (testOverlapOnAxes(axes1)) return false; - // loop over the axes2 if (testOverlapOnAxes(axes2)) return false; SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); return !testOverlapOnAxes(edgeAxis); - - // if we get here then we know that every axis had overlap on it, so we can guarantee an intersection } private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { @@ -49,15 +52,31 @@ private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { private boolean testOverlapOnAxes(SatAxis[] axes) { for (SatAxis axis : axes) { - // project both shapes onto the axis + if (axis.getNormal().lengthSquared() == 0 || Double.isNaN(axis.getNormal().lengthSquared())) + continue; + SatProjection p1 = shape1.project(provider0, axis); SatProjection p2 = shape2.project(provider1, axis); - // do the projections overlap? - if (p1.noOverlap(p2)) { - // then we can guarantee that the shapes do not overlap + + if (p1.noOverlap(p2)) return true; + + double signedPenetration = p1.getOverlap(p2); + double penetration = Math.abs(signedPenetration); + if (this.penetration > penetration) { + this.msa = axis; + this.penetration = penetration; } } + return false; } + + public double getPenetration() { + return penetration; + } + + public SatAxis getMsa() { + return msa; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java new file mode 100644 index 0000000..ebc152e --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.sat.clip; + +import fr.radi3nt.maths.components.Vector3D; + +public class AxisAndVertexIndex { + + private final Vector3D axis; + private final int index; + + public AxisAndVertexIndex(Vector3D axis, int index) { + this.axis = axis; + this.index = index; + } + + public Vector3D getAxis() { + return axis; + } + + public int getIndex() { + return index; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java new file mode 100644 index 0000000..3747388 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java @@ -0,0 +1,49 @@ +package fr.radi3nt.maths.sat.clip; + +import fr.radi3nt.maths.components.Vector3D; + +import java.util.ArrayList; +import java.util.Collection; + +public class ClipPlane { + + private final Vector3D normal; + private final Vector3D vertexOnPlane; + + public ClipPlane(Vector3D normal, Vector3D vertexOnPlane) { + this.normal = normal; + this.vertexOnPlane = vertexOnPlane; + } + + public Collection clip(Iterable otherEdges) { + Collection clippedEdges = new ArrayList<>(); + double projectedClip = normal.dot(vertexOnPlane); + + for (Edge edge : otherEdges) { + double projectedVertex1 = normal.dot(edge.getVertex1()); + double projectedVertex2 = normal.dot(edge.getVertex2()); + + if (projectedVertex1>=projectedClip && projectedVertex2>=projectedClip) + clippedEdges.add(edge); + else { + if (projectedVertex1>=projectedClip) { + double on = (projectedClip-projectedVertex1)/(projectedVertex2-projectedVertex1); + Vector3D computedNewVertex = computeInterpolation(edge.getVertex1(), edge.getVertex2(), on); + clippedEdges.add(new Edge(edge.getVertex1(), computedNewVertex)); + + } else if (projectedVertex2>=projectedClip) { + double on = (projectedClip-projectedVertex2)/(projectedVertex1-projectedVertex2); + Vector3D computedNewVertex = computeInterpolation(edge.getVertex2(), edge.getVertex1(), on); + clippedEdges.add(new Edge(computedNewVertex, edge.getVertex2())); + + } + } + } + return clippedEdges; + } + + private Vector3D computeInterpolation(Vector3D vertex1, Vector3D vertex2, double on) { + Vector3D edgeLocal = vertex2.clone().subtract(vertex1); + return vertex1.clone().add(edgeLocal.multiply(on)); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java new file mode 100644 index 0000000..76bf023 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java @@ -0,0 +1,36 @@ +package fr.radi3nt.maths.sat.clip; + +import fr.radi3nt.maths.components.Vector3D; + +import java.util.ArrayList; +import java.util.Collection; + +public class ClipPlanes { + + private final ClipPlane[] clipPlane; + + public ClipPlanes(ClipPlane... clipPlane) { + this.clipPlane = clipPlane; + } + + public Collection clipEdges(Collection edges) { + Collection resultList = new ArrayList<>(edges); + + for (ClipPlane plane : clipPlane) { + resultList = plane.clip(resultList); + } + return resultList; + } + + public Collection clip(Collection edges) { + Collection edgeList = clipEdges(edges); + Collection result = new ArrayList<>(); + for (Edge edge : edgeList) { + result.add(edge.getVertex1()); + if (!edge.getVertex1().equals(edge.getVertex2())) + result.add(edge.getVertex2()); + } + return result; + } + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java new file mode 100644 index 0000000..f4187e4 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.sat.clip; + +import fr.radi3nt.maths.components.Vector3D; + +public class Edge { + + private final Vector3D vertex1; + private final Vector3D vertex2; + + public Edge(Vector3D vertex1, Vector3D vertex2) { + this.vertex1 = vertex1; + this.vertex2 = vertex2; + } + + public Vector3D getVertex1() { + return vertex1; + } + + public Vector3D getVertex2() { + return vertex2; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java index 5a458a9..888f03b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java @@ -18,7 +18,6 @@ public double dot(Vector3D dotted) { return normal.dot(dotted); } - @Deprecated public Vector3D getNormal() { return normal; } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java index 17603d5..9db35e6 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java @@ -11,10 +11,10 @@ public SatEdge(Vector3D edge) { } public SatAxis axis(SatEdge other) { - return new SatAxis(other.edge.getCrossProduct(edge)); + return new SatAxis(other.edge.getCrossProduct(edge, new Vector3D()).normalize()); } public SatAxis axis(SatEdge other, Vector3D result) { - return new SatAxis(other.edge.getCrossProduct(edge, result)); + return new SatAxis(other.edge.getCrossProduct(edge, result).normalize()); } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java new file mode 100644 index 0000000..0d90628 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java @@ -0,0 +1,20 @@ +package fr.radi3nt.maths.sat.projection; + +public class OverlapInfo { + + private final boolean overlap; + private final double overlapAmount; + + public OverlapInfo(boolean overlap, double overlapAmount) { + this.overlap = overlap; + this.overlapAmount = overlapAmount; + } + + public boolean isOverlap() { + return overlap; + } + + public double getOverlapAmount() { + return overlapAmount; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java index c98b8e8..1c10149 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java @@ -1,34 +1,49 @@ package fr.radi3nt.maths.sat.projection; -import fr.radi3nt.maths.sat.swept.SweptResult; +import static java.lang.Math.abs; public class SatProjection { - private double min; - private double max; + private static final OverlapInfo NO_OVERLAP = new OverlapInfo(false, 0); + + public double min; + public double max; + + private double tEnter; + private double tLeave; public SatProjection(double min, double max) { this.min = min; this.max = max; } + public OverlapInfo overlapInfo(SatProjection p2) { + if (this.min <= p2.min) { + if (this.max >= p2.min) + return new OverlapInfo(true, abs(p2.min - this.max)); + } else { + if (this.min <= p2.max) + return new OverlapInfo(true, abs(this.min - p2.max)); + } + return NO_OVERLAP; + } + + public boolean contains(SatProjection p2) { + return (min <= p2.min && max >= p2.max); + } + public boolean noOverlap(SatProjection p2) { return !overlap(p2); } - private boolean overlap(SatProjection p2) { - if (this.min <= p2.min) { - return this.max >= p2.min; - } else { - return p2.max >= this.min; - } + public boolean overlap(SatProjection p2) { + return this.min <= p2.max ? this.max >= p2.min : this.min <= p2.min; } - public void sweptOverlap(SatProjection p2, double speed, SweptResult resultPassing) { + public void sweptOverlap(SatProjection p2, double speed) { double tEnter; double tLeave; - tEnter = (p2.min - this.max) / speed; tLeave = (p2.max - this.min) / speed; @@ -38,7 +53,8 @@ public void sweptOverlap(SatProjection p2, double speed, SweptResult resultPassi tLeave = oldTEnter; } - resultPassing.set(tEnter, tLeave, null); + this.tEnter = tEnter; + this.tLeave = tLeave; } public double getOverlap(SatProjection p2) { @@ -47,9 +63,20 @@ public double getOverlap(SatProjection p2) { return p2.min - this.max; } else { if (p2.max >= this.min) - return p2.max - this.min; + return this.min - p2.max; } - return -1d; + return Double.MAX_VALUE; + } + + public int getOverlapNormal(SatProjection p2) { + if (this.min <= p2.min) { + if (this.max >= p2.min) + return 1; + } else { + if (p2.max >= this.min) + return -1; + } + return 0; } public void setMin(double min) { @@ -59,4 +86,23 @@ public void setMin(double min) { public void setMax(double max) { this.max = max; } + + public double getTEnter() { + return tEnter; + } + + public double getTLeave() { + return tLeave; + } + + + @Override + public String toString() { + return "SatProjection{" + + "min=" + min + + ", max=" + max + + ", tEnter=" + tEnter + + ", tLeave=" + tLeave + + '}'; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java index d33d754..b4c4a68 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java @@ -1,11 +1,27 @@ package fr.radi3nt.maths.sat.shape; import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.clip.AxisAndVertexIndex; +import fr.radi3nt.maths.sat.clip.ClipPlane; +import fr.radi3nt.maths.sat.clip.ClipPlanes; +import fr.radi3nt.maths.sat.clip.Edge; import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; +import java.util.Arrays; +import java.util.Collection; + public class BoxSAT implements VerticesSATShape { + private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ + new AxisAndVertexIndex(new Vector3D(1, 0, 0), 1), + new AxisAndVertexIndex(new Vector3D(0, 1, 0), 1), + new AxisAndVertexIndex(new Vector3D(0, 0, 1), 1), + new AxisAndVertexIndex(new Vector3D(-1, 0, 0), 0), + new AxisAndVertexIndex(new Vector3D(0, -1, 0), 0), + new AxisAndVertexIndex(new Vector3D(0, 0, -1), 0), + }; + private static final SatAxis[] SAT_AXES = new SatAxis[]{ new SatAxis(new Vector3D(1, 0, 0)), new SatAxis(new Vector3D(0, 1, 0)), @@ -43,8 +59,40 @@ public SatEdge[] getEdges() { return SAT_EDGES; } + @Override + public ClipPlanes getClipPlanes() { + ClipPlane[] clipPlaneArray = new ClipPlane[6]; + for (int i = 0; i < SAT_CLIP_PLANES.length; i++) { + AxisAndVertexIndex satClipPlane = SAT_CLIP_PLANES[i]; + clipPlaneArray[i] = new ClipPlane(satClipPlane.getAxis(), vertices[satClipPlane.getIndex()]); + } + return new ClipPlanes(clipPlaneArray); + } + @Override public Vector3D[] getVertices() { return vertices; } + + @Override + public Collection getClipEdges() { + return Arrays.asList( + new Edge(vertices[0], vertices[6]), + new Edge(vertices[0], vertices[4]), + new Edge(vertices[0], vertices[2]), + + new Edge(vertices[1], vertices[7]), + new Edge(vertices[1], vertices[5]), + new Edge(vertices[1], vertices[3]), + + new Edge(vertices[6], vertices[7]), + new Edge(vertices[7], vertices[2]), + + new Edge(vertices[5], vertices[4]), + new Edge(vertices[4], vertices[3]), + + new Edge(vertices[5], vertices[6]), + new Edge(vertices[3], vertices[2]) + ); + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java deleted file mode 100644 index 608c2f0..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/ObbSAT.java +++ /dev/null @@ -1,54 +0,0 @@ -package fr.radi3nt.maths.sat.shape; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; - -@Deprecated -public class ObbSAT implements VerticesSATShape { //todo does it work ? - - private final Vector3D point; - - private final Vector3D xSide; - private final Vector3D ySide; - private final Vector3D zSide; - - public ObbSAT(Vector3D point, Vector3D xSide, Vector3D ySide, Vector3D zSide) { - this.point = point; - this.xSide = xSide; - this.ySide = ySide; - this.zSide = zSide; - } - - @Override - public SatAxis[] getAxes() { - return new SatAxis[]{ - new SatAxis(xSide.clone().normalize()), - new SatAxis(ySide.clone().normalize()), - new SatAxis(zSide.clone().normalize()) - }; - } - - @Override - public SatEdge[] getEdges() { - return new SatEdge[]{ - new SatEdge(xSide), - new SatEdge(ySide), - new SatEdge(zSide) - }; - } - - @Override - public Vector3D[] getVertices() { - return new Vector3D[]{ - point.clone(), - point.clone().add(xSide), - point.clone().add(xSide).add(ySide), - point.clone().add(xSide).add(ySide).add(zSide), - point.clone().add(xSide).add(zSide), - point.clone().add(zSide), - point.clone().add(ySide), - point.clone().add(ySide).add(zSide), - }; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java new file mode 100644 index 0000000..eca6cba --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java @@ -0,0 +1,143 @@ +package fr.radi3nt.maths.sat.shape; + +import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.vectors.Vector4f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; +import fr.radi3nt.maths.sat.clip.AxisAndVertexIndex; +import fr.radi3nt.maths.sat.clip.ClipPlane; +import fr.radi3nt.maths.sat.clip.ClipPlanes; +import fr.radi3nt.maths.sat.clip.Edge; +import fr.radi3nt.maths.sat.components.SatAxis; +import fr.radi3nt.maths.sat.components.SatEdge; + +import java.util.Arrays; +import java.util.Collection; + +public class TransformedBoxSAT implements VerticesSATShape { + + private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ + new AxisAndVertexIndex(new Vector3D(1, 0, 0), 0), + new AxisAndVertexIndex(new Vector3D(0, 1, 0), 0), + new AxisAndVertexIndex(new Vector3D(0, 0, 1), 0), + new AxisAndVertexIndex(new Vector3D(-1, 0, 0), 1), + new AxisAndVertexIndex(new Vector3D(0, -1, 0), 1), + new AxisAndVertexIndex(new Vector3D(0, 0, -1), 1), + }; + + private final Vector3D[] vertices; + private Matrix4x4 transform; + + public TransformedBoxSAT(Vector3D min, Vector3D max, Matrix4x4 transform) { + this.transform = transform; + vertices = new Vector3D[]{ + min.clone(), + max.clone(), + new Vector3D(max.getX(), min.getY(), min.getZ()), + new Vector3D(max.getX(), max.getY(), min.getZ()), + new Vector3D(min.getX(), max.getY(), min.getZ()), + new Vector3D(min.getX(), max.getY(), max.getZ()), + new Vector3D(min.getX(), min.getY(), max.getZ()), + new Vector3D(max.getX(), min.getY(), max.getZ()) + }; + for (Vector3D vertex : vertices) { + Vector4f transformed = new SimpleVector4f((float) vertex.getX(), (float) vertex.getY(), (float) vertex.getZ(), 1); + transform.transform(transformed); + + vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); + } + } + + public void set(Vector3D min, Vector3D max, Matrix4x4 transform) { + vertices[0].copy(min); + vertices[1].copy(max); + vertices[2].copy(max.getX(), min.getY(), min.getZ()); + vertices[3].copy(max.getX(), max.getY(), min.getZ()); + vertices[4].copy(min.getX(), max.getY(), min.getZ()); + vertices[5].copy(min.getX(), max.getY(), max.getZ()); + vertices[6].copy(min.getX(), min.getY(), max.getZ()); + vertices[7].copy(max.getX(), min.getY(), max.getZ()); + Vector4f transformed = new SimpleVector4f(); + for (Vector3D vertex : vertices) { + transformed.set((float) vertex.getX(), (float) vertex.getY(), (float) vertex.getZ(), 1); + transform.transform(transformed); + vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); + } + this.transform = transform; + } + + @Override + public SatAxis[] getAxes() { + return computeAxis(); + } + + private SatAxis[] computeAxis() { + SatAxis[] axes = new SatAxis[3]; + Vector3D[] axis = computeBoxAxes(); + for (int i = 0; i < axes.length; i++) { + axes[i] = new SatAxis(axis[i]); + } + return axes; + } + + @Override + public SatEdge[] getEdges() { + return computeEdges(); + } + + @Override + public ClipPlanes getClipPlanes() { + ClipPlane[] clipPlaneArray = new ClipPlane[SAT_CLIP_PLANES.length]; + for (int i = 0; i < SAT_CLIP_PLANES.length; i++) { + AxisAndVertexIndex satClipPlane = SAT_CLIP_PLANES[i]; + Vector4f vector4f = new SimpleVector4f((float) satClipPlane.getAxis().getX(), (float) satClipPlane.getAxis().getY(), (float) satClipPlane.getAxis().getZ(), 0); + transform.transform(vector4f); + clipPlaneArray[i] = new ClipPlane(new Vector3D(vector4f.getX(), vector4f.getY(), vector4f.getZ()).normalize(), vertices[satClipPlane.getIndex()]); + } + return new ClipPlanes(clipPlaneArray); + } + + private SatEdge[] computeEdges() { + SatEdge[] edges = new SatEdge[3]; + Vector3D[] axis = computeBoxAxes(); + for (int i = 0; i < edges.length; i++) { + edges[i] = new SatEdge(axis[i]); + } + return edges; + } + + private Vector3D[] computeBoxAxes() { + Vector3D[] axis = new Vector3D[3]; + axis[0] = vertices[6].clone().subtract(vertices[0]).normalize(); + axis[1] = vertices[4].clone().subtract(vertices[0]).normalize(); + axis[2] = vertices[2].clone().subtract(vertices[0]).normalize(); + return axis; + } + + @Override + public Vector3D[] getVertices() { + return vertices; + } + + @Override + public Collection getClipEdges() { + return Arrays.asList( + new Edge(vertices[0], vertices[6]), + new Edge(vertices[0], vertices[4]), + new Edge(vertices[0], vertices[2]), + + new Edge(vertices[1], vertices[7]), + new Edge(vertices[1], vertices[5]), + new Edge(vertices[1], vertices[3]), + + new Edge(vertices[6], vertices[7]), + new Edge(vertices[7], vertices[2]), + + new Edge(vertices[5], vertices[4]), + new Edge(vertices[4], vertices[3]), + + new Edge(vertices[5], vertices[6]), + new Edge(vertices[3], vertices[2]) + ); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java index ddfb6fd..ce77d07 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java @@ -1,10 +1,14 @@ package fr.radi3nt.maths.sat.shape; import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.sat.clip.ClipPlanes; +import fr.radi3nt.maths.sat.clip.Edge; import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.projection.SatProjection; import fr.radi3nt.maths.sat.projection.SatProjectionProvider; +import java.util.Collection; + public interface VerticesSATShape extends SATShape { @Override @@ -15,15 +19,15 @@ default SatProjection project(SatProjectionProvider provider, SatAxis axis) { double max = min; for (int i = 1; i < vertices.length; i++) { double p = axis.dot(vertices[i]); - if (p < min) { - min = p; - } else if (p > max) { - max = p; - } + min = Math.min(p, min); + max = Math.max(p, max); } return provider.project(min, max); } Vector3D[] getVertices(); + + ClipPlanes getClipPlanes(); + Collection getClipEdges(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java index 8f412f2..011ae99 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java @@ -3,9 +3,14 @@ import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.maths.sat.clip.ClipPlane; +import fr.radi3nt.maths.sat.clip.ClipPlanes; +import fr.radi3nt.maths.sat.clip.Edge; import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; +import java.util.Arrays; +import java.util.Collection; import java.util.function.Consumer; public class ComputingTriangleSAT implements TriangleSAT { @@ -76,6 +81,24 @@ public SatEdge[] getEdges() { }; } + @Override + public Collection getClipEdges() { + Vector3D[] vertices = getVertices(); + return Arrays.asList( + new Edge(vertices[0], vertices[1]), + new Edge(vertices[1], vertices[2]), + new Edge(vertices[2], vertices[0]) + ); + } + + @Override + public ClipPlanes getClipPlanes() { + ClipPlane[] clipPlaneArray = new ClipPlane[] { + new ClipPlane(getAxes()[0].getNormal(), new Vector3D(vert1)) + }; + return new ClipPlanes(clipPlaneArray); + } + private Vector3D sub(Vector3f vert1, Vector3f vert2) { return new Vector3D(vert1.getX()-vert2.getX(), vert1.getY()-vert2.getY(), vert1.getZ()-vert2.getZ()); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java index b3a0906..2272cb8 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java @@ -2,9 +2,15 @@ import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.sat.clip.ClipPlane; +import fr.radi3nt.maths.sat.clip.ClipPlanes; +import fr.radi3nt.maths.sat.clip.Edge; import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; +import java.util.Arrays; +import java.util.Collection; + public class StoringTriangleSAT implements TriangleSAT { private final Vector3D[] vertices = new Vector3D[3]; @@ -44,4 +50,21 @@ public SatAxis[] getAxes() { public SatEdge[] getEdges() { return edges; } + + @Override + public Collection getClipEdges() { + return Arrays.asList( + new Edge(vertices[0], vertices[1]), + new Edge(vertices[1], vertices[2]), + new Edge(vertices[2], vertices[0]) + ); + } + + @Override + public ClipPlanes getClipPlanes() { + ClipPlane[] clipPlaneArray = new ClipPlane[] { + new ClipPlane(getAxes()[0].getNormal(), vertices[0]) + }; + return new ClipPlanes(clipPlaneArray); + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java index dfb6f24..814b0cb 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java @@ -35,15 +35,15 @@ public SweptResult resolve() { SweptResult shapeOne = testOverlapOnAxes(axes1); if (shapeOne == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; // loop over the axes2 SweptResult shapeTwo = testOverlapOnAxes(axes2); if (shapeTwo == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; SweptResult edges = testOverlapOnAxes(shape1.getEdges(), shape2.getEdges()); if (edges == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; double tEnter = -Double.MAX_VALUE; double tLeave = Double.MAX_VALUE; @@ -69,10 +69,12 @@ public SweptResult resolve() { tLeave = Math.min(edges.getTLeave(), tLeave); if (tEnter > tLeave) { - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; } - return new SweptResult(tEnter, tLeave, enterAxis); + if (enterAxis!=null) + return new SweptResult(true, tEnter, tLeave, enterAxis); + return SweptResult.NO_CONTACT; } private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { @@ -80,8 +82,6 @@ private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { double tLeave = Double.MAX_VALUE; SatAxis enterAxis = null; - SweptResult resultPassing = new SweptResult(); - for (SatEdge edge : edges) { for (SatEdge other : others) { SatAxis axis = edge.axis(other, cacheCross); @@ -95,24 +95,32 @@ private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { if (speed == 0) { if (p1.noOverlap(p2)) { return null; + } else { + if (tEnter<0) { + tEnter = 0; + tLeave = 1; + enterAxis = axis; + } } continue; } - p1.sweptOverlap(p2, speed, resultPassing); - if (tEnter < resultPassing.getTEnter()) { + p1.sweptOverlap(p2, speed); + if (tEnter < p1.getTEnter()) { enterAxis = axis.useNewNormalVector(new Vector3D()); - tEnter = resultPassing.getTEnter(); + tEnter = p1.getTEnter(); if (tEnter > 1) return null; } - tLeave = Math.min(resultPassing.getTLeave(), tLeave); + tLeave = Math.min(p1.getTLeave(), tLeave); if (tLeave < 0) return null; } } - return new SweptResult(tEnter, tLeave, enterAxis); + if (enterAxis!=null) + return new SweptResult(true, tEnter, tLeave, enterAxis); + return SweptResult.NO_CONTACT; } private SweptResult testOverlapOnAxes(SatAxis... axes) { @@ -121,7 +129,6 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { double tLeave = Double.MAX_VALUE; SatAxis enterAxis = null; - SweptResult resultPassing = new SweptResult(); for (SatAxis axis : axes) { // project both shapes onto the axis SatProjection p1 = shape1.project(provider0, axis); @@ -132,22 +139,28 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { if (speed == 0) { if (p1.noOverlap(p2)) { return null; + } else { + if (tEnter<0) { + tEnter = 0; + tLeave = 1; + enterAxis = axis; + } } continue; } - p1.sweptOverlap(p2, speed, resultPassing); - if (tEnter < resultPassing.getTEnter()) { + p1.sweptOverlap(p2, speed); + if (tEnter < p1.getTEnter()) { enterAxis = axis; - tEnter = resultPassing.getTEnter(); + tEnter = p1.getTEnter(); if (tEnter > 1) return null; } - tLeave = Math.min(resultPassing.getTLeave(), tLeave); + tLeave = Math.min(p1.getTLeave(), tLeave); if (tLeave < 0) return null; } - return new SweptResult(tEnter, tLeave, enterAxis); + return new SweptResult(true, tEnter, tLeave, enterAxis); } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java index 62f4b3c..167ede3 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java @@ -31,16 +31,16 @@ public SweptResult resolve() { SweptResult shapeOne = testOverlapOnAxes(axes1); if (shapeOne == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; // loop over the axes2 SweptResult shapeTwo = testOverlapOnAxes(axes2); if (shapeTwo == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); SweptResult edges = testOverlapOnAxes(edgeAxis); if (edges == null) - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; double tEnter = -Double.MAX_VALUE; double tLeave = Double.MAX_VALUE; @@ -66,10 +66,10 @@ public SweptResult resolve() { tLeave = Math.min(edges.getTLeave(), tLeave); if (tEnter > tLeave) { - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; } - return new SweptResult(tEnter, tLeave, enterAxis); + return new SweptResult(true, tEnter, tLeave, enterAxis); } private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { @@ -91,7 +91,6 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { double tLeave = Double.MAX_VALUE; SatAxis enterAxis = null; - SweptResult resultPassing = new SweptResult(); for (SatAxis axis : axes) { // project both shapes onto the axis SatProjection p1 = shape1.project(provider0, axis); @@ -106,14 +105,14 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { continue; } - p1.sweptOverlap(p2, speed, resultPassing); - if (tEnter < resultPassing.getTEnter()) { + p1.sweptOverlap(p2, speed); + if (tEnter < p1.getTEnter()) { enterAxis = axis; - tEnter = resultPassing.getTEnter(); + tEnter = p1.getTEnter(); } - tLeave = Math.min(resultPassing.getTLeave(), tLeave); + tLeave = Math.min(p1.getTLeave(), tLeave); } - return new SweptResult(tEnter, tLeave, enterAxis); + return new SweptResult(true, tEnter, tLeave, enterAxis); } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java index 8ab0639..a128d26 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java @@ -1,26 +1,58 @@ package fr.radi3nt.maths.sat.swept; +import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.sat.components.SatAxis; public class SweptResult { + public static final SweptResult NO_CONTACT = new SweptResult(false, Double.MAX_VALUE, Double.MIN_VALUE, null); + + private boolean contact; private double tEnter; private double tLeave; private SatAxis enterAxis; + private Vector3D contactPoint; public SweptResult() { } + public SweptResult(double tEnter, double tLeave, SatAxis enterAxis) { + this.contact = true; + this.tEnter = tEnter; + this.tLeave = tLeave; + this.enterAxis = enterAxis; + } + + public SweptResult(boolean contact, double tEnter, double tLeave, SatAxis enterAxis) { + this.contact = contact; + this.tEnter = tEnter; + this.tLeave = tLeave; + this.enterAxis = enterAxis; + } + + public SweptResult(boolean contact, double tEnter, double tLeave, SatAxis enterAxis, Vector3D contactPoint) { + this.contact = contact; this.tEnter = tEnter; this.tLeave = tLeave; this.enterAxis = enterAxis; + this.contactPoint = contactPoint; } - public void set(double tEnter, double tLeave, SatAxis enterAxis) { + public void set(Vector3D vertex, boolean contact, double tEnter, double tLeave, SatAxis enterAxis) { + this.contact = contact; this.tEnter = tEnter; this.tLeave = tLeave; this.enterAxis = enterAxis; + this.contactPoint = vertex; + } + + public Vector3D getContactPoint() { + return contactPoint; + } + + public boolean isContact() { + return contact; } public double getTEnter() { @@ -38,8 +70,10 @@ public SatAxis getEnterAxis() { @Override public String toString() { return "SweptResult{" + - "tEnter=" + tEnter + + "contact=" + contact + + ", tEnter=" + tEnter + ", tLeave=" + tLeave + + ", enterAxis=" + enterAxis + '}'; } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java index 2ac9eaf..17f823b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java @@ -28,10 +28,8 @@ public SweptSatResolver(SatProjectionProvider provider, SATShape shape1, SATShap public SweptResult resolve() { SatAxis[] axes1 = shape1.getAxes(); SatAxis[] axes2 = shape2.getAxes(); - // loop over the axes1 SweptResult shapeOne = testOverlapOnAxes(axes1); - // loop over the axes2 SweptResult shapeTwo = testOverlapOnAxes(axes2); SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); @@ -61,10 +59,10 @@ public SweptResult resolve() { tLeave = Math.min(edges.getTLeave(), tLeave); if (tEnter > tLeave) { - return new SweptResult(Double.MAX_VALUE, -Double.MAX_VALUE, null); + return SweptResult.NO_CONTACT; } - return new SweptResult(tEnter, tLeave, enterAxis); + return new SweptResult(true, tEnter, tLeave, enterAxis); } private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { @@ -86,12 +84,9 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { double tLeave = Double.MAX_VALUE; SatAxis enterAxis = null; - SweptResult resultPassing = new SweptResult(); for (SatAxis axis : axes) { - // project both shapes onto the axis SatProjection p1 = shape1.project(provider0, axis); SatProjection p2 = shape2.project(provider1, axis); - // do the projections overlap? double speed = axis.dot(velocity); if (speed == 0) { @@ -102,14 +97,14 @@ private SweptResult testOverlapOnAxes(SatAxis... axes) { continue; } - p1.sweptOverlap(p2, speed, resultPassing); - if (tEnter < resultPassing.getTEnter()) { + p1.sweptOverlap(p2, speed); + if (tEnter < p1.getTEnter()) { enterAxis = axis; - tEnter = resultPassing.getTEnter(); + tEnter = p1.getTEnter(); } - tLeave = Math.min(resultPassing.getTLeave(), tLeave); + tLeave = Math.min(p1.getTLeave(), tLeave); } - return new SweptResult(tEnter, tLeave, enterAxis); + return new SweptResult(true, tEnter, tLeave, enterAxis); } } diff --git a/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java new file mode 100644 index 0000000..eff70ca --- /dev/null +++ b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java @@ -0,0 +1,164 @@ +package fr.radi3nt.maths.components.arbitrary.matrix; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ArrayMatrixNxNdTest { + + private static final ArrayMatrixNxNd resultOneRow = new ArrayMatrixNxNd(3, 4); + private static final ArrayMatrixNxNd resultMultiple = new ArrayMatrixNxNd(2, 3); + + @BeforeAll + static void setUp() { + resultOneRow.set(0, 0, 1); + resultOneRow.set(0, 1, 2); + resultOneRow.set(0, 2, 3); + resultOneRow.set(0, 3, 4); + + resultOneRow.set(1, 0, 2); + resultOneRow.set(1, 1, 4); + resultOneRow.set(1, 2, 6); + resultOneRow.set(1, 3, 8); + + resultOneRow.set(2, 0, 3); + resultOneRow.set(2, 1, 6); + resultOneRow.set(2, 2, 9); + resultOneRow.set(2, 3, 12); + + resultMultiple.set(0, 0, 22); + resultMultiple.set(1, 0, 28); + + resultMultiple.set(0, 1, 49); + resultMultiple.set(1, 1, 64); + + resultMultiple.set(0, 2, 76); + resultMultiple.set(1, 2, 100); + } + + @Test + void multiplyOneRow() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(0, 1, 2); + arrayMatrixNxNd.set(0, 2, 3); + arrayMatrixNxNd.set(0, 3, 4); + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 1); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(1, 0, 2); + arrayMatrixNxNd1.set(2, 0, 3); + Assertions.assertEquals(arrayMatrixNxNd.multiply(arrayMatrixNxNd1), resultOneRow); + } + + @Test + void multiplyMultiple() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(1, 0, 2); + arrayMatrixNxNd.set(2, 0, 3); + + arrayMatrixNxNd.set(0, 1, 4); + arrayMatrixNxNd.set(1, 1, 5); + arrayMatrixNxNd.set(2, 1, 6); + + arrayMatrixNxNd.set(0, 2, 7); + arrayMatrixNxNd.set(1, 2, 8); + arrayMatrixNxNd.set(2, 2, 9); + + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(2, 3); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(1, 0, 2); + + arrayMatrixNxNd1.set(0, 1, 3); + arrayMatrixNxNd1.set(1, 1, 4); + + arrayMatrixNxNd1.set(0, 2, 5); + arrayMatrixNxNd1.set(1, 2, 6); + + Assertions.assertEquals(arrayMatrixNxNd.multiply(arrayMatrixNxNd1), resultMultiple); + } + + @Test + void multiplyWithTransposedOneRow() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(0, 1, 2); + arrayMatrixNxNd.set(0, 2, 3); + arrayMatrixNxNd.set(0, 3, 4); + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(1, 3); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(0, 1, 2); + arrayMatrixNxNd1.set(0, 2, 3); + Assertions.assertEquals(arrayMatrixNxNd.multiplyWithTransposed(arrayMatrixNxNd1), resultOneRow); + } + + @Test + void multiplyWithTransposedMultiple() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(1, 0, 2); + arrayMatrixNxNd.set(2, 0, 3); + + arrayMatrixNxNd.set(0, 1, 4); + arrayMatrixNxNd.set(1, 1, 5); + arrayMatrixNxNd.set(2, 1, 6); + + arrayMatrixNxNd.set(0, 2, 7); + arrayMatrixNxNd.set(1, 2, 8); + arrayMatrixNxNd.set(2, 2, 9); + + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 2); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(0, 1, 2); + + arrayMatrixNxNd1.set(1, 0, 3); + arrayMatrixNxNd1.set(1, 1, 4); + + arrayMatrixNxNd1.set(2, 0, 5); + arrayMatrixNxNd1.set(2, 1, 6); + + Assertions.assertEquals(arrayMatrixNxNd.multiplyWithTransposed(arrayMatrixNxNd1), resultMultiple); + } + + @Test + void multiplyWithTransposedOtherOneRow() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(0, 1, 2); + arrayMatrixNxNd.set(0, 2, 3); + arrayMatrixNxNd.set(0, 3, 4); + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(1, 3); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(0, 1, 2); + arrayMatrixNxNd1.set(0, 2, 3); + Assertions.assertEquals(arrayMatrixNxNd1.multiplyTransposedOther(arrayMatrixNxNd), resultOneRow); + } + + @Test + void multiplyWithTransposedOtherMultiple() { + ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3); + arrayMatrixNxNd.set(0, 0, 1); + arrayMatrixNxNd.set(1, 0, 2); + arrayMatrixNxNd.set(2, 0, 3); + + arrayMatrixNxNd.set(0, 1, 4); + arrayMatrixNxNd.set(1, 1, 5); + arrayMatrixNxNd.set(2, 1, 6); + + arrayMatrixNxNd.set(0, 2, 7); + arrayMatrixNxNd.set(1, 2, 8); + arrayMatrixNxNd.set(2, 2, 9); + + ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 2); + arrayMatrixNxNd1.set(0, 0, 1); + arrayMatrixNxNd1.set(0, 1, 2); + + arrayMatrixNxNd1.set(1, 0, 3); + arrayMatrixNxNd1.set(1, 1, 4); + + arrayMatrixNxNd1.set(2, 0, 5); + arrayMatrixNxNd1.set(2, 1, 6); + Assertions.assertEquals(arrayMatrixNxNd1.multiplyTransposedOther(arrayMatrixNxNd), resultMultiple); + } + +} \ No newline at end of file diff --git a/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java new file mode 100644 index 0000000..5601aeb --- /dev/null +++ b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.components.arbitrary.matrix.sparse; + +import org.junit.jupiter.api.Test; + +class SparseMatrixdTest { + + @Test + void multiply() { + SparseMatrixd sparseMatrixd = new SparseMatrixd(); + sparseMatrixd.add(new SparseBlockd(0, 0, 1, 1, new double[]{1})); + sparseMatrixd.add(new SparseBlockd(0, 1, 1, 1, new double[]{2})); + sparseMatrixd.add(new SparseBlockd(0, 2, 1, 1, new double[]{3})); + sparseMatrixd.add(new SparseBlockd(0, 3, 1, 1, new double[]{4})); + + SparseMatrixd sparseMatrixd1 = new SparseMatrixd(); + sparseMatrixd1.add(new SparseBlockd(0, 0, 1, 1, new double[]{1})); + sparseMatrixd1.add(new SparseBlockd(1, 0, 1, 1, new double[]{2})); + sparseMatrixd1.add(new SparseBlockd(2, 0, 1, 1, new double[]{3})); + + System.out.println(sparseMatrixd.multiply(sparseMatrixd1)); + } +} \ No newline at end of file diff --git a/SplineHelper/.gitignore b/SplineHelper/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/SplineHelper/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/SplineHelper/pom.xml b/SplineHelper/pom.xml new file mode 100644 index 0000000..dbfc846 --- /dev/null +++ b/SplineHelper/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + SplineHelper + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java b/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java new file mode 100644 index 0000000..6a98521 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java @@ -0,0 +1,36 @@ +package fr.radi3nt.spline; + +import fr.radi3nt.spline.curve.Curve; +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve; +import fr.radi3nt.spline.curve.curves.cardinal.CatmullRomCurve; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.cardinal.dim1.DirectCardinalCurveController; + +public class MainSplineTesting { + + public static void main(String[] args) { + //testCurves(); + } + + private static void printSpline(Spline spline, int times) { + for (int i = 0; i <= 10*times; i++) { + System.out.println(spline.interpolate(i / 10f)); + } + System.out.println("--"); + } + + private static void testCurves() { + Curve curve = new CardinalCurve(new DirectCardinalCurveController(0, 1, 2, 3, 0.5f)); + printCurve(curve, 0); + curve = new CatmullRomCurve(0, 1, 2, 3); + printCurve(curve, 1); + } + + private static void printCurve(Curve curve, int index) { + for (int i = 0; i <= 10; i++) { + System.out.println(curve.interpolate(i / 10f+index)); + } + System.out.println("--"); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java new file mode 100644 index 0000000..a7b57a4 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java @@ -0,0 +1,19 @@ +package fr.radi3nt.spline.curve; + +public abstract class CharacteristicCurve implements Curve { + + @Override + public float interpolate(float t) { + float t2 = t*t; + float t3 = t*t*t; + return computeP(1, t, t2, t3); + } + + @Override + public float velocity(float t) { + float t2 = t*t; + return computeP(0, 1, 2*t, 3*t2); + } + + protected abstract float computeP(float a, float t, float t2, float t3); +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java new file mode 100644 index 0000000..d85b060 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java @@ -0,0 +1,8 @@ +package fr.radi3nt.spline.curve; + +public interface Curve { + + float interpolate(float t); + float velocity(float t); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java new file mode 100644 index 0000000..7f87ec7 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java @@ -0,0 +1,7 @@ +package fr.radi3nt.spline.curve.controller; + +public interface CurveController { + + + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java new file mode 100644 index 0000000..6def916 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java @@ -0,0 +1,27 @@ +package fr.radi3nt.spline.curve.curves; + +import fr.radi3nt.spline.curve.CharacteristicCurve; + +public class BCurve extends CharacteristicCurve { + + private final float pointA; + private final float pointB; + private final float pointC; + private final float pointD; + + public BCurve(float pointA, float pointB, float pointC, float pointD) { + this.pointA = pointA; + this.pointB = pointB; + this.pointC = pointC; + this.pointD = pointD; + } + + @Override + protected float computeP(float a, float t, float t2, float t3) { + float p = a * (pointA + 4*pointB + pointC) + + t *(-3*pointA + 3*pointC) + + t2 *(3*pointA - 6*pointB + 3*pointC) + + t3 *(-pointA + 3*pointB - 3*pointC + pointD); + return p/6; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java new file mode 100644 index 0000000..57db245 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java @@ -0,0 +1,31 @@ +package fr.radi3nt.spline.curve.curves; + +import fr.radi3nt.spline.curve.CharacteristicCurve; +import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierCurveController; + +public class CubicBezierCurve extends CharacteristicCurve { + + private final CubicBezierCurveController controller; + + public CubicBezierCurve(CubicBezierCurveController controller) { + this.controller = controller; + } + + protected float computeP(float a, float t, float t2, float t3) { + + float startPoint = controller.getStartPoint(); + float startPointControl = controller.getStartPointControl(); + + float endPoint = controller.getEndPoint(); + float endPointControl = controller.getEndPointControl(); + + return a * startPoint + + t *(-3*startPoint+3*startPointControl) + + t2 *(3*startPoint-6*startPointControl+3*endPointControl) + + t3 *(-startPoint+3*startPointControl-3*endPointControl+endPoint); + } + + public CubicBezierCurveController getController() { + return controller; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java new file mode 100644 index 0000000..295230e --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java @@ -0,0 +1,31 @@ +package fr.radi3nt.spline.curve.curves; + +import fr.radi3nt.spline.curve.CharacteristicCurve; +import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; + +public class HermiteCurve extends CharacteristicCurve { + + private final float startPoint; + private final float endPoint; + + private final float velocityStart; + private final float velocityEnd; + + public HermiteCurve(float startPoint, float endPoint, float velocityStart, float velocityEnd) { + this.startPoint = startPoint; + this.endPoint = endPoint; + this.velocityStart = velocityStart; + this.velocityEnd = velocityEnd; + } + + public CubicBezierCurve toBezier() { + return new CubicBezierCurve(new DirectCubicBezierCurveController(startPoint, endPoint, startPoint+velocityStart/3, endPoint-velocityEnd/3)); + } + + protected float computeP(float a, float t, float t2, float t3) { + return a * startPoint + + t * (velocityStart) + + t2 * (-3*startPoint - 2*velocityStart + 3*endPoint - velocityEnd) + + t3 * (2*startPoint + velocityStart - 2*endPoint + velocityEnd); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java new file mode 100644 index 0000000..6bdd66d --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java @@ -0,0 +1,27 @@ +package fr.radi3nt.spline.curve.curves.cardinal; + +import fr.radi3nt.spline.curve.CharacteristicCurve; + +public class CardinalCurve extends CharacteristicCurve { + + private final CardinalCurveController cardinalCurveController; + + public CardinalCurve(CardinalCurveController cardinalCurveController) { + this.cardinalCurveController = cardinalCurveController; + } + + @Override + protected float computeP(float a, float t, float t2, float t3) { + + float pointA = cardinalCurveController.getPositionA(); + float pointB = cardinalCurveController.getPositionB(); + float pointC = cardinalCurveController.getPositionC(); + float pointD = cardinalCurveController.getPositionD(); + float scale = cardinalCurveController.getScale(); + + return a * pointB + + t *(-pointA*scale + pointC*scale) + + t2 *(2*pointA*scale + (scale-3)*pointB + (3-2*scale)*pointC - pointD*scale) + + t3 *(-pointA*scale + (2-scale)*pointB + (scale-2)*pointC + pointD*scale); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java new file mode 100644 index 0000000..1cc3239 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java @@ -0,0 +1,14 @@ +package fr.radi3nt.spline.curve.curves.cardinal; + +import fr.radi3nt.spline.curve.controller.CurveController; + +public interface CardinalCurveController extends CurveController { + + float getPositionA(); + float getPositionB(); + float getPositionC(); + float getPositionD(); + + float getScale(); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java new file mode 100644 index 0000000..8d491bd --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java @@ -0,0 +1,27 @@ +package fr.radi3nt.spline.curve.curves.cardinal; + +import fr.radi3nt.spline.curve.CharacteristicCurve; + +public class CatmullRomCurve extends CharacteristicCurve { + + private final float pointA; + private final float pointB; + private final float pointC; + private final float pointD; + + public CatmullRomCurve(float pointA, float pointB, float pointC, float pointD) { + this.pointA = pointA; + this.pointB = pointB; + this.pointC = pointC; + this.pointD = pointD; + } + + @Override + protected float computeP(float a, float t, float t2, float t3) { + float p = a * 2 * pointB + + t *(-pointA+pointC) + + t2 *(2*pointA-5*pointB+4*pointC-pointD) + + t3 *(-pointA+3*pointB-3*pointC+pointD); + return p/2; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java new file mode 100644 index 0000000..5d14546 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java @@ -0,0 +1,51 @@ +package fr.radi3nt.spline.splines; + +import fr.radi3nt.spline.curve.Curve; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CollectionSpline implements Spline { + + protected final List curves; + + public CollectionSpline(List curves) { + this.curves = curves; + } + + @Override + public float interpolate(float t) { + int index = (int) Math.nextDown(t); + Curve curve = getCurveAtIndex(index); + return curve.interpolate(t-index); + } + + @Override + public float velocity(float t) { + int index = (int) Math.nextDown(t); + Curve curve = getCurveAtIndex(index); + return curve.velocity(t-index); + } + + protected Curve getCurveAtIndex(int index) { + checkForValidIndex(index); + return curves.get(index); + } + + private void checkForValidIndex(int index) { + if (index<0 || index>= curves.size()) + throw new IllegalArgumentException("Index is not in bounds 0 < " + curves.size() + " (index being: " + index + ")"); + } + + public List getCurves() { + return Collections.unmodifiableList(curves); + } + + @Override + public String toString() { + return "CollectionSpline{" + + "curves=" + Arrays.toString(curves.toArray(new Curve[0])) + + '}'; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java new file mode 100644 index 0000000..2bf2d7b --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java @@ -0,0 +1,8 @@ +package fr.radi3nt.spline.splines; + +public interface Spline { + + float interpolate(float t); + float velocity(float t); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java new file mode 100644 index 0000000..5108733 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java @@ -0,0 +1,7 @@ +package fr.radi3nt.spline.splines.builder; + +public interface PositionnedSplineController extends SplineController { + + void setPosition(int index, float pos); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java new file mode 100644 index 0000000..f2d1482 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java @@ -0,0 +1,9 @@ +package fr.radi3nt.spline.splines.builder; + +import fr.radi3nt.spline.splines.Spline; + +public interface SplineBuilder { + + Spline build(); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java new file mode 100644 index 0000000..75b89ed --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java @@ -0,0 +1,4 @@ +package fr.radi3nt.spline.splines.builder; + +public interface SplineController { +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java new file mode 100644 index 0000000..4107b3a --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java @@ -0,0 +1,26 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +public class BezierPoint { + + private final float point; + private final float pointControlBefore; + private final float pointControlAfter; + + public BezierPoint(float point, float pointControlBefore, float pointControlAfter) { + this.point = point; + this.pointControlBefore = pointControlBefore; + this.pointControlAfter = pointControlAfter; + } + + public float getPoint() { + return point; + } + + public float getPointControlBefore() { + return pointControlBefore; + } + + public float getPointControlAfter() { + return pointControlAfter; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java new file mode 100644 index 0000000..7415ad0 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java @@ -0,0 +1,11 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +public interface CubicBezierCurveController { + + float getStartPoint(); + float getStartPointControl(); + + float getEndPoint(); + float getEndPointControl(); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java new file mode 100644 index 0000000..285ac7d --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java @@ -0,0 +1,34 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +import fr.radi3nt.spline.curve.curves.CubicBezierCurve; +import fr.radi3nt.spline.splines.CollectionSpline; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.SplineBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class CubicBezierSplineBuilder implements SplineBuilder { + + private final CollectionSpline spline; + private final CubicBezierSplineController controller; + + public CubicBezierSplineBuilder(BezierPoint[] pos) { + controller = new CubicBezierSplineController(pos); + List curves = new ArrayList<>(); + for (int i = 0; i < pos.length-1; i++) { + CubicBezierCurve cardinal = new CubicBezierCurve(controller.createForIndex(i)); + curves.add(cardinal); + } + spline = new CollectionSpline(curves); + } + + @Override + public Spline build() { + return spline; + } + + public CubicBezierSplineController controller() { + return controller; + } +} \ No newline at end of file diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java new file mode 100644 index 0000000..2e553b1 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java @@ -0,0 +1,21 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +import fr.radi3nt.spline.splines.builder.SplineController; + +public class CubicBezierSplineController implements SplineController { + + private final BezierPoint[] positions; + + public CubicBezierSplineController(BezierPoint[] positions) { + this.positions = positions; + } + + public void setPoint(BezierPoint point, int index) { + positions[index] = point; + } + + public CubicBezierCurveController createForIndex(int index) { + return new InferredCubicBezierCurveController(index, positions); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java new file mode 100644 index 0000000..116c78c --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java @@ -0,0 +1,37 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +public class DirectCubicBezierCurveController implements CubicBezierCurveController { + + private final float startPoint; + private final float endPoint; + + private final float startPointControl; + private final float endPointControl; + + public DirectCubicBezierCurveController(float startPoint, float endPoint, float startPointControl, float endPointControl) { + this.startPoint = startPoint; + this.endPoint = endPoint; + this.startPointControl = startPointControl; + this.endPointControl = endPointControl; + } + + @Override + public float getStartPoint() { + return startPoint; + } + + @Override + public float getEndPoint() { + return endPoint; + } + + @Override + public float getStartPointControl() { + return startPointControl; + } + + @Override + public float getEndPointControl() { + return endPointControl; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java new file mode 100644 index 0000000..e16503f --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java @@ -0,0 +1,33 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim1; + +public class InferredCubicBezierCurveController implements CubicBezierCurveController { + + private final int index; + + private final BezierPoint[] pos; + + public InferredCubicBezierCurveController(int index, BezierPoint[] pos) { + this.index = index; + this.pos = pos; + } + + @Override + public float getStartPoint() { + return pos[index].getPoint(); + } + + @Override + public float getStartPointControl() { + return pos[index].getPointControlAfter(); + } + + @Override + public float getEndPoint() { + return pos[index+1].getPoint(); + } + + @Override + public float getEndPointControl() { + return pos[index+1].getPointControlBefore(); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java new file mode 100644 index 0000000..0648a24 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java @@ -0,0 +1,26 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim2; + +import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint; + +public class BezierPoint2D { + + private final BezierPoint xAxis; + private final BezierPoint yAxis; + + public BezierPoint2D(BezierPoint xAxis, BezierPoint yAxis) { + this.xAxis = xAxis; + this.yAxis = yAxis; + } + + public BezierPoint2D(float pointX, float pointControlBeforeX, float pointControlAfterX, float pointY, float pointControlBeforeY, float pointControlAfterY) { + this(new BezierPoint(pointX, pointControlBeforeX, pointControlAfterX), new BezierPoint(pointY, pointControlBeforeY, pointControlAfterY)); + } + + public BezierPoint getXAxis() { + return xAxis; + } + + public BezierPoint getYAxis() { + return yAxis; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java new file mode 100644 index 0000000..d59f349 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java @@ -0,0 +1,34 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim2; + +import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint; +import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineBuilder; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +public class CubicBezierSplineBuilder2D { + + private final CubicBezierSplineBuilder[] splineBuilders = new CubicBezierSplineBuilder[3]; + + public CubicBezierSplineBuilder2D(BezierPoint2D... positions) { + BezierPoint[] xPos = new BezierPoint[positions.length]; + BezierPoint[] yPos = new BezierPoint[positions.length]; + + for (int i = 0; i < positions.length; i++) { + BezierPoint2D position = positions[i]; + xPos[i] = position.getXAxis(); + yPos[i] = position.getYAxis(); + } + + splineBuilders[0] = new CubicBezierSplineBuilder(xPos); + splineBuilders[1] = new CubicBezierSplineBuilder(yPos); + } + + public Spline2D build() { + return new EncapsulatingSpline2D(splineBuilders[0].build(), splineBuilders[1].build()); + } + + public CubicBezierSplineController2D controller() { + return new CubicBezierSplineController2D(splineBuilders[0].controller(), splineBuilders[1].controller()); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java new file mode 100644 index 0000000..727f74f --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java @@ -0,0 +1,18 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim2; + +import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineController; + +public class CubicBezierSplineController2D { + + private final CubicBezierSplineController[] controllers; + + public CubicBezierSplineController2D(CubicBezierSplineController... controllers) { + this.controllers = controllers; + } + + + public void setPosition(BezierPoint2D point, int index) { + controllers[0].setPoint(point.getXAxis(), index); + controllers[1].setPoint(point.getYAxis(), index); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java new file mode 100644 index 0000000..2e04061 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java @@ -0,0 +1,34 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim1; + +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve; +import fr.radi3nt.spline.splines.CollectionSpline; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.SplineBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class CardinalSplineBuilder implements SplineBuilder { + + private final CollectionSpline spline; + private final CardinalSplineController controller; + + public CardinalSplineBuilder(float[] pos, float scale) { + controller = new CardinalSplineController(pos, scale); + List curves = new ArrayList<>(); + for (int i = 0; i < pos.length-1; i++) { + CardinalCurve cardinal = new CardinalCurve(controller.createForIndex(i)); + curves.add(cardinal); + } + spline = new CollectionSpline(curves); + } + + @Override + public Spline build() { + return spline; + } + + public CardinalSplineController controller() { + return controller; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java new file mode 100644 index 0000000..71a4d91 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java @@ -0,0 +1,32 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim1; + +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; +import fr.radi3nt.spline.splines.builder.PositionnedSplineController; + +import java.util.concurrent.atomic.AtomicReference; + +public class CardinalSplineController implements PositionnedSplineController { + + + private final float[] positions; + private final AtomicReference scale; + + public CardinalSplineController(float[] positions, float scale) { + this.positions = positions; + this.scale = new AtomicReference<>(scale); + } + + @Override + public void setPosition(int index, float pos) { + positions[index] = pos; + } + + public void setScale(float scale) { + this.scale.set(scale); + } + + public CardinalCurveController createForIndex(int index) { + return new InferredCardinalCurveController(index, positions, scale); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java new file mode 100644 index 0000000..9f2da12 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java @@ -0,0 +1,45 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim1; + +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; + +public class DirectCardinalCurveController implements CardinalCurveController { + + private final float positionA; + private final float positionB; + private final float positionC; + private final float positionD; + private final float scale; + + public DirectCardinalCurveController(float positionA, float positionB, float positionC, float positionD, float scale) { + this.positionA = positionA; + this.positionB = positionB; + this.positionC = positionC; + this.positionD = positionD; + this.scale = scale; + } + + @Override + public float getPositionA() { + return positionA; + } + + @Override + public float getPositionB() { + return positionB; + } + + @Override + public float getPositionC() { + return positionC; + } + + @Override + public float getPositionD() { + return positionD; + } + + @Override + public float getScale() { + return scale; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java new file mode 100644 index 0000000..7b0ee9f --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java @@ -0,0 +1,48 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim1; + +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; + +import java.util.concurrent.atomic.AtomicReference; + +public class InferredCardinalCurveController implements CardinalCurveController { + + private final int index; + + private final float[] pos; + private final AtomicReference scale; + + public InferredCardinalCurveController(int index, float[] pos, AtomicReference scale) { + this.index = index; + this.pos = pos; + this.scale = scale; + } + + @Override + public float getPositionA() { + return index == 0 ? (mirror(pos[index], pos[index + 1])) : pos[index - 1]; + } + + @Override + public float getPositionB() { + return pos[index]; + } + + @Override + public float getPositionC() { + return index + 1 >= pos.length ? mirror(getPositionB(), getPositionA()) : pos[index + 1]; + } + + @Override + public float getPositionD() { + return index == pos.length - 2 ? mirror(getPositionC(), getPositionB()) : pos[index + 2]; + } + + @Override + public float getScale() { + return scale.get(); + } + + private float mirror(float middlePos, float endPos) { + return middlePos*2 - endPos; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java new file mode 100644 index 0000000..6e718e8 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java @@ -0,0 +1,36 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim3; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineBuilder; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D; +import fr.radi3nt.spline.splines.dimensions.Spline3D; + +public class CardinalSplineBuilder3D { + + private final CardinalSplineBuilder[] splineBuilders = new CardinalSplineBuilder[3]; + + public CardinalSplineBuilder3D(Vector3f[] positions, float scale) { + float[] xPos = new float[positions.length]; + float[] yPos = new float[positions.length]; + float[] zPos = new float[positions.length]; + + for (int i = 0; i < positions.length; i++) { + Vector3f position = positions[i]; + xPos[i] = position.getX(); + yPos[i] = position.getY(); + zPos[i] = position.getZ(); + } + + splineBuilders[0] = new CardinalSplineBuilder(xPos, scale); + splineBuilders[1] = new CardinalSplineBuilder(yPos, scale); + splineBuilders[2] = new CardinalSplineBuilder(zPos, scale); + } + + public Spline3D build() { + return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build()); + } + + public CardinalSplineController3D controller() { + return new CardinalSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller()); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java new file mode 100644 index 0000000..bf6bd3b --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java @@ -0,0 +1,26 @@ +package fr.radi3nt.spline.splines.builder.cardinal.dim3; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineController; + +public class CardinalSplineController3D { + + private final CardinalSplineController[] controllers; + + public CardinalSplineController3D(CardinalSplineController... controllers) { + this.controllers = controllers; + } + + + public void setPosition(int index, Vector3f position) { + controllers[0].setPosition(index, position.getX()); + controllers[1].setPosition(index, position.getY()); + controllers[2].setPosition(index, position.getZ()); + } + + public void setScale(float scale) { + for (CardinalSplineController controller : controllers) { + controller.setScale(scale); + } + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java new file mode 100644 index 0000000..3b8f140 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java @@ -0,0 +1,46 @@ +package fr.radi3nt.spline.splines.dimensions; + +import fr.radi3nt.maths.components.vectors.Vector2f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector2f; +import fr.radi3nt.spline.splines.Spline; + +import java.util.Arrays; + +public class EncapsulatingSpline2D implements Spline2D { + + private final Spline[] splines; + + public EncapsulatingSpline2D(Spline... splines) { + this.splines = splines; + } + + + @Override + public Vector2f interpolate(float t) { + return new SimpleVector2f(interpolateIndex(0, t), interpolateIndex(1, t)); + } + + private float interpolateIndex(int index, float t) { + return splines[index].interpolate(t); + } + + @Override + public Vector2f velocity(float t) { + return new SimpleVector2f(velocityIndex(0, t), velocityIndex(1, t)); + } + + private float velocityIndex(int index, float t) { + return splines[index].velocity(t); + } + + public Spline[] getSplines() { + return splines; + } + + @Override + public String toString() { + return "EncapsulatingSpline2D{" + + "splines=" + Arrays.toString(splines) + + '}'; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java new file mode 100644 index 0000000..8b84679 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java @@ -0,0 +1,33 @@ +package fr.radi3nt.spline.splines.dimensions; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.spline.splines.Spline; + +public class EncapsulatingSpline3D implements Spline3D { + + private final Spline[] splines; + + public EncapsulatingSpline3D(Spline... splines) { + this.splines = splines; + } + + + @Override + public Vector3f interpolate(float t) { + return new SimpleVector3f(interpolateIndex(0, t), interpolateIndex(1, t), interpolateIndex(2, t)); + } + + private float interpolateIndex(int index, float t) { + return splines[index].interpolate(t); + } + + @Override + public Vector3f velocity(float t) { + return new SimpleVector3f(velocityIndex(0, t), velocityIndex(1, t), velocityIndex(2, t)); + } + + private float velocityIndex(int index, float t) { + return splines[index].velocity(t); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java new file mode 100644 index 0000000..4d041c2 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java @@ -0,0 +1,10 @@ +package fr.radi3nt.spline.splines.dimensions; + +import fr.radi3nt.maths.components.vectors.Vector2f; + +public interface Spline2D { + + Vector2f interpolate(float t); + Vector2f velocity(float t); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java new file mode 100644 index 0000000..0a6eebc --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java @@ -0,0 +1,10 @@ +package fr.radi3nt.spline.splines.dimensions; + +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface Spline3D { + + Vector3f interpolate(float t); + Vector3f velocity(float t); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java new file mode 100644 index 0000000..a17ba10 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java @@ -0,0 +1,43 @@ +package fr.radi3nt.spline.splines.hybrid.cardinal; + +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.hybrid.hermite.HermiteSpline; + +public class CardinalUsingHermitSpline implements Spline { + + private final HermiteSpline hermiteSpline; + + public CardinalUsingHermitSpline(float[] pos, float scale) { + float[] velocities = new float[pos.length]; + for (int i = 0; i < pos.length; i++) { + int startIndex = i-1; + int endIndex = i+1; + float firstPos; + if (startIndex<0) + firstPos = pos[i]*2-pos[i+1]; + else + firstPos = pos[i-1]; + + float secondPos; + if (endIndex>=pos.length) + secondPos = pos[i]*2-pos[i-1]; + else + secondPos = pos[i+1]; + + float vel = secondPos-firstPos; + velocities[i] = vel*scale; + } + + hermiteSpline = new HermiteSpline(pos, velocities); + } + + @Override + public float interpolate(float t) { + return hermiteSpline.interpolate(t); + } + + @Override + public float velocity(float t) { + return hermiteSpline.velocity(t); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java new file mode 100644 index 0000000..d4d72ef --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java @@ -0,0 +1,32 @@ +package fr.radi3nt.spline.splines.hybrid.hermite; + +import fr.radi3nt.spline.curve.Curve; +import fr.radi3nt.spline.curve.curves.HermiteCurve; +import fr.radi3nt.spline.splines.CollectionSpline; + +import java.util.ArrayList; +import java.util.List; + +public class HermiteSpline extends CollectionSpline { + + public HermiteSpline(float[] pos, float[] velocities) { + this(new ArrayList<>(), pos, velocities); + } + + public HermiteSpline(List curves, float[] pos, float[] velocities) { + super(curves); + for (int i = 0; i < velocities.length-1; i++) { + float currentPos = pos[i]; + float nextPos = pos[i+1]; + float currentVel = velocities[i]; + float nextVel = velocities[i+1]; + + curves.add(new HermiteCurve(currentPos, nextPos, currentVel, nextVel)); + } + } + + @Override + public float interpolate(float t) { + return super.interpolate(t); + } +} diff --git a/pom.xml b/pom.xml index 8ecf03c..ca5214e 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,8 @@ BehaviorTree LanguageHelperV2 DataStructures + SplineHelper + AnimationHelper From 9a204eaaa53180356358d0ccbb7214c5b65104ba Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 24 Aug 2023 14:33:44 +0200 Subject: [PATCH 040/125] Quaternions enhancements (#5) * Added quaternion constructor that creates it from a vector and a 'w' component * Added static import for Math * Now clamping w component to [-1;1] to ensure right behavior with acos * Marked fromVectorToAnother() as deprecated and added a more robust method fromTwoVectors() * Now using sin and cos rule to convert cos to sin & added fail-safe when w==1 (meaning no rotation) * Added velocity() to approximate the quaternion velocity of two quaternion * Organised methods and added getAngle() * Refactored to match standards * Pulled changes to abstract Quaternion interface --- .../quaternions/ComponentsQuaternion.java | 129 +++++++++++++----- .../advanced/quaternions/Quaternion.java | 19 ++- 2 files changed, 110 insertions(+), 38 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 903f003..e81ff19 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -8,6 +8,10 @@ import java.util.Objects; +import static fr.radi3nt.maths.Maths.clamp; +import static java.lang.Math.abs; +import static java.lang.Math.sqrt; + public class ComponentsQuaternion implements Quaternion { private float x; @@ -22,14 +26,41 @@ public ComponentsQuaternion(float x, float y, float z, float w) { this.w = w; } + public ComponentsQuaternion(Vector3f vector, float w) { + this(vector.getX(), vector.getY(), vector.getZ(), w); + } + + @Deprecated public static Quaternion fromVectorToAnother(Vector3f v1, Vector3f v2) { Vector3f vector = v1.duplicate().cross(v2); - float w = (float) (Math.sqrt((v1.lengthSquared()) * (v2.lengthSquared())) + v1.dot(v2)); + float w = (float) (sqrt((v1.lengthSquared()) * (v2.lengthSquared())) + v1.dot(v2)); Quaternion componentsQuaternion = new ComponentsQuaternion(vector.getX(), vector.getY(), vector.getZ(), w); componentsQuaternion.normalise(); return componentsQuaternion; } + public static Quaternion fromTwoVectors(Vector3f u, Vector3f v) { + float norm_u_norm_v = (float) sqrt(u.lengthSquared() * v.lengthSquared()); + float real_part = norm_u_norm_v + u.dot(v); + Vector3f w; + + if (real_part < 1.e-6f * norm_u_norm_v) { + /* If u and v are exactly opposite, rotate 180 degrees + * around an arbitrary orthogonal axis. Axis normalisation + * can happen later, when we normalise the quaternion. */ + real_part = 0.0f; + w = abs(u.getX()) > abs(u.getZ()) ? new SimpleVector3f(-u.getY(), u.getX(), 0.f) + : new SimpleVector3f(0.f, -u.getZ(), u.getY()); + } else { + /* Otherwise, build quaternion the standard way. */ + w = u.duplicate().cross(v); + } + + Quaternion quaternion = new ComponentsQuaternion(w.getX(), w.getY(), w.getZ(), real_part); + quaternion.normalise(); + return quaternion; + } + public static Quaternion fromAxisAndAngle(Vector3f axis, Angle angle) { Vector3f actualAxis = axis.duplicate().normalize(); @@ -40,19 +71,7 @@ public static Quaternion fromAxisAndAngle(Vector3f axis, Angle angle) { float y = actualAxis.getY() * sin_a; float z = actualAxis.getZ() * sin_a; - return new ComponentsQuaternion(x, y, z, cos_a); - } - - @Override - public Vector3f getAxis() { - float angle = (float) Math.asin(w); - float sin_a = (float) Math.sin(angle / 2); - - float x = this.x / sin_a; - float y = this.y / sin_a; - float z = this.z / sin_a; - - return new SimpleVector3f(x, y, z); + return new ComponentsQuaternion(x, y, z, clamp(cos_a, -1, 1)); } public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angleZ) { @@ -77,26 +96,67 @@ public static Quaternion zero() { return ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.zero()); } + @Override + public Vector3f getAxisOrDefault(Vector3f axis) { + float sinFromCos = (float) sqrt(Math.max(0, 1 - w * w)); + if (sinFromCos == 0 || Float.isNaN(sinFromCos)) + return axis; + + float x = this.x / sinFromCos; + float y = this.y / sinFromCos; + float z = this.z / sinFromCos; + + Vector3f vector = new SimpleVector3f(x, y, z); + if (vector.lengthSquared() == 0) + return axis; + return vector; + } + + @Override + public Vector3f getVector() { + return new SimpleVector3f(x, y, z); + } + @Override public float getX() { return x; } + @Override + public void setX(float x) { + this.x = x; + } + @Override public float getY() { return y; } + @Override + public void setY(float y) { + this.y = y; + } + @Override public float getZ() { return z; } + @Override + public void setZ(float z) { + this.z = z; + } + @Override public float getW() { return w; } + @Override + public void setW(float w) { + this.w = w; + } + @Override public void inverse() { this.x = -x; @@ -173,10 +233,10 @@ public void multiplyInv(Vector3f vec) { @Override public void multiply(float s) { - this.x*=s; - this.y*=s; - this.z*=s; - this.w*=s; + this.x *= s; + this.y *= s; + this.z *= s; + this.w *= s; } @Override @@ -184,15 +244,15 @@ public void interpolate(Quaternion quaternionEnd, float ease) { double cosHalfTheta = dot(quaternionEnd); // if qa=quaternionEnd or qa=-quaternionEnd then theta = 0 and we can return qa - if (Math.abs(cosHalfTheta) >= 1.0) { + if (abs(cosHalfTheta) >= 1.0) { return; } // Calculate temporary values. double halfTheta = Math.acos(cosHalfTheta); - double sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + double sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta); // if theta = 180 degrees then result is not fully defined // we could rotate around any axis normal to qa or quaternionEnd - if (Math.abs(sinHalfTheta) < 0) { // fabs is floating point absolute + if (abs(sinHalfTheta) < 0) { // fabs is floating point absolute this.w = (w * 0.5f + quaternionEnd.getW() * 0.5f); this.x = (x * 0.5f + quaternionEnd.getX() * 0.5f); this.y = (y * 0.5f + quaternionEnd.getY() * 0.5f); @@ -208,6 +268,17 @@ public void interpolate(Quaternion quaternionEnd, float ease) { z = (float) (z * ratioA + quaternionEnd.getZ() * ratioB); } + @Override + public Vector3f velocity(Quaternion other, float delta) { + Vector3f vel = new SimpleVector3f( + this.w * other.getX() - this.x * other.getW() - this.y * other.getZ() + this.z * other.getY(), + this.w * other.getY() + this.x * other.getZ() - this.y * other.getW() - this.z * other.getX(), + this.w * other.getZ() - this.x * other.getY() + this.y * other.getX() - this.z * other.getW() + ); + vel.mul((2 / delta)); + return vel; + } + @Override public float dot(Quaternion other) { return x * other.getX() + y * other.getY() + z * other.getZ() + w * other.getW(); @@ -215,7 +286,7 @@ public float dot(Quaternion other) { @Override public float getMagnitude() { - return (float) Math.sqrt(w * w + x * x + y * y + z * z); + return (float) sqrt(w * w + x * x + y * y + z * z); } @Override @@ -237,18 +308,8 @@ public void copy(Quaternion rotation) { } @Override - public void setX(float x) { - this.x = x; - } - - @Override - public void setY(float y) { - this.y = y; - } - - @Override - public void setZ(float z) { - this.z = z; + public JavaMathAngle getAngle() { + return JavaMathAngle.fromRadiant(2 * Math.acos(clamp(w, -1, 1))); } @Override diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index 964bf45..be199a7 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -1,17 +1,26 @@ package fr.radi3nt.maths.components.advanced.quaternions; +import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; import fr.radi3nt.maths.components.vectors.Vector3f; public interface Quaternion { float getX(); + void setX(float x); + float getY(); + void setY(float y); + float getZ(); + void setZ(float z); + float getW(); + void setW(float w); + void inverse(); void normalise(); @@ -32,6 +41,8 @@ public interface Quaternion { void interpolate(Quaternion quaternionEnd, float ease); + Vector3f velocity(Quaternion other, float delta); + float dot(Quaternion other); float getMagnitude(); @@ -42,9 +53,9 @@ public interface Quaternion { void copy(Quaternion rotation); - Vector3f getAxis(); + Vector3f getAxisOrDefault(Vector3f axis); - void setX(float x); - void setY(float y); - void setZ(float z); + Vector3f getVector(); + + Angle getAngle(); } From 28109f13d78bf0a6c022c7218ddcddab908e73bb Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 24 Aug 2023 14:36:20 +0200 Subject: [PATCH 041/125] Inverse kinematics (#4) * Added InverseKinematics module with CCD implementation * Refactoring CCDIKSolver - Removed unused methods - Simplified code - Renamed variables - Extracted methods * Removed unused import statement * Removed unused variable and its assignment * Added FABRIK solver - no constraints nor limits - converting directions to local quaternions --- InverseKinematics/pom.xml | 28 +++++ .../radi3nt/ik/solvers/IkIterativeSolver.java | 25 ++++ .../java/fr/radi3nt/ik/solvers/IkSolver.java | 7 ++ .../radi3nt/ik/solvers/ccdik/CCDIKSolver.java | 109 ++++++++++++++++++ .../fr/radi3nt/ik/solvers/ccdik/CCDJoint.java | 33 ++++++ .../constraint/HingeJointConstraint.java | 31 +++++ .../ccdik/constraint/JointConstraint.java | 7 ++ .../ccdik/constraint/NoJointConstraint.java | 17 +++ .../ik/solvers/ccdik/effectors/Effector.java | 9 ++ .../ccdik/effectors/JointsEffector.java | 43 +++++++ .../ccdik/limit/AngleClampJointLimit.java | 61 ++++++++++ .../ccdik/limit/CompositionJointLimit.java | 20 ++++ .../ik/solvers/ccdik/limit/JointLimit.java | 9 ++ .../ik/solvers/fabrik/FABRIKSolver.java | 84 ++++++++++++++ .../ik/solvers/fabrik/chain/IKChain.java | 12 ++ .../fabrik/chain/IkJointTransform.java | 23 ++++ .../ik/solvers/fabrik/chain/IkLink.java | 41 +++++++ .../solvers/fabrik/chain/SimpleIKChain.java | 106 +++++++++++++++++ pom.xml | 1 + 19 files changed, 666 insertions(+) create mode 100644 InverseKinematics/pom.xml create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkSolver.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/Effector.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/JointsEffector.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/FABRIKSolver.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IKChain.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkJointTransform.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkLink.java create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/SimpleIKChain.java diff --git a/InverseKinematics/pom.xml b/InverseKinematics/pom.xml new file mode 100644 index 0000000..c65a72b --- /dev/null +++ b/InverseKinematics/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + InverseKinematics + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java new file mode 100644 index 0000000..1798b31 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java @@ -0,0 +1,25 @@ +package fr.radi3nt.ik.solvers; + +public abstract class IkIterativeSolver implements IkSolver { + + private final int maxIterations; + protected final float allowedMarginOfError; + + public IkIterativeSolver(int maxIterations, float allowedMarginOfError) { + this.maxIterations = maxIterations; + this.allowedMarginOfError = allowedMarginOfError; + } + + + @Override + public void solve() { + for (int i = 0; i < maxIterations; i++) { + if (isInAllowedMarginOfError()) + break; + iteration(); + } + } + + protected abstract boolean isInAllowedMarginOfError(); + protected abstract void iteration(); +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkSolver.java new file mode 100644 index 0000000..fe90399 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkSolver.java @@ -0,0 +1,7 @@ +package fr.radi3nt.ik.solvers; + +public interface IkSolver { + + void solve(); + +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java new file mode 100644 index 0000000..7b95b67 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java @@ -0,0 +1,109 @@ +package fr.radi3nt.ik.solvers.ccdik; + +import fr.radi3nt.ik.solvers.IkIterativeSolver; +import fr.radi3nt.ik.solvers.ccdik.effectors.Effector; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class CCDIKSolver extends IkIterativeSolver { + + private final Effector endEffector; + private final CCDJoint[] joints; + private final Vector3f upAxis; + private Vector3f goal; + + private Vector3f lastEndEffectorWorldPosition = null; + + public CCDIKSolver(int maxIterations, float allowedMarginOfError, Vector3f goal, Effector endEffector, Vector3f upAxis, CCDJoint[] joints) { + super(maxIterations, allowedMarginOfError); + this.goal = goal; + this.endEffector = endEffector; + this.upAxis = upAxis; + this.joints = joints; + } + + @Override + protected boolean isInAllowedMarginOfError() { + return evaluateMarginOfError() <= allowedMarginOfError*allowedMarginOfError; + } + + protected float evaluateMarginOfError() { + if (lastEndEffectorWorldPosition == null) + lastEndEffectorWorldPosition = endEffector.getWorldPosition(); + return lastEndEffectorWorldPosition.duplicate().sub(goal).lengthSquared(); + } + + @Override + protected void iteration() { + for (int jointIndex = getEndJointIndex(); jointIndex >= 0; jointIndex--) { + CCDJoint joint = joints[jointIndex]; + Quaternion fromToQuaternion = getRotationBetweenEndEffectorAndGoalUsingWorldSpace(jointIndex); + joint.rotation.multiply(fromToQuaternion); + joint.constrain(); + joint.limit(); + } + } + + private Quaternion getRotationBetweenEndEffectorAndGoalUsingWorldSpace(int joinIndex) { + Vector3f ei = lastEndEffectorWorldPosition==null ? endEffector.getWorldPosition().duplicate() : lastEndEffectorWorldPosition.duplicate(); + Vector3f et = goal.duplicate(); + lastEndEffectorWorldPosition = null; + + Vector3f bonePos = getBonePos(joinIndex); + Quaternion invLinkRot = getAllPreviousRotation(joinIndex+1); + invLinkRot.inverse(); + + Vector3f localEi = convertToBoneLocalSpace(ei, bonePos, invLinkRot); + localEi.normalize(); + Vector3f localEt = convertToBoneLocalSpace(et, bonePos, invLinkRot); + localEt.normalize(); + + return ComponentsQuaternion.fromTwoVectors(localEi, localEt); + } + + private static Vector3f convertToBoneLocalSpace(Vector3f worldPosition, Vector3f bonePos, Quaternion invLinkRot) { + Vector3f localEi = worldPosition.duplicate().sub(bonePos); + invLinkRot.transform(localEi); + return localEi; + } + + private Vector3f getBonePos(int index) { + Quaternion cumulatedRotation = ComponentsQuaternion.zero(); + Vector3f worldPos = new SimpleVector3f(); + for (int i = 0; i < index; i++) { + CCDJoint joint = joints[i]; + Quaternion rotation = joint.rotation; + float length = joint.getLength(); + + cumulatedRotation.multiply(rotation); + Vector3f localTranslation = upAxis.duplicate(); + cumulatedRotation.transform(localTranslation); + localTranslation.mul(length); + worldPos.add(localTranslation); + } + return worldPos; + } + + public void setGoal(Vector3f goal) { + this.goal = goal; + } + + private Quaternion getAllPreviousRotation(int index) { + Quaternion localSpaceRotation = ComponentsQuaternion.zero(); + for (int i = 0; i < index; i++) { + Quaternion linkInverseRot = joints[i].rotation; + localSpaceRotation.multiply(linkInverseRot); + } + return localSpaceRotation; + } + + private int getEndJointIndex() { + return joints.length-1; + } + + public Vector3f getGoal() { + return goal; + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java new file mode 100644 index 0000000..878fcda --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java @@ -0,0 +1,33 @@ +package fr.radi3nt.ik.solvers.ccdik; + +import fr.radi3nt.ik.solvers.ccdik.constraint.JointConstraint; +import fr.radi3nt.ik.solvers.ccdik.limit.JointLimit; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; + +public class CCDJoint { + + private final float length; + public Quaternion rotation = ComponentsQuaternion.zero(); + + private final JointConstraint jointConstraint; + private final JointLimit jointLimit; + + public CCDJoint(float length, JointConstraint jointConstraint, JointLimit jointLimit) { + this.length = length; + this.jointConstraint = jointConstraint; + this.jointLimit = jointLimit; + } + + public void constrain() { + jointConstraint.constrain(this); + } + + public void limit() { + jointLimit.limit(this); + } + + public float getLength() { + return length; + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java new file mode 100644 index 0000000..e0633d7 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java @@ -0,0 +1,31 @@ +package fr.radi3nt.ik.solvers.ccdik.constraint; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class HingeJointConstraint implements JointConstraint { + + private final Vector3f constrainedAxis; + + public HingeJointConstraint(Vector3f constrainedAxis) { + this.constrainedAxis = constrainedAxis; + } + + @Override + public void constrain(CCDJoint ccdJoint) { + Quaternion invRot = ccdJoint.rotation.duplicate(); + invRot.inverse(); + + Vector3f parentAxis = constrainedAxis.duplicate(); + invRot.transform(parentAxis); + + Quaternion quaternion = ComponentsQuaternion.fromTwoVectors(constrainedAxis, parentAxis); + ccdJoint.rotation.multiply(quaternion); + } + + public Vector3f getConstrainedAxis() { + return constrainedAxis; + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java new file mode 100644 index 0000000..06708da --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java @@ -0,0 +1,7 @@ +package fr.radi3nt.ik.solvers.ccdik.constraint; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; + +public interface JointConstraint { + void constrain(CCDJoint ccdJoint); +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java new file mode 100644 index 0000000..4841324 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java @@ -0,0 +1,17 @@ +package fr.radi3nt.ik.solvers.ccdik.constraint; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; + +public class NoJointConstraint implements JointConstraint { + + public static NoJointConstraint INSTANCE = new NoJointConstraint(); + + private NoJointConstraint() { + + } + + @Override + public void constrain(CCDJoint ccdJoint) { + + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/Effector.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/Effector.java new file mode 100644 index 0000000..759e6ba --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/Effector.java @@ -0,0 +1,9 @@ +package fr.radi3nt.ik.solvers.ccdik.effectors; + +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface Effector { + + Vector3f getWorldPosition(); + +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/JointsEffector.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/JointsEffector.java new file mode 100644 index 0000000..ad3b632 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/effectors/JointsEffector.java @@ -0,0 +1,43 @@ +package fr.radi3nt.ik.solvers.ccdik.effectors; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class JointsEffector implements Effector { + + private final Vector3f startPos; + private final Vector3f upAxis; + + private final CCDJoint[] joints; + + public JointsEffector(Vector3f startPos, Vector3f upAxis, CCDJoint... joints) { + this.startPos = startPos; + this.joints = joints; + this.upAxis = upAxis; + } + + @Override + public Vector3f getWorldPosition() { + return getBonePos().add(startPos); + } + + private Vector3f getBonePos() { + Quaternion cumulatedRotation = ComponentsQuaternion.zero(); + Vector3f worldPos = new SimpleVector3f(); + for (CCDJoint joint : joints) { + Quaternion rotation = joint.rotation; + float length = joint.getLength(); + + cumulatedRotation.multiply(rotation); + Vector3f localTranslation = upAxis.duplicate(); + cumulatedRotation.transform(localTranslation); + localTranslation.mul(length); + worldPos.add(localTranslation); + } + return worldPos; + } + +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java new file mode 100644 index 0000000..2e7e23f --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java @@ -0,0 +1,61 @@ +package fr.radi3nt.ik.solvers.ccdik.limit; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.ik.solvers.ccdik.constraint.HingeJointConstraint; +import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class AngleClampJointLimit implements JointLimit { + + private final Angle minAngle; + private final Angle maxAngle; + private final Quaternion zeroAngle; + private final Vector3f defaultAxis; + + public AngleClampJointLimit(Angle minAngle, Angle maxAngle, Quaternion zeroAngle, Vector3f defaultAxis) { + this.minAngle = minAngle; + this.maxAngle = maxAngle; + this.zeroAngle = zeroAngle; + this.defaultAxis = defaultAxis; + } + + public AngleClampJointLimit(Angle minAngle, Angle maxAngle, HingeJointConstraint constraint) { + this(minAngle, maxAngle, constraint.getConstrainedAxis()); + } + + public AngleClampJointLimit(Angle minAngle, Angle maxAngle, Vector3f axis) { + this(minAngle, maxAngle, ComponentsQuaternion.fromAxisAndAngle(axis, JavaMathAngle.zero()), axis.duplicate()); + } + + @Override + public void limit(CCDJoint ccdJoint) { + + double minAngleRadiant = minAngle.getRadiant(); + double maxAngleRadiant = maxAngle.getRadiant(); + + double max = Math.max(maxAngleRadiant, minAngleRadiant); + double min = Math.min(maxAngleRadiant, minAngleRadiant); + + Quaternion q1 = ccdJoint.rotation.duplicate(); + Quaternion q2 = zeroAngle.duplicate(); + q1.inverse(); + q1.multiply(q2); + + double angle = (2 * Math.atan2(q1.getVector().length(), q1.getW())); + + Vector3f axis = ccdJoint.rotation.getAxisOrDefault(defaultAxis.duplicate()); + if (axis.dot(defaultAxis)<0) { + angle=-angle; + axis.negate(); + } + + angle = Maths.clamp(angle, min, max); + + Quaternion result = ComponentsQuaternion.fromAxisAndAngle(axis, JavaMathAngle.fromRadiant(angle)); + ccdJoint.rotation.copy(result); + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java new file mode 100644 index 0000000..a9945a2 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java @@ -0,0 +1,20 @@ +package fr.radi3nt.ik.solvers.ccdik.limit; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; + +public class CompositionJointLimit implements JointLimit { + + private final JointLimit[] jointLimits; + + public CompositionJointLimit(JointLimit... jointLimits) { + this.jointLimits = jointLimits; + } + + + @Override + public void limit(CCDJoint ccdJoint) { + for (JointLimit jointLimit : jointLimits) { + jointLimit.limit(ccdJoint); + } + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java new file mode 100644 index 0000000..993575e --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java @@ -0,0 +1,9 @@ +package fr.radi3nt.ik.solvers.ccdik.limit; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; + +public interface JointLimit { + + void limit(CCDJoint ccdJoint); + +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/FABRIKSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/FABRIKSolver.java new file mode 100644 index 0000000..5939701 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/FABRIKSolver.java @@ -0,0 +1,84 @@ +package fr.radi3nt.ik.solvers.fabrik; + +import fr.radi3nt.ik.solvers.IkIterativeSolver; +import fr.radi3nt.ik.solvers.fabrik.chain.IKChain; +import fr.radi3nt.ik.solvers.fabrik.chain.IkJointTransform; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class FABRIKSolver extends IkIterativeSolver { + + private final IKChain chain; + private IkJointTransform goal = new IkJointTransform(new SimpleVector3f(), ComponentsQuaternion.zero()); + private IkJointTransform start = new IkJointTransform(new SimpleVector3f(), ComponentsQuaternion.zero()); + + public FABRIKSolver(int maxIterations, float allowedMarginOfError, IKChain chain) { + super(maxIterations, allowedMarginOfError); + this.chain = chain; + } + + @Override + public void solve() { + Vector3f dirToGoal = goal.getResultPosition().duplicate().sub(start.getResultPosition()); + float chainLength = chain.getTotalLength(); + if (dirToGoal.lengthSquared()>chainLength*chainLength) + extendTowardsGoal(); + else + super.solve(); + } + + private void extendTowardsGoal() { + chain.setEndPointAndReturnCalculatedStart(goal, 0); + IkJointTransform lastTransform = chain.setStartPointAndReturnCalculatedEnd(start, 0); + for (int i = 1; i < chain.getLinkAmount(); i++) { + chain.setEndPointAndReturnCalculatedStart(goal, i); + lastTransform = chain.setStartPointAndReturnCalculatedEnd(lastTransform, i); + } + } + + @Override + protected void iteration() { + backwardsPass(); + forwardPass(); + } + + private void backwardsPass() { + IkJointTransform lastTransform = goal; + for (int i = getEndLinkIndex(); i >= 0; i--) { + lastTransform = chain.setEndPointAndReturnCalculatedStart(lastTransform, i); + } + } + + private void forwardPass() { + IkJointTransform lastTransform = start; + for (int i = 0; i < chain.getLinkAmount(); i++) { + lastTransform = chain.setStartPointAndReturnCalculatedEnd(lastTransform, i); + } + } + + @Override + protected boolean isInAllowedMarginOfError() { + return evaluateMarginOfError() <= allowedMarginOfError*allowedMarginOfError; + } + + protected float evaluateMarginOfError() { + return getTipJointPosition().duplicate().sub(goal.getResultPosition()).lengthSquared(); + } + + private Vector3f getTipJointPosition() { + return chain.getEndPoint(getEndLinkIndex()).getResultPosition(); + } + + private int getEndLinkIndex() { + return chain.getLinkAmount() - 1; + } + + public void setStart(IkJointTransform start) { + this.start = start; + } + + public void setGoal(IkJointTransform goal) { + this.goal = goal; + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IKChain.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IKChain.java new file mode 100644 index 0000000..9369a4b --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IKChain.java @@ -0,0 +1,12 @@ +package fr.radi3nt.ik.solvers.fabrik.chain; + +public interface IKChain { + + IkJointTransform setEndPointAndReturnCalculatedStart(IkJointTransform transform, int index); + IkJointTransform setStartPointAndReturnCalculatedEnd(IkJointTransform transform, int index); + IkJointTransform getEndPoint(int index); + IkJointTransform getStartPoint(int index); + float getTotalLength(); + int getLinkAmount(); + +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkJointTransform.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkJointTransform.java new file mode 100644 index 0000000..b833056 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkJointTransform.java @@ -0,0 +1,23 @@ +package fr.radi3nt.ik.solvers.fabrik.chain; + +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class IkJointTransform { + + private final Vector3f resultPosition; + private final Quaternion resultRotation; + + public IkJointTransform(Vector3f resultPosition, Quaternion resultRotation) { + this.resultPosition = resultPosition; + this.resultRotation = resultRotation; + } + + public Vector3f getResultPosition() { + return resultPosition; + } + + public Quaternion getResultRotation() { + return resultRotation; + } +} diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkLink.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkLink.java new file mode 100644 index 0000000..d43a43b --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/IkLink.java @@ -0,0 +1,41 @@ +package fr.radi3nt.ik.solvers.fabrik.chain; + +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class IkLink { + + private final float length; + + private IkJointTransform startTransform; + private IkJointTransform endTransform; + + public IkLink(float length, IkJointTransform startTransform, IkJointTransform endTransform) { + this.length = length; + this.startTransform = startTransform; + this.endTransform = endTransform; + } + + public float getLength() { + return length; + } + + public IkJointTransform getStartTransform() { + return startTransform; + } + + public void setStartTransform(IkJointTransform startTransform) { + this.startTransform = startTransform; + } + + public IkJointTransform getEndTransform() { + return endTransform; + } + + public void setEndTransform(IkJointTransform endTransform) { + this.endTransform = endTransform; + } + + public Vector3f getDirection() { + return endTransform.getResultPosition().duplicate().sub(startTransform.getResultPosition()).normalize(); + } +} \ No newline at end of file diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/SimpleIKChain.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/SimpleIKChain.java new file mode 100644 index 0000000..0cb3f66 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/fabrik/chain/SimpleIKChain.java @@ -0,0 +1,106 @@ +package fr.radi3nt.ik.solvers.fabrik.chain; + +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class SimpleIKChain implements IKChain { + + private final IkLink[] ikLinks; + private final float totalLength; + + public SimpleIKChain(IkLink... ikLinks) { + this.ikLinks = ikLinks; + float calculatingTotalLength = 0; + for (IkLink ikLink : ikLinks) { + calculatingTotalLength+= ikLink.getLength(); + } + totalLength = calculatingTotalLength; + } + + @Override + public IkJointTransform setEndPointAndReturnCalculatedStart(IkJointTransform transform, int index) { + IkLink currentLink = ikLinks[index]; + currentLink.setEndTransform(transform); + + calculateStartFromEnd(currentLink, index); + + return currentLink.getStartTransform(); + } + + private void calculateStartFromEnd(IkLink currentLink, int index) { + Vector3f startPos = currentLink.getStartTransform().getResultPosition(); + Vector3f endPos = currentLink.getEndTransform().getResultPosition(); + Vector3f dirEndToStart = startPos.duplicate().sub(endPos); + dirEndToStart.normalize(); + dirEndToStart.mul(currentLink.getLength()); + Quaternion quaternion = ComponentsQuaternion.fromTwoVectors(dirEndToStart, new SimpleVector3f(0, 0, 1)); + + Quaternion localSpaceRotation = ComponentsQuaternion.zero(); + for (int i = 0; i < index; i++) { + Quaternion linkInverseRot = ikLinks[i].getStartTransform().getResultRotation().duplicate(); + localSpaceRotation.multiply(linkInverseRot); + } + localSpaceRotation.inverse(); + + localSpaceRotation.multiply(quaternion); + + currentLink.setStartTransform(new IkJointTransform(endPos.duplicate().sub(dirEndToStart), localSpaceRotation)); + } + + @Override + public IkJointTransform setStartPointAndReturnCalculatedEnd(IkJointTransform transform, int index) { + IkLink currentLink = ikLinks[index]; + currentLink.setStartTransform(transform); + + calculateEndFromStart(currentLink, index); + + return currentLink.getEndTransform(); + } + + private void calculateEndFromStart(IkLink currentLink, int index) { + Vector3f startPos = currentLink.getStartTransform().getResultPosition(); + Vector3f endPos = currentLink.getEndTransform().getResultPosition(); + Vector3f dirStartToEnd = endPos.duplicate().sub(startPos); + dirStartToEnd.normalize(); + + Quaternion quaternion = ComponentsQuaternion.fromTwoVectors(new SimpleVector3f(0, 0, 1), dirStartToEnd); + + Quaternion localSpaceRotation = ComponentsQuaternion.zero(); + for (int i = 0; i < index; i++) { + Quaternion linkInverseRot = ikLinks[i].getStartTransform().getResultRotation().duplicate(); + localSpaceRotation.multiply(linkInverseRot); + } + localSpaceRotation.inverse(); + + localSpaceRotation.multiply(quaternion); + + currentLink.setEndTransform(new IkJointTransform(startPos.duplicate().sub(dirStartToEnd), ComponentsQuaternion.zero())); + currentLink.setStartTransform(new IkJointTransform(currentLink.getStartTransform().getResultPosition(), localSpaceRotation)); + } + + @Override + public IkJointTransform getEndPoint(int index) { + return ikLinks[index].getEndTransform(); + } + + @Override + public IkJointTransform getStartPoint(int index) { + return ikLinks[index].getStartTransform(); + } + + public IkLink[] getIkLinks() { + return ikLinks; + } + + @Override + public float getTotalLength() { + return totalLength; + } + + @Override + public int getLinkAmount() { + return ikLinks.length; + } +} diff --git a/pom.xml b/pom.xml index ca5214e..d6ce306 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ DataStructures SplineHelper AnimationHelper + InverseKinematics From 78ecbba0d4e3641df6f27793dbd71f6f12899dfc Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 24 Aug 2023 15:57:45 +0200 Subject: [PATCH 042/125] Miscellaneous (#6) * Organised ArgParser imports * Expended imports * Removed unused and deprecated classes * Added starting delta to avoid issues like diving by 0 on the first use --- .../main/java/fr/radi3nt/argp/ArgParser.java | 2 +- .../radi3nt/argp/parsing/ArgumentParser.java | 2 +- .../fr/radi3nt/argp/scheme/ArgScheme.java | 2 +- .../logs/implementations/TemplateLog.java | 4 +- .../radi3nt/maths/components/Quaternion.java | 146 ------------------ .../radi3nt/maths/components/Transform.java | 91 ----------- .../java/fr/radi3nt/timer/JavaSyncTimer.java | 8 + 7 files changed, 14 insertions(+), 241 deletions(-) delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/Quaternion.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/Transform.java diff --git a/ArgParser/src/main/java/fr/radi3nt/argp/ArgParser.java b/ArgParser/src/main/java/fr/radi3nt/argp/ArgParser.java index 03ea377..98487f1 100644 --- a/ArgParser/src/main/java/fr/radi3nt/argp/ArgParser.java +++ b/ArgParser/src/main/java/fr/radi3nt/argp/ArgParser.java @@ -2,8 +2,8 @@ import fr.radi3nt.argp.exceptions.ArgumentException; import fr.radi3nt.argp.parsing.ArgumentParser; -import fr.radi3nt.argp.parsing.result.ArgumentParseResult; import fr.radi3nt.argp.parsing.repo.ArgumentRepository; +import fr.radi3nt.argp.parsing.result.ArgumentParseResult; import fr.radi3nt.argp.parsing.result.ParserResult; import fr.radi3nt.argp.parsing.result.ParserResultBuilder; import fr.radi3nt.argp.parsing.result.ParserResultBuilderFactory; diff --git a/ArgParser/src/main/java/fr/radi3nt/argp/parsing/ArgumentParser.java b/ArgParser/src/main/java/fr/radi3nt/argp/parsing/ArgumentParser.java index 8776dbe..04aa183 100644 --- a/ArgParser/src/main/java/fr/radi3nt/argp/parsing/ArgumentParser.java +++ b/ArgParser/src/main/java/fr/radi3nt/argp/parsing/ArgumentParser.java @@ -1,7 +1,7 @@ package fr.radi3nt.argp.parsing; -import fr.radi3nt.argp.parsing.result.ArgumentParseResult; import fr.radi3nt.argp.exceptions.ParsingException; +import fr.radi3nt.argp.parsing.result.ArgumentParseResult; public interface ArgumentParser { diff --git a/ArgParser/src/main/java/fr/radi3nt/argp/scheme/ArgScheme.java b/ArgParser/src/main/java/fr/radi3nt/argp/scheme/ArgScheme.java index f8364f5..edbaa5a 100644 --- a/ArgParser/src/main/java/fr/radi3nt/argp/scheme/ArgScheme.java +++ b/ArgParser/src/main/java/fr/radi3nt/argp/scheme/ArgScheme.java @@ -1,7 +1,7 @@ package fr.radi3nt.argp.scheme; -import fr.radi3nt.argp.parsing.result.ParserResult; import fr.radi3nt.argp.exceptions.ArgumentException; +import fr.radi3nt.argp.parsing.result.ParserResult; /** * Argument scheme precise the validity of a chain of arguments diff --git a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/TemplateLog.java b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/TemplateLog.java index 342d760..0a58162 100644 --- a/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/TemplateLog.java +++ b/LogHelper/src/main/java/fr/radi3nt/loghelper/logs/logs/implementations/TemplateLog.java @@ -3,7 +3,9 @@ import fr.radi3nt.loghelper.logs.actions.LogAction; import fr.radi3nt.loghelper.logs.logs.WritableLog; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class TemplateLog implements WritableLog { diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Quaternion.java deleted file mode 100644 index 7f8819c..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Quaternion.java +++ /dev/null @@ -1,146 +0,0 @@ -package fr.radi3nt.maths.components; - - -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.creator.VectorFactory; - -public class Quaternion { - - private float x; - private float y; - private float z; - private float w; - - public Quaternion(float x, float y, float z, float w){ - this.setX(x); - this.setY(y); - this.setZ(z); - this.setW(w); - } - - public Quaternion(Vector3f v, float w){ - this.setX(v.getX()); - this.setY(v.getY()); - this.setZ(v.getZ()); - this.setW(w); - } - - public float length() - { - return (float) Math.sqrt(x*x + y*y + z*z + w*w); - } - - public Quaternion normalize() - { - float length = length(); - - x /= length; - y /= length; - z /= length; - w /= length; - - return this; - } - - public Quaternion conjugate() - { - return new Quaternion (-x, -y, -z, w); - } - - public Quaternion mul(Quaternion r) - { - float w_ = w * r.getW() - x * r.getX() - y * r.getY() - z * r.getZ(); - float x_ = x * r.getW() + w * r.getX() + y * r.getZ() - z * r.getY(); - float y_ = y * r.getW() + w * r.getY() + z * r.getX() - x * r.getZ(); - float z_ = z * r.getW() + w * r.getZ() + x * r.getY() - y * r.getX(); - - return new Quaternion(x_, y_, z_, w_); - } - - public Quaternion mul(Vector3f r) - { - float w_ = -x * r.getX() - y * r.getY() - z * r.getZ(); - float x_ = w * r.getX() + y * r.getZ() - z * r.getY(); - float y_ = w * r.getY() + z * r.getX() - x * r.getZ(); - float z_ = w * r.getZ() + x * r.getY() - y * r.getX(); - - return new Quaternion(x_, y_, z_, w_); - } - - public Quaternion div(float r) - { - float w_ = w/r; - float x_ = x/r; - float y_ = y/r; - float z_ = z/r; - return new Quaternion(x_, y_, z_, w_); - } - - public Quaternion mul(float r) - { - float w_ = w*r; - float x_ = x*r; - float y_ = y*r; - float z_ = z*r; - return new Quaternion(x_, y_, z_, w_); - } - - public Quaternion sub(Quaternion r) - { - float w_ = w - r.getW(); - float x_ = x - r.getX(); - float y_ = y - r.getY(); - float z_ = z - r.getZ(); - return new Quaternion(x_, y_, z_, w_); - } - - public Quaternion add(Quaternion r) - { - float w_ = w + r.getW(); - float x_ = x + r.getX(); - float y_ = y + r.getY(); - float z_ = z + r.getZ(); - return new Quaternion(x_, y_, z_, w_); - } - - public Vector3f xyz(){ - return VectorFactory.createVector3f(x,y,z); - } - - public String toString() - { - return "[" + this.x + "," + this.y + "," + this.z + "," + this.w + "]"; - } - - public float getX() { - return x; - } - - public void setX(float x) { - this.x = x; - } - - public float getY() { - return y; - } - - public void setY(float y) { - this.y = y; - } - - public float getZ() { - return z; - } - - public void setZ(float z) { - this.z = z; - } - - public float getW() { - return w; - } - - public void setW(float w) { - this.w = w; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Transform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/Transform.java deleted file mode 100644 index 3bbbdac..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/Transform.java +++ /dev/null @@ -1,91 +0,0 @@ -package fr.radi3nt.maths.components; - -import fr.radi3nt.maths.components.matrices.Matrix; -import fr.radi3nt.maths.components.matrices.implementation.MatrixCreator; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class Transform { - - private Vector3f translation; - private Vector3f rotation; - private Vector3f scaling; - - private Matrix modelMatrix; - private Matrix worldMatrix; - - private boolean changed = false; - - public Transform() - { - setTranslation(new SimpleVector3f(0,0,0)); - setRotation(new SimpleVector3f(0,0,0)); - setScaling(new SimpleVector3f(1,1,1)); - } - - public Matrix getWorldMatrix() - { - checkUpdate(); - return worldMatrix; - } - - public Matrix getModelMatrix() - { - checkUpdate(); - return modelMatrix; - } - - public Vector3f getTranslation() { - changed(); - return translation; - } - - public void setTranslation(Vector3f translation) { - this.translation = translation; - changed(); - } - - public Vector3f getRotation() { - changed(); - return rotation; - } - - public void setRotation(Vector3f rotation) { - this.rotation = rotation; - changed(); - } - - public Vector3f getScaling() { - changed(); - return scaling; - } - - public void setScaling(Vector3f scaling) { - this.scaling = scaling; - changed(); - } - - private void changed() { - changed = true; - } - - private void updateModelMatrix() { - Matrix rotate = MatrixCreator.createMatrix().rotate((float) Math.toRadians(rotation.getX()), new SimpleVector3f(1, 0, 0)).rotate((float) Math.toRadians(rotation.getY()), new SimpleVector3f(0, 1, 0)).rotate((float) Math.toRadians(rotation.getZ()), new SimpleVector3f(0, 0, 1)); - this.modelMatrix = rotate; - } - - private void updateWorldMatrix() { - Matrix translate = MatrixCreator.createMatrix().translation(translation); - Matrix rotate = MatrixCreator.createMatrix().rotate((float) Math.toRadians(rotation.getX()), new SimpleVector3f(1, 0, 0)).rotate((float) Math.toRadians(rotation.getY()), new SimpleVector3f(0, 1, 0)).rotate((float) Math.toRadians(rotation.getZ()), new SimpleVector3f(0, 0, 1)); - Matrix scale = MatrixCreator.createMatrix().scaling(scaling); - worldMatrix = translate.mul(rotate).mul(scale); - } - - private void checkUpdate() { - if (changed) { - updateWorldMatrix(); - updateModelMatrix(); - } - changed = false; - } -} diff --git a/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java b/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java index 45a9404..9389652 100644 --- a/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java +++ b/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java @@ -7,6 +7,14 @@ public class JavaSyncTimer implements SyncTimer { private double fps; private double delta; + public JavaSyncTimer(double delta) { + this.delta = delta; + this.fps = 1d / delta; + } + + public JavaSyncTimer() { + } + @Override public void start() { lastTime = System.nanoTime(); From 4413c3ef36fdfc4c960f522d3b563105527eb4d2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 13 Sep 2023 21:44:45 +0200 Subject: [PATCH 043/125] Pathfinding (#7) * Added Pathfinding module (implemented A*) * Fixed issue where the node was never opened --- Pathfinding/pom.xml | 28 ++++ .../radi3nt/pathfinding/AStarPathfinder.java | 127 ++++++++++++++++++ .../heuristic/HeuristicEvaluator.java | 10 ++ .../heuristic/ManhattanDistance.java | 22 +++ .../heuristic/SquaredDistance.java | 19 +++ .../heuristic/WeightedHeuristicDistance.java | 30 +++++ .../fr/radi3nt/pathfinding/node/CostData.java | 23 ++++ .../fr/radi3nt/pathfinding/node/FindNode.java | 85 ++++++++++++ .../radi3nt/pathfinding/node/NodeStatus.java | 9 ++ .../fr/radi3nt/pathfinding/node/PathNode.java | 10 ++ .../node/PathfinderPointSupplier.java | 12 ++ .../radi3nt/pathfinding/path/IndexedPath.java | 42 ++++++ .../fr/radi3nt/pathfinding/path/Path.java | 15 +++ .../path/optimisation/PathOptimiser.java | 11 ++ .../optimisation/SimplifyPathOptimiser.java | 65 +++++++++ .../path/optimisation/SimplifyPredicate.java | 10 ++ .../StraightLineSimplification.java | 18 +++ .../pathfinding/tracking/Neighbour.java | 23 ++++ .../tracking/queue/PathPointQueue.java | 14 ++ .../queue/PriorityPathPointQueue.java | 36 +++++ .../radi3nt/spline/curve/curves/BCurve.java | 27 ---- .../spline/curve/curves/bcurve/BCurve.java | 29 ++++ 22 files changed, 638 insertions(+), 27 deletions(-) create mode 100644 Pathfinding/pom.xml create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/heuristic/HeuristicEvaluator.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/heuristic/ManhattanDistance.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/heuristic/SquaredDistance.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/heuristic/WeightedHeuristicDistance.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/node/CostData.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/node/FindNode.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/node/NodeStatus.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/node/PathNode.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/node/PathfinderPointSupplier.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/IndexedPath.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/Path.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/PathOptimiser.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/tracking/Neighbour.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/tracking/queue/PathPointQueue.java create mode 100644 Pathfinding/src/main/java/fr/radi3nt/pathfinding/tracking/queue/PriorityPathPointQueue.java delete mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java diff --git a/Pathfinding/pom.xml b/Pathfinding/pom.xml new file mode 100644 index 0000000..fe8847b --- /dev/null +++ b/Pathfinding/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + Pathfinding + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java new file mode 100644 index 0000000..c612499 --- /dev/null +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java @@ -0,0 +1,127 @@ +package fr.radi3nt.pathfinding; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.pathfinding.heuristic.HeuristicEvaluator; +import fr.radi3nt.pathfinding.node.*; +import fr.radi3nt.pathfinding.path.IndexedPath; +import fr.radi3nt.pathfinding.path.Path; +import fr.radi3nt.pathfinding.path.optimisation.PathOptimiser; +import fr.radi3nt.pathfinding.tracking.Neighbour; +import fr.radi3nt.pathfinding.tracking.queue.PathPointQueue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class AStarPathfinder { + + private static final int MAX_ITERATIONS = 100_000; + private final PathPointQueue pathQueue; + private final PathfinderPointSupplier pathfinderPointSupplier; + private final HeuristicEvaluator heuristicEvaluator; + private final Collection pathOptimisers; + private final float reachThreshold; + private final float pathfindingLimit; + + public AStarPathfinder(PathPointQueue pathBuilder, PathfinderPointSupplier pathfinderPointSupplier, HeuristicEvaluator distanceCalculator, Collection pathOptimisers, float reachThreshold, float pathfindingLimit) { + this.pathQueue = pathBuilder; + this.pathfinderPointSupplier = pathfinderPointSupplier; + this.heuristicEvaluator = distanceCalculator; + this.pathOptimisers = pathOptimisers; + this.reachThreshold = reachThreshold; + this.pathfindingLimit = pathfindingLimit; + } + + public Path find(Vector3f start, Vector3f end) { + pathQueue.clear(); + pathfinderPointSupplier.prepare(); + + FindNode startPoint = pathfinderPointSupplier.pointFromPosition(start); + + FindNode lastPoint = startPoint; + float lastDistanceToEnd = heuristicEvaluator.distanceBetween(startPoint.getFloatPosition(), end); + startPoint.set(0, 0, lastDistanceToEnd); + + pathQueue.queue(startPoint); + + boolean endFound = false; + + int iterations = 0; + while (pathQueue.hasPoints() && !endFound && iterations= pathfindingLimit) + continue; + + boolean opened = neighbourPoint.getStatus()== NodeStatus.OPENED; + if (opened && neighbourCostData.accumulatedCostFromStart pathNodes = new ArrayList<>(); + + FindNode current = lastPoint; + while (current!=null) { + pathNodes.add(pathfinderPointSupplier.nodeForPoint(current)); + current = current.getPrevious(); + } + + Collections.reverse(pathNodes); + + for (PathOptimiser pathOptimiser : pathOptimisers) { + pathNodes = pathOptimiser.optimise(pathNodes); + } + + return new IndexedPath(pathNodes.toArray(new PathNode[0])); + } + + private boolean isEnd(Vector3f end, FindNode current) { + return current.getFloatPosition().duplicate().sub(end).lengthSquared() { + + private final Vector3i position; + private final CostData costData; + private FindNode previous; + private NodeStatus nodeStatus = NodeStatus.UNDISCOVERED; + + public FindNode(Vector3i position, float weight) { + this.position = position; + this.costData = new CostData(weight); + } + + public void open() { + nodeStatus = NodeStatus.OPENED; + } + + public void visit() { + nodeStatus = NodeStatus.VISITED; + } + + public NodeStatus getStatus() { + return nodeStatus; + } + + public void set(float distanceFromStart, float accumulatedCostFromStart, float distanceFromEnd) { + costData.set(distanceFromStart, accumulatedCostFromStart, distanceFromEnd); + } + + public void set(float distanceFromStart, float accumulatedCostFromStart, float distanceFromEnd, FindNode previous) { + set(distanceFromStart, accumulatedCostFromStart, distanceFromEnd); + this.previous = previous; + } + + public boolean isCurrentPathFaster(float accumulatedOther) { + return costData.accumulatedCostFromStart optimise(List pathNodes); + +} diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java new file mode 100644 index 0000000..b04e174 --- /dev/null +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java @@ -0,0 +1,65 @@ +package fr.radi3nt.pathfinding.path.optimisation; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.pathfinding.node.PathNode; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class SimplifyPathOptimiser implements PathOptimiser { + + private final Collection simplifyPredicates; + + public SimplifyPathOptimiser(Collection simplifyPredicates) { + this.simplifyPredicates = simplifyPredicates; + } + + public SimplifyPathOptimiser(SimplifyPredicate... simplifyPredicates) { + this(new ArrayList<>(Arrays.asList(simplifyPredicates))); + } + + @Override + public List optimise(List pathNodes) { + List result = new ArrayList<>(); + PathNode lastNode = pathNodes.get(0); + Vector3f lastDirection = null; + + result.add(pathNodes.get(0)); + + for (int i = 1; i < pathNodes.size()-1; i++) { + PathNode currentNode = pathNodes.get(i); + PathNode nextNode = pathNodes.get(i+1); + Vector3f currentPos = currentNode.getPosition(); + Vector3f nextPos = nextNode.getPosition(); + + if (lastDirection==null) { + lastDirection = currentPos.duplicate().sub(lastNode.getPosition()); + lastDirection.normalize(); + } + + Vector3f directionToNext = nextPos.duplicate().sub(currentPos); + directionToNext.normalize(); + + if (canSimplify(directionToNext, lastDirection, lastNode, currentNode, nextNode)) + continue; + + result.add(currentNode); + lastNode = currentNode; + lastDirection = null; + } + + result.add(pathNodes.get(pathNodes.size()-1)); + + return result; + } + + protected boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos) { + for (SimplifyPredicate simplifyPredicate : simplifyPredicates) { + if (simplifyPredicate.canSimplify(directionToNext, lastDirection, lastPos, currentPos, nextPos)) + return true; + } + return false; + } +} diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java new file mode 100644 index 0000000..dc00c07 --- /dev/null +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java @@ -0,0 +1,10 @@ +package fr.radi3nt.pathfinding.path.optimisation; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.pathfinding.node.PathNode; + +public interface SimplifyPredicate { + + boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos); + +} diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java new file mode 100644 index 0000000..158e788 --- /dev/null +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java @@ -0,0 +1,18 @@ +package fr.radi3nt.pathfinding.path.optimisation; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.pathfinding.node.PathNode; + +public class StraightLineSimplification implements SimplifyPredicate { + + private final float threshold; + + public StraightLineSimplification(float threshold) { + this.threshold = threshold; + } + + @Override + public boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos) { + return directionToNext.duplicate().sub(lastDirection).lengthSquared() finderPoints = new PriorityQueue<>(); + + @Override + public FindNode dequeue() { + return finderPoints.poll(); + } + + @Override + public void queue(FindNode finderPoint) { + finderPoints.add(finderPoint); + } + + @Override + public boolean hasPoints() { + return !finderPoints.isEmpty(); + } + + @Override + public void clear() { + finderPoints.clear(); + } + + @Override + public void update(FindNode neighbour) { + finderPoints.remove(neighbour); + finderPoints.add(neighbour); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java deleted file mode 100644 index 6def916..0000000 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/BCurve.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.radi3nt.spline.curve.curves; - -import fr.radi3nt.spline.curve.CharacteristicCurve; - -public class BCurve extends CharacteristicCurve { - - private final float pointA; - private final float pointB; - private final float pointC; - private final float pointD; - - public BCurve(float pointA, float pointB, float pointC, float pointD) { - this.pointA = pointA; - this.pointB = pointB; - this.pointC = pointC; - this.pointD = pointD; - } - - @Override - protected float computeP(float a, float t, float t2, float t3) { - float p = a * (pointA + 4*pointB + pointC) - + t *(-3*pointA + 3*pointC) - + t2 *(3*pointA - 6*pointB + 3*pointC) - + t3 *(-pointA + 3*pointB - 3*pointC + pointD); - return p/6; - } -} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java new file mode 100644 index 0000000..f1da16b --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java @@ -0,0 +1,29 @@ +package fr.radi3nt.spline.curve.curves.bcurve; + +import fr.radi3nt.spline.curve.CharacteristicCurve; + +public class BCurve extends CharacteristicCurve { + + private final BCurveController controller; + + public BCurve(BCurveController controller) { + this.controller = controller; + } + + @Override + protected float computeP(float a, float t, float t2, float t3) { + float pointA = controller.getPositionA(); + float pointB = controller.getPositionB(); + float pointC = controller.getPositionC(); + float pointD = controller.getPositionD(); + float p = a * (pointA + 4*pointB + pointC) + + t *(-3*pointA + 3*pointC) + + t2 *(3*pointA - 6*pointB + 3*pointC) + + t3 *(-pointA + 3*pointB - 3*pointC + pointD); + return p/6; + } + + public BCurveController getController() { + return controller; + } +} From 99fb01745707ef6ab17bfdfc042627c38f521bfd Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 13 Sep 2023 23:07:34 +0200 Subject: [PATCH 044/125] BSplines (#8) * Added BSplines * Re-organised SplineHelper module --- .../spline/BezierKeyedSplineBuilder.java | 2 +- .../spline/curve/curves/HermiteCurve.java | 1 + .../curve/curves/bcurve/BCurveController.java | 12 ++++++ .../curves/{ => bezier}/CubicBezierCurve.java | 4 +- .../bezier}/CubicBezierCurveController.java | 2 +- .../bezier/dim1/CubicBezierSplineBuilder.java | 2 +- .../dim1/CubicBezierSplineController.java | 1 + .../DirectCubicBezierCurveController.java | 2 + .../InferredCubicBezierCurveController.java | 2 + .../builder/bspline/dim1/BSplineBuilder.java | 36 ++++++++++++++++ .../bspline/dim1/BSplineController.java | 24 +++++++++++ .../bspline/dim1/DirectBCurveController.java | 39 ++++++++++++++++++ .../dim1/InferredBCurveController.java | 41 +++++++++++++++++++ .../bspline/dim3/BSplineBuilder3D.java | 37 +++++++++++++++++ .../bspline/dim3/BSplineController3D.java | 20 +++++++++ .../dimensions/EncapsulatingSpline3D.java | 4 ++ 16 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java rename SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/{ => bezier}/CubicBezierCurve.java (88%) rename SplineHelper/src/main/java/fr/radi3nt/spline/{splines/builder/bezier/dim1 => curve/curves/bezier}/CubicBezierCurveController.java (75%) create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java index f59ff49..5c84a86 100644 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java +++ b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java @@ -4,7 +4,7 @@ import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; import fr.radi3nt.spline.curve.Curve; -import fr.radi3nt.spline.curve.curves.CubicBezierCurve; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; import fr.radi3nt.spline.splines.CollectionSpline; import fr.radi3nt.spline.splines.Spline; import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java index 295230e..c5522ca 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java @@ -1,6 +1,7 @@ package fr.radi3nt.spline.curve.curves; import fr.radi3nt.spline.curve.CharacteristicCurve; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; public class HermiteCurve extends CharacteristicCurve { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java new file mode 100644 index 0000000..bfced96 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java @@ -0,0 +1,12 @@ +package fr.radi3nt.spline.curve.curves.bcurve; + +import fr.radi3nt.spline.curve.controller.CurveController; + +public interface BCurveController extends CurveController { + + float getPositionA(); + float getPositionB(); + float getPositionC(); + float getPositionD(); + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java similarity index 88% rename from SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java index 57db245..a1f3fe8 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/CubicBezierCurve.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java @@ -1,7 +1,7 @@ -package fr.radi3nt.spline.curve.curves; +package fr.radi3nt.spline.curve.curves.bezier; import fr.radi3nt.spline.curve.CharacteristicCurve; -import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierCurveController; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController; public class CubicBezierCurve extends CharacteristicCurve { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java similarity index 75% rename from SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java index 7415ad0..82fd6e8 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierCurveController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java @@ -1,4 +1,4 @@ -package fr.radi3nt.spline.splines.builder.bezier.dim1; +package fr.radi3nt.spline.curve.curves.bezier; public interface CubicBezierCurveController { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java index 285ac7d..8299d48 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java @@ -1,6 +1,6 @@ package fr.radi3nt.spline.splines.builder.bezier.dim1; -import fr.radi3nt.spline.curve.curves.CubicBezierCurve; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; import fr.radi3nt.spline.splines.CollectionSpline; import fr.radi3nt.spline.splines.Spline; import fr.radi3nt.spline.splines.builder.SplineBuilder; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java index 2e553b1..d6e1ccb 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java @@ -1,5 +1,6 @@ package fr.radi3nt.spline.splines.builder.bezier.dim1; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController; import fr.radi3nt.spline.splines.builder.SplineController; public class CubicBezierSplineController implements SplineController { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java index 116c78c..a559d3b 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java @@ -1,5 +1,7 @@ package fr.radi3nt.spline.splines.builder.bezier.dim1; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController; + public class DirectCubicBezierCurveController implements CubicBezierCurveController { private final float startPoint; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java index e16503f..4e7bfc0 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java @@ -1,5 +1,7 @@ package fr.radi3nt.spline.splines.builder.bezier.dim1; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController; + public class InferredCubicBezierCurveController implements CubicBezierCurveController { private final int index; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java new file mode 100644 index 0000000..34aec89 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java @@ -0,0 +1,36 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim1; + +import fr.radi3nt.spline.curve.curves.bcurve.BCurve; +import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve; +import fr.radi3nt.spline.splines.CollectionSpline; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.SplineBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class BSplineBuilder implements SplineBuilder { + + private final CollectionSpline spline; + private final BSplineController controller; + + public BSplineBuilder(float[] pos) { + controller = new BSplineController(pos); + List curves = new ArrayList<>(); + for (int i = 0; i < pos.length-1; i++) { + BCurve cardinal = new BCurve(controller.createForIndex(i)); + curves.add(cardinal); + } + spline = new CollectionSpline(curves); + } + + @Override + public Spline build() { + return spline; + } + + public BSplineController controller() { + return controller; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java new file mode 100644 index 0000000..ceb9db2 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java @@ -0,0 +1,24 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim1; + +import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; +import fr.radi3nt.spline.splines.builder.PositionnedSplineController; + +public class BSplineController implements PositionnedSplineController { + + private final float[] positions; + + public BSplineController(float[] positions) { + this.positions = positions; + } + + @Override + public void setPosition(int index, float pos) { + positions[index] = pos; + } + + public BCurveController createForIndex(int index) { + return new InferredBCurveController(index, positions); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java new file mode 100644 index 0000000..da47015 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java @@ -0,0 +1,39 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim1; + +import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; + +public class DirectBCurveController implements BCurveController { + + private final float positionA; + private final float positionB; + private final float positionC; + private final float positionD; + + public DirectBCurveController(float positionA, float positionB, float positionC, float positionD) { + this.positionA = positionA; + this.positionB = positionB; + this.positionC = positionC; + this.positionD = positionD; + } + + @Override + public float getPositionA() { + return positionA; + } + + @Override + public float getPositionB() { + return positionB; + } + + @Override + public float getPositionC() { + return positionC; + } + + @Override + public float getPositionD() { + return positionD; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java new file mode 100644 index 0000000..c68ea4e --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java @@ -0,0 +1,41 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim1; + +import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; +import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; + +import java.util.concurrent.atomic.AtomicReference; + +public class InferredBCurveController implements BCurveController { + + private final int index; + private final float[] pos; + + public InferredBCurveController(int index, float[] pos) { + this.index = index; + this.pos = pos; + } + + @Override + public float getPositionA() { + return index == 0 ? (mirror(pos[index], pos[index + 1])) : pos[index - 1]; + } + + @Override + public float getPositionB() { + return pos[index]; + } + + @Override + public float getPositionC() { + return index + 1 >= pos.length ? mirror(getPositionB(), getPositionA()) : pos[index + 1]; + } + + @Override + public float getPositionD() { + return index == pos.length - 2 ? mirror(getPositionC(), getPositionB()) : pos[index + 2]; + } + + private float mirror(float middlePos, float endPos) { + return middlePos*2 - endPos; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java new file mode 100644 index 0000000..b06535a --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java @@ -0,0 +1,37 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim3; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineBuilder; +import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineBuilder; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D; +import fr.radi3nt.spline.splines.dimensions.Spline3D; + +public class BSplineBuilder3D { + + private final BSplineBuilder[] splineBuilders = new BSplineBuilder[3]; + + public BSplineBuilder3D(Vector3f... positions) { + float[] xPos = new float[positions.length]; + float[] yPos = new float[positions.length]; + float[] zPos = new float[positions.length]; + + for (int i = 0; i < positions.length; i++) { + Vector3f position = positions[i]; + xPos[i] = position.getX(); + yPos[i] = position.getY(); + zPos[i] = position.getZ(); + } + + splineBuilders[0] = new BSplineBuilder(xPos); + splineBuilders[1] = new BSplineBuilder(yPos); + splineBuilders[2] = new BSplineBuilder(zPos); + } + + public Spline3D build() { + return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build()); + } + + public BSplineController3D controller() { + return new BSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller()); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java new file mode 100644 index 0000000..6a7f89d --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java @@ -0,0 +1,20 @@ +package fr.radi3nt.spline.splines.builder.bspline.dim3; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineController; +import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineController; + +public class BSplineController3D { + + private final BSplineController[] controllers; + + public BSplineController3D(BSplineController... controllers) { + this.controllers = controllers; + } + + public void setPosition(int index, Vector3f position) { + controllers[0].setPosition(index, position.getX()); + controllers[1].setPosition(index, position.getY()); + controllers[2].setPosition(index, position.getZ()); + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java index 8b84679..4010919 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java @@ -30,4 +30,8 @@ public Vector3f velocity(float t) { private float velocityIndex(int index, float t) { return splines[index].velocity(t); } + + public Spline[] getSplines() { + return splines; + } } From 35c588f61b32c78179e449ea38a82caef27dfdaa Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 13 Sep 2023 23:16:44 +0200 Subject: [PATCH 045/125] Added AABBs (#9) --- .../main/java/fr/radi3nt/maths/aabb/AABB.java | 26 +++++++++++++++++++ .../fr/radi3nt/maths/aabb/AxisMapping.java | 16 ++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java new file mode 100644 index 0000000..fc2cf79 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java @@ -0,0 +1,26 @@ +package fr.radi3nt.maths.aabb; + +public class AABB { + + private final AxisMapping xMapping; + private final AxisMapping yMapping; + private final AxisMapping zMapping; + + public AABB(AxisMapping xMapping, AxisMapping yMapping, AxisMapping zMapping) { + this.xMapping = xMapping; + this.yMapping = yMapping; + this.zMapping = zMapping; + } + + public AxisMapping getxMapping() { + return xMapping; + } + + public AxisMapping getyMapping() { + return yMapping; + } + + public AxisMapping getzMapping() { + return zMapping; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java new file mode 100644 index 0000000..eb92f15 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java @@ -0,0 +1,16 @@ +package fr.radi3nt.maths.aabb; + +public class AxisMapping { + + private final double min; + private final double max; + + public AxisMapping(double min, double max) { + this.min = min; + this.max = max; + } + + public boolean intersect(AxisMapping axisMapping) { + return (min <= axisMapping.max && max >= axisMapping.min); + } +} From 76885f9ca6b9f7094919c7e643b461e019b53f01 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 13 Sep 2023 23:49:36 +0200 Subject: [PATCH 046/125] Math overhaul (#10) * Added fromVec4() in ComponentQuaternion * Implementing missing features in VectorNf classes * Made regular vector implement OperatingVectorNf --- .../quaternions/ComponentsQuaternion.java | 5 ++ .../arbitrary/OperatingVectorNf.java | 18 +++++ .../maths/components/arbitrary/VectorNf.java | 3 +- .../arbitrary/vector/ArrayVectorNf.java | 52 ++++++++++++- .../arbitrary/vector/ExtensibleVectorNf.java | 48 +++++++++++- .../maths/components/vectors/Vector3f.java | 4 +- .../maths/components/vectors/Vector4f.java | 7 +- .../implementations/SimpleVector3f.java | 26 +++++++ .../implementations/SimpleVector3i.java | 32 ++++++-- .../implementations/SimpleVector4f.java | 75 ++++++++++++++++++- 10 files changed, 256 insertions(+), 14 deletions(-) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index e81ff19..b5e3b36 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -4,6 +4,7 @@ import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.Vector4f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; import java.util.Objects; @@ -96,6 +97,10 @@ public static Quaternion zero() { return ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.zero()); } + public static Quaternion fromVec4(Vector4f response) { + return new ComponentsQuaternion(response.getX(), response.getY(), response.getZ(), response.getW()); + } + @Override public Vector3f getAxisOrDefault(Vector3f axis) { float sinFromCos = (float) sqrt(Math.max(0, 1 - w * w)); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java new file mode 100644 index 0000000..71ca7a8 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java @@ -0,0 +1,18 @@ +package fr.radi3nt.maths.components.arbitrary; + +public interface OperatingVectorNf { + + float get(int row); + + OperatingVectorNf duplicate(); + + OperatingVectorNf div(float number); + OperatingVectorNf mul(float number); + + OperatingVectorNf add(OperatingVectorNf other); + OperatingVectorNf sub(OperatingVectorNf other); + + int size(); + + float length(); +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java index c2cb5ee..87f170a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java @@ -2,7 +2,7 @@ import fr.radi3nt.maths.components.vectors.Vector; -public interface VectorNf extends Vector { +public interface VectorNf extends Vector, OperatingVectorNf { float get(int row); @@ -15,5 +15,4 @@ public interface VectorNf extends Vector { void clamp(int row, float min, float max); int size(); - } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java index 2ce89e0..7a7b027 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java @@ -1,6 +1,7 @@ package fr.radi3nt.maths.components.arbitrary.vector; import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; import fr.radi3nt.maths.components.arbitrary.VectorNf; import java.util.Arrays; @@ -13,9 +14,17 @@ public ArrayVectorNf(int size) { vector = new float[size]; } + private ArrayVectorNf(float[] vector) { + this.vector = vector; + } + @Override public float length() { - throw new UnsupportedOperationException("Not implemented"); + float total = 0; + for (float v : vector) { + total+=v*v; + } + return (float) Math.sqrt(total); } public int size() { @@ -26,6 +35,47 @@ public float get(int row) { return vector[row]; } + @Override + public ArrayVectorNf duplicate() { + return new ArrayVectorNf(Arrays.copyOf(vector, vector.length)); + } + + @Override + public ArrayVectorNf div(float number) { + for (int i = 0; i < vector.length; i++) { + vector[i]/=number; + } + return this; + } + + @Override + public ArrayVectorNf mul(float number) { + for (int i = 0; i < vector.length; i++) { + vector[i]*=number; + } + return this; + } + + @Override + public ArrayVectorNf add(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + for (int i = 0; i < vector.length; i++) { + vector[i]+=other.get(i); + } + return this; + } + + @Override + public ArrayVectorNf sub(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + for (int i = 0; i < vector.length; i++) { + vector[i]-=other.get(i); + } + return this; + } + public void set(int row, float v) { vector[row] = v; } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java index 20c7924..840f56d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ExtensibleVectorNf.java @@ -1,6 +1,7 @@ package fr.radi3nt.maths.components.arbitrary.vector; import fr.radi3nt.maths.Maths; +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; import fr.radi3nt.maths.components.arbitrary.VectorNf; import java.util.ArrayList; @@ -14,9 +15,17 @@ public ExtensibleVectorNf() { vector = new ArrayList<>(); } + private ExtensibleVectorNf(List vector) { + this.vector = vector; + } + @Override public float length() { - throw new UnsupportedOperationException("Not implemented"); + float total = 0; + for (float v : vector) { + total+=v*v; + } + return (float) Math.sqrt(total); } public int size() { @@ -27,6 +36,43 @@ public float get(int row) { return vector.get(row); } + @Override + public ExtensibleVectorNf duplicate() { + return new ExtensibleVectorNf(new ArrayList<>(vector)); + } + + @Override + public OperatingVectorNf div(float number) { + vector.replaceAll(aFloat -> aFloat/number); + return this; + } + + @Override + public OperatingVectorNf mul(float number) { + vector.replaceAll(aFloat -> aFloat*number); + return this; + } + + @Override + public OperatingVectorNf add(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + for (int i = 0; i < vector.size(); i++) { + vector.set(i, vector.get(i)+other.get(i)); + } + return this; + } + + @Override + public OperatingVectorNf sub(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + for (int i = 0; i < vector.size(); i++) { + vector.set(i, vector.get(i)-other.get(i)); + } + return this; + } + public void set(int row, float v) { if (row >= vector.size()) vector.add(row, v); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java index 5319fc4..5cf7b0b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java @@ -1,6 +1,8 @@ package fr.radi3nt.maths.components.vectors; -public interface Vector3f extends Vector { +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; + +public interface Vector3f extends Vector, OperatingVectorNf { float getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index 7818cb0..d95dc5b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -1,6 +1,8 @@ package fr.radi3nt.maths.components.vectors; -public interface Vector4f extends Vector { +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; + +public interface Vector4f extends Vector, OperatingVectorNf { float getX(); void setX(float x); @@ -11,7 +13,8 @@ public interface Vector4f extends Vector { float getW(); void setW(float w); - void div(float div); + Vector4f div(float div); + float dot(Vector4f other); void normalize(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index c722050..bb2e568 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -1,6 +1,7 @@ package fr.radi3nt.maths.components.vectors.implementations; import fr.radi3nt.maths.components.Vector3D; +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector3i; import fr.radi3nt.maths.components.vectors.Vector4f; @@ -123,6 +124,31 @@ public Vector3f mul(float mul) { return mul(mul, mul, mul); } + @Override + public OperatingVectorNf add(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + this.x += other.get(0); + this.y += other.get(1); + this.z += other.get(2); + return this; + } + + @Override + public OperatingVectorNf sub(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + this.x -= other.get(0); + this.y -= other.get(1); + this.z -= other.get(2); + return this; + } + + @Override + public int size() { + return 3; + } + @Override public Vector3f div(Vector3f vector2f) { return div(vector2f.getX(), vector2f.getY(), vector2f.getZ()); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java index f45407a..004b531 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java @@ -1,5 +1,6 @@ package fr.radi3nt.maths.components.vectors.implementations; +import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector3i; public class SimpleVector3i implements Vector3i { @@ -21,6 +22,16 @@ public SimpleVector3i(Vector3i vector3f) { public SimpleVector3i() { } + public SimpleVector3i(Vector3f position) { + this.x = (int) Math.floor(position.getX()); + this.y = (int) Math.floor(position.getY()); + this.z = (int) Math.floor(position.getZ()); + } + + public static Vector3i fromRound(Vector3f start) { + return new SimpleVector3i(Math.round(start.getX()), Math.round(start.getY()), Math.round(start.getZ())); + } + @Override public int getX() { return x; @@ -194,11 +205,20 @@ public boolean equals(Object o) { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + x; - result = prime * result + y; - result = prime * result + z; - return result; + int seed = 3; + { + seed = getSeed(this.x, seed); + seed = getSeed(this.y, seed); + seed = getSeed(this.z, seed); + } + return seed; + } + + private static int getSeed(int number, int seed) { + int x = ((number >> 16) ^ number) * 0x45d9f3b; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = (x >> 16) ^ x; + seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 6991002..efae448 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -1,5 +1,7 @@ package fr.radi3nt.maths.components.vectors.implementations; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.Vector4f; @@ -27,6 +29,17 @@ public SimpleVector4f(Vector3f vec, float w) { public SimpleVector4f() { } + public SimpleVector4f(Quaternion quaternion) { + this(quaternion.getX(), quaternion.getY(), quaternion.getZ(), quaternion.getW()); + } + + public static Vector4f fromAbs(Quaternion quaternion) { + Vector4f vector = new SimpleVector4f(quaternion); + if (quaternion.getW()<0) + vector.mul(-1); + return vector; + } + @Override public float getX() { return x; @@ -88,11 +101,71 @@ public void set(float x, float y, float z, int w) { setW(w); } - public void div(float length) { + @Override + public float get(int row) { + if (row==0) + return x; + if (row==1) + return y; + if (row==2) + return z; + if (row==3) + return w; + throw new IllegalArgumentException(); + } + + @Override + public Vector4f duplicate() { + return new SimpleVector4f(x, y, z, w); + } + + public Vector4f div(float length) { this.setX(getX()/length); this.setY(getY()/length); this.setZ(getZ()/length); this.setW(getW()/length); + return this; + } + + @Override + public float dot(Vector4f other) { + return x * other.getX() + y * other.getY() + z * other.getZ() + w * other.getW(); + } + + @Override + public OperatingVectorNf mul(float number) { + this.setX(getX()*number); + this.setY(getY()*number); + this.setZ(getZ()*number); + this.setW(getW()*number); + return this; + } + + @Override + public OperatingVectorNf add(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + this.x += other.get(0); + this.y += other.get(1); + this.z += other.get(2); + this.w += other.get(3); + return this; + } + + @Override + public OperatingVectorNf sub(OperatingVectorNf other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + this.x -= other.get(0); + this.y -= other.get(1); + this.z -= other.get(2); + this.w -= other.get(3); + return this; + } + + @Override + public int size() { + return 4; } @Override From 59889407a484b3604f6243b4270c703b94f5585b Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 14 Sep 2023 09:25:19 +0200 Subject: [PATCH 047/125] Sat overhaul (#11) * Reduced overhead and fixed duplicated vertices deletion system * Added AABB computation for VerticesSATShape * Replaced getClipEdges return type to an array to reduce overhead * Caching axis in TransformedBoxSAT * Added overlap comparison with point --- .../fr/radi3nt/maths/sat/clip/ClipPlane.java | 32 ++++++++--------- .../fr/radi3nt/maths/sat/clip/ClipPlanes.java | 23 +++++++----- .../java/fr/radi3nt/maths/sat/clip/Edge.java | 10 ++++-- .../maths/sat/projection/SatProjection.java | 4 +++ .../fr/radi3nt/maths/sat/shape/BoxSAT.java | 9 ++--- .../maths/sat/shape/TransformedBoxSAT.java | 30 ++++++++-------- .../maths/sat/shape/VerticesSATShape.java | 35 +++++++++++++++++-- .../shape/triangles/ComputingTriangleSAT.java | 8 ++--- .../shape/triangles/StoringTriangleSAT.java | 9 ++--- 9 files changed, 98 insertions(+), 62 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java index 3747388..9d87f15 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java @@ -2,9 +2,6 @@ import fr.radi3nt.maths.components.Vector3D; -import java.util.ArrayList; -import java.util.Collection; - public class ClipPlane { private final Vector3D normal; @@ -15,31 +12,32 @@ public ClipPlane(Vector3D normal, Vector3D vertexOnPlane) { this.vertexOnPlane = vertexOnPlane; } - public Collection clip(Iterable otherEdges) { - Collection clippedEdges = new ArrayList<>(); + public void clip(Edge[] otherEdges) { double projectedClip = normal.dot(vertexOnPlane); - for (Edge edge : otherEdges) { + for (int i = 0; i < otherEdges.length; i++) { + Edge edge = otherEdges[i]; + if (edge==null) + continue; + double projectedVertex1 = normal.dot(edge.getVertex1()); double projectedVertex2 = normal.dot(edge.getVertex2()); - if (projectedVertex1>=projectedClip && projectedVertex2>=projectedClip) - clippedEdges.add(edge); - else { - if (projectedVertex1>=projectedClip) { - double on = (projectedClip-projectedVertex1)/(projectedVertex2-projectedVertex1); + if (!(projectedVertex1 >= projectedClip) || !(projectedVertex2 >= projectedClip)) { + if (projectedVertex1 >= projectedClip) { + double on = (projectedClip - projectedVertex1) / (projectedVertex2 - projectedVertex1); Vector3D computedNewVertex = computeInterpolation(edge.getVertex1(), edge.getVertex2(), on); - clippedEdges.add(new Edge(edge.getVertex1(), computedNewVertex)); + edge.setVertices(edge.getVertex1(), computedNewVertex); - } else if (projectedVertex2>=projectedClip) { - double on = (projectedClip-projectedVertex2)/(projectedVertex1-projectedVertex2); + } else if (projectedVertex2 >= projectedClip) { + double on = (projectedClip - projectedVertex2) / (projectedVertex1 - projectedVertex2); Vector3D computedNewVertex = computeInterpolation(edge.getVertex2(), edge.getVertex1(), on); - clippedEdges.add(new Edge(computedNewVertex, edge.getVertex2())); - + edge.setVertices(computedNewVertex, edge.getVertex2()); + } else { + otherEdges[i] = null; } } } - return clippedEdges; } private Vector3D computeInterpolation(Vector3D vertex1, Vector3D vertex2, double on) { diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java index 76bf023..155b9b0 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java @@ -7,30 +7,35 @@ public class ClipPlanes { + private static final double EPSILON = 1e-2f; private final ClipPlane[] clipPlane; public ClipPlanes(ClipPlane... clipPlane) { this.clipPlane = clipPlane; } - public Collection clipEdges(Collection edges) { - Collection resultList = new ArrayList<>(edges); - + public Edge[] clipEdges(Edge[] edges) { for (ClipPlane plane : clipPlane) { - resultList = plane.clip(resultList); + plane.clip(edges); } - return resultList; + return edges; } - public Collection clip(Collection edges) { - Collection edgeList = clipEdges(edges); - Collection result = new ArrayList<>(); + public Collection clip(Edge[] edges) { + Edge[] edgeList = clipEdges(edges); + Collection result = new ArrayList<>(edgeList.length); for (Edge edge : edgeList) { + if (edge==null) + continue; result.add(edge.getVertex1()); - if (!edge.getVertex1().equals(edge.getVertex2())) + if (notSameVertices(edge)) result.add(edge.getVertex2()); } return result; } + private static boolean notSameVertices(Edge edge) { + return edge.getVertex1().clone().subtract(edge.getVertex2()).lengthSquared() > EPSILON; + } + } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java index f4187e4..ec9505a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java @@ -4,8 +4,8 @@ public class Edge { - private final Vector3D vertex1; - private final Vector3D vertex2; + private Vector3D vertex1; + private Vector3D vertex2; public Edge(Vector3D vertex1, Vector3D vertex2) { this.vertex1 = vertex1; @@ -19,4 +19,10 @@ public Vector3D getVertex1() { public Vector3D getVertex2() { return vertex2; } + + public void setVertices(Vector3D vertex1, Vector3D vertex2) { + this.vertex1 = vertex1; + this.vertex2 = vertex2; + } + } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java index 1c10149..1a61c25 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java @@ -40,6 +40,10 @@ public boolean overlap(SatProjection p2) { return this.min <= p2.max ? this.max >= p2.min : this.min <= p2.min; } + public boolean overlap(double p2) { + return this.min < p2 && this.max > p2; + } + public void sweptOverlap(SatProjection p2, double speed) { double tEnter; double tLeave; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java index b4c4a68..c3aa191 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java @@ -8,9 +8,6 @@ import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; -import java.util.Arrays; -import java.util.Collection; - public class BoxSAT implements VerticesSATShape { private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ @@ -75,8 +72,8 @@ public Vector3D[] getVertices() { } @Override - public Collection getClipEdges() { - return Arrays.asList( + public Edge[] getClipEdges() { + return new Edge[] { new Edge(vertices[0], vertices[6]), new Edge(vertices[0], vertices[4]), new Edge(vertices[0], vertices[2]), @@ -93,6 +90,6 @@ public Collection getClipEdges() { new Edge(vertices[5], vertices[6]), new Edge(vertices[3], vertices[2]) - ); + }; } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java index eca6cba..63f4922 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java @@ -11,9 +11,6 @@ import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; -import java.util.Arrays; -import java.util.Collection; - public class TransformedBoxSAT implements VerticesSATShape { private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ @@ -26,6 +23,8 @@ public class TransformedBoxSAT implements VerticesSATShape { }; private final Vector3D[] vertices; + private Vector3D[] axis; + private SatAxis[] satAxes; private Matrix4x4 transform; public TransformedBoxSAT(Vector3D min, Vector3D max, Matrix4x4 transform) { @@ -46,6 +45,8 @@ public TransformedBoxSAT(Vector3D min, Vector3D max, Matrix4x4 transform) { vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); } + computeBoxAxes(); + computeAxis(); } public void set(Vector3D min, Vector3D max, Matrix4x4 transform) { @@ -64,20 +65,21 @@ public void set(Vector3D min, Vector3D max, Matrix4x4 transform) { vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); } this.transform = transform; + computeBoxAxes(); + computeAxis(); } @Override public SatAxis[] getAxes() { - return computeAxis(); + return satAxes; } - private SatAxis[] computeAxis() { - SatAxis[] axes = new SatAxis[3]; - Vector3D[] axis = computeBoxAxes(); - for (int i = 0; i < axes.length; i++) { - axes[i] = new SatAxis(axis[i]); + private void computeAxis() { + satAxes = new SatAxis[3]; + Vector3D[] axis = this.axis; + for (int i = 0; i < satAxes.length; i++) { + satAxes[i] = new SatAxis(axis[i]); } - return axes; } @Override @@ -107,7 +109,7 @@ private SatEdge[] computeEdges() { } private Vector3D[] computeBoxAxes() { - Vector3D[] axis = new Vector3D[3]; + axis = new Vector3D[3]; axis[0] = vertices[6].clone().subtract(vertices[0]).normalize(); axis[1] = vertices[4].clone().subtract(vertices[0]).normalize(); axis[2] = vertices[2].clone().subtract(vertices[0]).normalize(); @@ -120,8 +122,8 @@ public Vector3D[] getVertices() { } @Override - public Collection getClipEdges() { - return Arrays.asList( + public Edge[] getClipEdges() { + return new Edge[] { new Edge(vertices[0], vertices[6]), new Edge(vertices[0], vertices[4]), new Edge(vertices[0], vertices[2]), @@ -138,6 +140,6 @@ public Collection getClipEdges() { new Edge(vertices[5], vertices[6]), new Edge(vertices[3], vertices[2]) - ); + }; } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java index ce77d07..dbf9e1a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java @@ -1,5 +1,7 @@ package fr.radi3nt.maths.sat.shape; +import fr.radi3nt.maths.aabb.AABB; +import fr.radi3nt.maths.aabb.AxisMapping; import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.sat.clip.ClipPlanes; import fr.radi3nt.maths.sat.clip.Edge; @@ -7,8 +9,6 @@ import fr.radi3nt.maths.sat.projection.SatProjection; import fr.radi3nt.maths.sat.projection.SatProjectionProvider; -import java.util.Collection; - public interface VerticesSATShape extends SATShape { @Override @@ -29,5 +29,34 @@ default SatProjection project(SatProjectionProvider provider, SatAxis axis) { Vector3D[] getVertices(); ClipPlanes getClipPlanes(); - Collection getClipEdges(); + Edge[] getClipEdges(); + + default AABB toAABB() { + final AABB aabb; + float maxX = -Float.MAX_VALUE; + float minX = Float.MAX_VALUE; + + float maxY = -Float.MAX_VALUE; + float minY = Float.MAX_VALUE; + + float maxZ = -Float.MAX_VALUE; + float minZ = Float.MAX_VALUE; + + for (Vector3D vertex : getVertices()) { + maxX = (float) Math.max(maxX, vertex.getX()); + minX = (float) Math.min(minX, vertex.getX()); + + maxY = (float) Math.max(maxY, vertex.getY()); + minY = (float) Math.min(minY, vertex.getY()); + + maxZ = (float) Math.max(maxZ, vertex.getZ()); + minZ = (float) Math.min(minZ, vertex.getZ()); + } + + aabb = new AABB( + new AxisMapping(minX, maxX), + new AxisMapping(minY, maxY), + new AxisMapping(minZ, maxZ)); + return aabb; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java index 011ae99..f004318 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java @@ -9,8 +9,6 @@ import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; -import java.util.Arrays; -import java.util.Collection; import java.util.function.Consumer; public class ComputingTriangleSAT implements TriangleSAT { @@ -82,13 +80,13 @@ public SatEdge[] getEdges() { } @Override - public Collection getClipEdges() { + public Edge[] getClipEdges() { Vector3D[] vertices = getVertices(); - return Arrays.asList( + return new Edge[] { new Edge(vertices[0], vertices[1]), new Edge(vertices[1], vertices[2]), new Edge(vertices[2], vertices[0]) - ); + }; } @Override diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java index 2272cb8..01627b1 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java @@ -8,9 +8,6 @@ import fr.radi3nt.maths.sat.components.SatAxis; import fr.radi3nt.maths.sat.components.SatEdge; -import java.util.Arrays; -import java.util.Collection; - public class StoringTriangleSAT implements TriangleSAT { private final Vector3D[] vertices = new Vector3D[3]; @@ -52,12 +49,12 @@ public SatEdge[] getEdges() { } @Override - public Collection getClipEdges() { - return Arrays.asList( + public Edge[] getClipEdges() { + return new Edge[] { new Edge(vertices[0], vertices[1]), new Edge(vertices[1], vertices[2]), new Edge(vertices[2], vertices[0]) - ); + }; } @Override From 951b95c8058f63f20426999d9bddfe77ceba53d2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 14 Sep 2023 09:28:01 +0200 Subject: [PATCH 048/125] Added Pathfinding module in pom.xml --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index d6ce306..7afa99e 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ SplineHelper AnimationHelper InverseKinematics + Pathfinding From 3667a7ebef5d9c66bc9254731385775acd8444c1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 14 Sep 2023 09:33:10 +0200 Subject: [PATCH 049/125] Ik enhancement (#12) * Added check to avoid unnecessary solving * Added BallSocketJointConstraint to limit angle on BallSocket joints --- .../radi3nt/ik/solvers/IkIterativeSolver.java | 13 +++++- .../constraint/BallSocketJointConstraint.java | 41 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java index 1798b31..60187cc 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java @@ -5,6 +5,8 @@ public abstract class IkIterativeSolver implements IkSolver { private final int maxIterations; protected final float allowedMarginOfError; + private boolean solved; + public IkIterativeSolver(int maxIterations, float allowedMarginOfError) { this.maxIterations = maxIterations; this.allowedMarginOfError = allowedMarginOfError; @@ -13,11 +15,20 @@ public IkIterativeSolver(int maxIterations, float allowedMarginOfError) { @Override public void solve() { + if (isInAllowedMarginOfError()) { + solved = false; + return; + } for (int i = 0; i < maxIterations; i++) { + iteration(); if (isInAllowedMarginOfError()) break; - iteration(); } + solved = true; + } + + public boolean iterationWasSolved() { + return solved; } protected abstract boolean isInAllowedMarginOfError(); diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java new file mode 100644 index 0000000..9bf4fa2 --- /dev/null +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java @@ -0,0 +1,41 @@ +package fr.radi3nt.ik.solvers.ccdik.constraint; + +import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class BallSocketJointConstraint implements JointConstraint { + + private final Vector3f upAxis; + private final Vector3f constrainingAxis; + private final Angle limit; + + public BallSocketJointConstraint(Vector3f upAxis, Vector3f constrainingAxis, Angle limit) { + this.upAxis = upAxis; + this.constrainingAxis = constrainingAxis; + this.limit = limit; + } + + @Override + public void constrain(CCDJoint ccdJoint) { + Quaternion toUpQuaternion = ComponentsQuaternion.fromTwoVectors(constrainingAxis, upAxis); + Quaternion toAxisFromUpQuaternion = toUpQuaternion.duplicate(); + toAxisFromUpQuaternion.inverse(); + + Quaternion rot = ccdJoint.rotation.duplicate(); + rot.multiply(toUpQuaternion); + Angle angle = rot.getAngle(); + double rad = Math.min(angle.getRadiant(), limit.getRadiant()); + Angle constrainedAngle = JavaMathAngle.fromRadiant(rad); + + Quaternion newRotation = ComponentsQuaternion.fromAxisAndAngle(rot.getAxisOrDefault(new SimpleVector3f(0, 1, 0)), constrainedAngle); + newRotation.multiply(toAxisFromUpQuaternion); + + ccdJoint.rotation = newRotation; + + } +} From 9cf27b22daa82d63166973bc4adabc95b0da87aa Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 15 Sep 2023 13:38:17 +0200 Subject: [PATCH 050/125] Added lengthSquared() in Vector2f --- .../java/fr/radi3nt/maths/components/vectors/Vector2f.java | 1 + .../components/vectors/implementations/SimpleVector2f.java | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java index f7e61da..c850418 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java @@ -26,4 +26,5 @@ public interface Vector2f extends Vector { float dot(Vector2f vector2f); Vector2f normalize(); + float lengthSquared(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java index 21acfe8..47eafbf 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java @@ -110,9 +110,14 @@ public Vector2f normalize() { return div(length()); } + @Override + public float lengthSquared() { + return x * x + y * y; + } + @Override public float length() { - return (float) Math.sqrt(x * x + y * y); + return (float) Math.sqrt(lengthSquared()); } @Override From bb371b989273147c6e738d8b1d7db8e6789d0581 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 15 Sep 2023 13:51:41 +0200 Subject: [PATCH 051/125] Removed redundant duplicate() from CCDIKSolver --- .../main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java index 7b95b67..8c8bc2d 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java @@ -47,8 +47,8 @@ protected void iteration() { } private Quaternion getRotationBetweenEndEffectorAndGoalUsingWorldSpace(int joinIndex) { - Vector3f ei = lastEndEffectorWorldPosition==null ? endEffector.getWorldPosition().duplicate() : lastEndEffectorWorldPosition.duplicate(); - Vector3f et = goal.duplicate(); + Vector3f ei = lastEndEffectorWorldPosition==null ? endEffector.getWorldPosition() : lastEndEffectorWorldPosition; + Vector3f et = goal; lastEndEffectorWorldPosition = null; Vector3f bonePos = getBonePos(joinIndex); From b379e9916161bedbb1b798d22b01b91720b42e05 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 26 Sep 2023 23:35:46 +0200 Subject: [PATCH 052/125] Separated limits and constraints (limits only need quaternions) (#13) --- .../java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java | 2 +- .../solvers/ccdik/limit/AngleClampJointLimit.java | 11 +++++------ .../BallSocketJointLimit.java} | 14 ++++++-------- .../solvers/ccdik/limit/CompositionJointLimit.java | 4 ++-- .../radi3nt/ik/solvers/ccdik/limit/JointLimit.java | 4 ++-- 5 files changed, 16 insertions(+), 19 deletions(-) rename InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/{constraint/BallSocketJointConstraint.java => limit/BallSocketJointLimit.java} (78%) diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java index 878fcda..a4805ff 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java @@ -24,7 +24,7 @@ public void constrain() { } public void limit() { - jointLimit.limit(this); + jointLimit.limit(this.rotation); } public float getLength() { diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java index 2e7e23f..04cbe19 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/AngleClampJointLimit.java @@ -1,6 +1,5 @@ package fr.radi3nt.ik.solvers.ccdik.limit; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; import fr.radi3nt.ik.solvers.ccdik.constraint.HingeJointConstraint; import fr.radi3nt.maths.Maths; import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; @@ -32,7 +31,7 @@ public AngleClampJointLimit(Angle minAngle, Angle maxAngle, Vector3f axis) { } @Override - public void limit(CCDJoint ccdJoint) { + public void limit(Quaternion rotation) { double minAngleRadiant = minAngle.getRadiant(); double maxAngleRadiant = maxAngle.getRadiant(); @@ -40,14 +39,14 @@ public void limit(CCDJoint ccdJoint) { double max = Math.max(maxAngleRadiant, minAngleRadiant); double min = Math.min(maxAngleRadiant, minAngleRadiant); - Quaternion q1 = ccdJoint.rotation.duplicate(); + Quaternion q1 = rotation.duplicate(); Quaternion q2 = zeroAngle.duplicate(); q1.inverse(); q1.multiply(q2); - double angle = (2 * Math.atan2(q1.getVector().length(), q1.getW())); + double angle = (2 * Math.atan2(q1.getVector().length()+0f, q1.getW())); - Vector3f axis = ccdJoint.rotation.getAxisOrDefault(defaultAxis.duplicate()); + Vector3f axis = rotation.getAxisOrDefault(defaultAxis.duplicate()); if (axis.dot(defaultAxis)<0) { angle=-angle; axis.negate(); @@ -56,6 +55,6 @@ public void limit(CCDJoint ccdJoint) { angle = Maths.clamp(angle, min, max); Quaternion result = ComponentsQuaternion.fromAxisAndAngle(axis, JavaMathAngle.fromRadiant(angle)); - ccdJoint.rotation.copy(result); + rotation.copy(result); } } diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/BallSocketJointLimit.java similarity index 78% rename from InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java rename to InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/BallSocketJointLimit.java index 9bf4fa2..a0af327 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/BallSocketJointConstraint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/BallSocketJointLimit.java @@ -1,6 +1,5 @@ -package fr.radi3nt.ik.solvers.ccdik.constraint; +package fr.radi3nt.ik.solvers.ccdik.limit; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; @@ -8,25 +7,25 @@ import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; -public class BallSocketJointConstraint implements JointConstraint { +public class BallSocketJointLimit implements JointLimit { private final Vector3f upAxis; private final Vector3f constrainingAxis; private final Angle limit; - public BallSocketJointConstraint(Vector3f upAxis, Vector3f constrainingAxis, Angle limit) { + public BallSocketJointLimit(Vector3f upAxis, Vector3f constrainingAxis, Angle limit) { this.upAxis = upAxis; this.constrainingAxis = constrainingAxis; this.limit = limit; } @Override - public void constrain(CCDJoint ccdJoint) { + public void limit(Quaternion rotation) { Quaternion toUpQuaternion = ComponentsQuaternion.fromTwoVectors(constrainingAxis, upAxis); Quaternion toAxisFromUpQuaternion = toUpQuaternion.duplicate(); toAxisFromUpQuaternion.inverse(); - Quaternion rot = ccdJoint.rotation.duplicate(); + Quaternion rot = rotation.duplicate(); rot.multiply(toUpQuaternion); Angle angle = rot.getAngle(); double rad = Math.min(angle.getRadiant(), limit.getRadiant()); @@ -35,7 +34,6 @@ public void constrain(CCDJoint ccdJoint) { Quaternion newRotation = ComponentsQuaternion.fromAxisAndAngle(rot.getAxisOrDefault(new SimpleVector3f(0, 1, 0)), constrainedAngle); newRotation.multiply(toAxisFromUpQuaternion); - ccdJoint.rotation = newRotation; - + rotation.copy(newRotation); } } diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java index a9945a2..d72bd8d 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/CompositionJointLimit.java @@ -1,6 +1,6 @@ package fr.radi3nt.ik.solvers.ccdik.limit; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; public class CompositionJointLimit implements JointLimit { @@ -12,7 +12,7 @@ public CompositionJointLimit(JointLimit... jointLimits) { @Override - public void limit(CCDJoint ccdJoint) { + public void limit(Quaternion ccdJoint) { for (JointLimit jointLimit : jointLimits) { jointLimit.limit(ccdJoint); } diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java index 993575e..6e9eb11 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/limit/JointLimit.java @@ -1,9 +1,9 @@ package fr.radi3nt.ik.solvers.ccdik.limit; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; public interface JointLimit { - void limit(CCDJoint ccdJoint); + void limit(Quaternion ccdJoint); } From 65905f0e8a17646434760ea564a70c1d53b3e76a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Tue, 26 Sep 2023 23:36:59 +0200 Subject: [PATCH 053/125] Added normalizeSafely() to Vector3f --- .../java/fr/radi3nt/maths/components/vectors/Vector3f.java | 2 ++ .../components/vectors/implementations/SimpleVector3f.java | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java index 5cf7b0b..6996dee 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java @@ -57,4 +57,6 @@ public interface Vector3f extends Vector, OperatingVectorNf { void add(int row, float value); float get(int row); + + Vector3f normalizeSafely(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index bb2e568..17b5cab 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -239,6 +239,13 @@ public float get(int row) { throw new IllegalArgumentException(); } + @Override + public Vector3f normalizeSafely() { + if (this.lengthSquared()!=0) + this.normalize(); + return this; + } + @Override public float length() { return (float) Math.sqrt(x * x + y * y + z * z); From 58eade0f2ffe6fa67b3f17dcba26e9ac4d3b99f9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Mon, 16 Oct 2023 10:32:38 +0200 Subject: [PATCH 054/125] Returning an empty path is start==end (#14) --- .../main/java/fr/radi3nt/pathfinding/AStarPathfinder.java | 2 ++ .../main/java/fr/radi3nt/pathfinding/path/IndexedPath.java | 5 +++++ .../src/main/java/fr/radi3nt/pathfinding/path/Path.java | 1 + 3 files changed, 8 insertions(+) diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java index c612499..7781142 100644 --- a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java @@ -38,6 +38,8 @@ public Path find(Vector3f start, Vector3f end) { pathfinderPointSupplier.prepare(); FindNode startPoint = pathfinderPointSupplier.pointFromPosition(start); + if (isEnd(end, startPoint)) + return new IndexedPath(new PathNode[0]); FindNode lastPoint = startPoint; float lastDistanceToEnd = heuristicEvaluator.distanceBetween(startPoint.getFloatPosition(), end); diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/IndexedPath.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/IndexedPath.java index 0fcd059..da2cdad 100644 --- a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/IndexedPath.java +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/IndexedPath.java @@ -36,6 +36,11 @@ public PathNode getGoal() { return positions[positions.length-1]; } + @Override + public boolean isEmpty() { + return positions.length==0; + } + public PathNode[] getPositions() { return positions; } diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/Path.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/Path.java index 066d5b0..9f8d9e4 100644 --- a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/Path.java +++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/Path.java @@ -12,4 +12,5 @@ public interface Path { PathNode getGoal(); + boolean isEmpty(); } From 5c7ba664b37da446fffafafe0db5c4edd4e07fe2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 9 Nov 2023 14:14:24 +0100 Subject: [PATCH 055/125] Added dynamics package These classes compute smooth motion according to provided parameters --- .../DirectionRotationSmoothDynamics.java | 20 +++++ .../maths/dynamics/DynamicsConstants.java | 60 ++++++++++++++ .../maths/dynamics/FloatSmoothDynamics.java | 64 +++++++++++++++ .../VectorRotationSmoothDynamics.java | 32 ++++++++ .../maths/dynamics/VectorSmoothDynamics.java | 78 +++++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java new file mode 100644 index 0000000..ae9e9f5 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java @@ -0,0 +1,20 @@ +package fr.radi3nt.maths.dynamics; + +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class DirectionRotationSmoothDynamics extends VectorSmoothDynamics { + + public DirectionRotationSmoothDynamics(DynamicsConstants constants, Vector3f start) { + super(constants, start); + } + + @Override + public void update(float step) { + if (inputPrevious.dot(inputCurrent)<0) { + inputCurrent.mul(-1); + } + + super.update(step); + response.normalizeSafely(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java new file mode 100644 index 0000000..d72df5a --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java @@ -0,0 +1,60 @@ +package fr.radi3nt.maths.dynamics; + +import static java.lang.Math.PI; +import static java.lang.Math.abs; + +public class DynamicsConstants { + + private final float k1; + private final float k2; + private final float k3; + + private final float w; + private final float z; + private final float d; + + public DynamicsConstants(float k1, float k2, float k3, float w, float z, float d) { + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + this.w = w; + this.z = z; + this.d = d; + } + + public static DynamicsConstants from(float f, float z, float r) { + float w = (float) (2f*PI*f); + + float k1 = (float) (z/(PI * f)); + float k2 = 1f/ (w*w); + float k3 = r * z / w; + + float d = (float) (w * Math.sqrt(abs(z*z-1))); + + return new DynamicsConstants(k1, k2, k3, w, z, d); + } + + public float getW() { + return w; + } + + public float getZ() { + return z; + } + + public float getD() { + return d; + } + + public float getK1() { + return k1; + } + + public float getK2() { + return k2; + } + + public float getK3() { + return k3; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java new file mode 100644 index 0000000..8edad7f --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java @@ -0,0 +1,64 @@ +package fr.radi3nt.maths.dynamics; + +public class FloatSmoothDynamics { + + private DynamicsConstants constants; + protected float inputPrevious, inputCurrent; + protected float response, responseDerivative; + + public FloatSmoothDynamics(DynamicsConstants constants, float start) { + this.constants = constants; + this.response = start; + this.inputCurrent = start; + this.inputPrevious = start; + responseDerivative = 0; + } + + public void update(float step) { + if (step==0) + return; + float inputDerivative = (inputCurrent - inputPrevious)/step; + inputPrevious = inputCurrent; + float k1Stable, k2Stable; + if (systemIsAtHighSpeed(constants, step)) { + k1Stable = constants.getK1(); + k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); + } else { + k1Stable = constants.getK1(); + k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); + } + + response+=responseDerivative*step; + float multipliedByTTerm = (inputDerivative*constants.getK3()+inputCurrent-response)*step; + responseDerivative = (multipliedByTTerm+responseDerivative*k2Stable)/(k2Stable+step*k1Stable); + } + + public float getResponseDerivative() { + return responseDerivative; + } + + public void setInputCurrent(float inputCurrent) { + this.inputCurrent = inputCurrent; + } + + public float getResponse() { + return response; + } + + private boolean systemIsAtHighSpeed(DynamicsConstants constants, float step) { + return constants.getW()*step >= constants.getZ(); + } + + public void setConstants(DynamicsConstants constants) { + this.constants = constants; + } + + public void setCurrent(float currentLocalPos) { + response = currentLocalPos; + responseDerivative = 0; + } + + public void setCurrentBypass(float currentLocalPos) { + response = currentLocalPos; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java new file mode 100644 index 0000000..ddb03b2 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java @@ -0,0 +1,32 @@ +package fr.radi3nt.maths.dynamics; + +import fr.radi3nt.maths.components.vectors.Vector4f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; + +public class VectorRotationSmoothDynamics extends VectorSmoothDynamics { + + private final boolean loop; + + public VectorRotationSmoothDynamics(DynamicsConstants constants, Vector4f start) { + this(constants, start, true); + } + + public VectorRotationSmoothDynamics(DynamicsConstants constants, Vector4f start, boolean loop) { + super(constants, start); + this.loop = loop; + } + + @Override + public void update(float step) { + if (loop && inputPrevious.dot(inputCurrent)<0) { + inputCurrent.mul(-1); + } + + super.update(step); + response.normalize(); + } + + public void setCurrentBypass(SimpleVector4f current) { + this.response = current; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java new file mode 100644 index 0000000..f8ab14c --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java @@ -0,0 +1,78 @@ +package fr.radi3nt.maths.dynamics; + +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; + +public class VectorSmoothDynamics { + + private DynamicsConstants constants; + protected T inputPrevious, inputCurrent; + protected T response, responseDerivative; + private float speed = 0; + + public VectorSmoothDynamics(DynamicsConstants constants, T start) { + this.constants = constants; + this.response = (T) start.duplicate(); + this.inputCurrent = (T) start.duplicate(); + this.inputPrevious = (T) start.duplicate(); + responseDerivative = (T) start.duplicate().mul(0); + } + + public void update(float step) { + if (step==0) + return; + OperatingVectorNf inputDerivative = inputCurrent.duplicate().sub(inputPrevious).div(step); + inputPrevious = (T) inputCurrent.duplicate(); + float k1Stable, k2Stable; + if (systemIsAtHighSpeed(constants, step)) { + k1Stable = constants.getK1(); + k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); + } else { + k1Stable = constants.getK1(); + k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); + } + + response.add(responseDerivative.duplicate().mul(step)); + //responseDerivative.add(inputDerivative.mul(constants.getK3()).add(inputCurrent).sub(response).sub(responseDerivative.duplicate().mul(k1Stable)).div(k2Stable).mul(step)); + OperatingVectorNf multipliedByTTerm = inputDerivative.mul(constants.getK3()).add(inputCurrent).sub(response).mul(step); + responseDerivative = (T) multipliedByTTerm.add(responseDerivative.duplicate().mul(k2Stable)).div(k2Stable+step*k1Stable); + speed = responseDerivative.length(); + } + + public T getResponseDerivative() { + return responseDerivative; + } + + public float getSpeed() { + return speed; + } + + public void setInputCurrent(T inputCurrent) { + this.inputCurrent = inputCurrent; + } + + public T getResponse() { + return response; + } + + private boolean systemIsAtHighSpeed(DynamicsConstants constants, float step) { + return constants.getW()*step >= constants.getZ(); + } + + public void setConstants(DynamicsConstants constants) { + this.constants = constants; + } + + public void setCurrent(T currentLocalPos) { + response = currentLocalPos; + responseDerivative = (T) currentLocalPos.duplicate().mul(0); + speed = 0; + } + + public T getInputPrevious() { + return inputPrevious; + } + + public void setInputPrevious(T inputPrevious) { + this.inputPrevious = inputPrevious; + } +} From 7a05a15a7692aa8d713ea3a005e438d6c9bb74d1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 9 Nov 2023 14:20:56 +0100 Subject: [PATCH 056/125] Improved matrix multiplication using 2-dimensional arrays --- .../radi3nt/maths/components/MatrixNxNd.java | 2 - .../arbitrary/matrix/ArrayMatrixNxNd.java | 49 ++++++++---- .../matrix/sparse/SparseMatrixd.java | 76 +++++++++++++++++-- 3 files changed, 104 insertions(+), 23 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java index 06dda55..5ed1fcf 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/MatrixNxNd.java @@ -16,8 +16,6 @@ public interface MatrixNxNd { BitSet nonZero(); - double[] getM(); - MatrixNxNd multiply(MatrixNxNd matrixNxN); MatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java index 48bf1d5..99fd154 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNd.java @@ -11,17 +11,17 @@ public class ArrayMatrixNxNd implements MatrixNxNd { private final int width; private final int height; - private final double[] m; + private final double[][] m; private final BitSet zeroSet; public ArrayMatrixNxNd(int width, int height) { this.width = width; this.height = height; - m = new double[width * height]; + m = new double[width][height]; zeroSet = new BitSet(this.width * this.height); } - protected ArrayMatrixNxNd(int width, int height, double[] m) { + protected ArrayMatrixNxNd(int width, int height, double[][] m) { this.width = width; this.height = height; this.m = m; @@ -66,7 +66,7 @@ public ArrayMatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN) { ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { - float total = 0; + double total = 0; for (int i = 0; i < this.width; i++) { if (nonZero.get(i + x * matrixNxN.getWidth())) total += this.get(i, y) * matrixNxN.get(i, x); @@ -92,7 +92,7 @@ public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { - float total = 0; + double total = 0; for (int i = 0; i < matrixNxN.getWidth(); i++) { if (nonZero.get(i + x * this.getWidth())) total += matrixNxN.get(i, y) * this.get(i, x); @@ -105,19 +105,30 @@ public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { return result; } + public double[] getWidthArray(int x) { + return m[x]; + } + @Override public double get(int x, int y) { - return m[x + y * width]; + double[] array = m[x]; + return array==null ? 0 : array[y]; } @Override public void set(int x, int y, double value) { - m[x + y * width] = value; - zeroSet.set(x + y * width, value != 0); + double[] array = m[x]; + if (array==null) + m[x] = array = new double[this.width]; + array[y] = value; + zeroSet.set(x + y * this.width, value != 0); } public void add(int x, int y, double total) { - m[x + y * width] += total; + double[] array = m[x]; + if (array==null) + m[x] = array = new double[this.width]; + array[y] += total; } public void markAllNonZero() { @@ -139,10 +150,10 @@ public BitSet nonZero() { @Override public ArrayMatrixNxNd duplicate() { - return new ArrayMatrixNxNd(width, height, Arrays.copyOf(m, m.length)); + return new ArrayMatrixNxNd(width, height, deepCopy(m)); } - public double[] getM() { + public double[][] getM() { return m; } @@ -169,14 +180,14 @@ public boolean equals(Object o) { if (width != that.width) return false; if (height != that.height) return false; - return Arrays.equals(m, that.m); + return Arrays.deepEquals(m, that.m); } @Override public int hashCode() { int result = width; result = 31 * result + height; - result = 31 * result + Arrays.hashCode(m); + result = 31 * result + Arrays.deepHashCode(m); return result; } @@ -198,4 +209,16 @@ public String toString() { return stringBuilder.toString(); } + + public static double[][] deepCopy(double[][] original) { + if (original == null) { + return null; + } + + final double[][] result = new double[original.length][]; + for (int i = 0; i < original.length; i++) { + result[i] = Arrays.copyOf(original[i], original[i].length); + } + return result; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java index 3b5c53b..ec76c12 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixd.java @@ -76,11 +76,6 @@ public BitSet nonZero() { return bitSet; } - @Override - public double[] getM() { - throw new UnsupportedOperationException(); - } - public VectorNd transform(VectorNd vector) { VectorNd result = new ArrayVectorNd(height); for (SparseBlockd sparseBlock : sparseBlocks) { @@ -116,7 +111,41 @@ public MatrixNxNd duplicate() { public MatrixNxNd multiply(MatrixNxNd matrixNxN) { if (this.width != matrixNxN.getHeight()) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getHeight() + "!=" + this.width); + if (matrixNxN instanceof ArrayMatrixNxNd) { + return multiplyIntern((ArrayMatrixNxNd) matrixNxN); + } + return multiplyGeneral(matrixNxN); + } + + private MatrixNxNd multiplyIntern(ArrayMatrixNxNd matrixNxN) { + int resultWidth = matrixNxN.getWidth(); + int resultHeight = this.height; + + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int x = 0; x < resultWidth; x++) { + double[] array = matrixNxN.getWidthArray(x); + if (array==null) + continue; + for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { + double temp = array[i]; + if (temp==0) + continue; + for (int y = sparseBlock.getStartY(); y < sparseBlock.getStartY() + sparseBlock.getHeight(); y++) { + double adding = temp*sparseBlock.get(i, y); + if (adding==0) + continue; + result.add(x, y, adding); + } + } + } + } + result.markAllNonZero(); + return result; + } + + private ArrayMatrixNxNd multiplyGeneral(MatrixNxNd matrixNxN) { int resultWidth = matrixNxN.getWidth(); int resultHeight = this.height; @@ -171,15 +200,46 @@ public ArrayMatrixNxNd multiplyWithTransposed(MatrixNxNd matrixNxN) { public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { if (matrixNxN.getWidth() != this.width) throw new UnsupportedOperationException("Unable to multiply matrices: " + matrixNxN.getWidth() + "!=" + this.width); + if (matrixNxN instanceof ArrayMatrixNxNd) + return multiplyTransposedOtherIntern((ArrayMatrixNxNd) matrixNxN); + return multiplyTransposedMatrixOtherGeneral(matrixNxN); + } + private MatrixNxNd multiplyTransposedOtherIntern(ArrayMatrixNxNd matrixNxN) { int resultWidth = this.height; int resultHeight = matrixNxN.getHeight(); - BitSet bitSet = matrixNxN.nonZero(); + ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + BitSet resultNonZero = result.nonZero(); + for (SparseBlockd sparseBlock : sparseBlocks) { + for (int x = sparseBlock.getStartY(); x < sparseBlock.getStartY() + sparseBlock.getHeight(); x++) { + for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { + double cache = sparseBlock.get(i, x); + if (cache==0) + continue; + double[] values = matrixNxN.getWidthArray(i); + if (values==null) + continue; + for (int y = 0; y < resultHeight; y++) { + double added = values[y] * cache; + if (added==0) + continue; + result.add(x, y, added); + resultNonZero.set(x + y * resultWidth, true); + } + } + } + } + + return result; + } - int otherWidth = matrixNxN.getWidth(); + private ArrayMatrixNxNd multiplyTransposedMatrixOtherGeneral(MatrixNxNd matrixNxN) { + int resultWidth = this.height; + int resultHeight = matrixNxN.getHeight(); ArrayMatrixNxNd result = new ArrayMatrixNxNd(resultWidth, resultHeight); + BitSet resultNonZero = result.nonZero(); for (SparseBlockd sparseBlock : sparseBlocks) { for (int x = sparseBlock.getStartY(); x < sparseBlock.getStartY() + sparseBlock.getHeight(); x++) { for (int i = sparseBlock.getStartX(); i < sparseBlock.getStartX() + sparseBlock.getWidth(); i++) { @@ -191,11 +251,11 @@ public MatrixNxNd multiplyTransposedOther(MatrixNxNd matrixNxN) { if (added==0) continue; result.add(x, y, added); + resultNonZero.set(x + y * resultWidth, true); } } } } - result.markAllNonZero(); return result; } From a96eca04f3684bdf82a6a799d286ea896df09198 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 11 Nov 2023 00:05:00 +0100 Subject: [PATCH 057/125] Added ComponentsQuaternion constructor with Vector4f --- .../components/advanced/quaternions/ComponentsQuaternion.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index b5e3b36..8b2a361 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -31,6 +31,10 @@ public ComponentsQuaternion(Vector3f vector, float w) { this(vector.getX(), vector.getY(), vector.getZ(), w); } + public ComponentsQuaternion(Vector4f vector) { + this(vector.getX(), vector.getY(), vector.getZ(), vector.getW()); + } + @Deprecated public static Quaternion fromVectorToAnother(Vector3f v1, Vector3f v2) { Vector3f vector = v1.duplicate().cross(v2); From a642c8761cbed2ce24ff3232719f35def151c2c1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 2 May 2024 13:52:26 +0200 Subject: [PATCH 058/125] Spline module cleanup (optimised imports) (#15) --- .../radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java | 1 - .../spline/splines/builder/bspline/dim1/BSplineBuilder.java | 2 -- .../spline/splines/builder/bspline/dim1/BSplineController.java | 1 - .../splines/builder/bspline/dim1/DirectBCurveController.java | 1 - .../splines/builder/bspline/dim1/InferredBCurveController.java | 3 --- .../spline/splines/builder/bspline/dim3/BSplineBuilder3D.java | 1 - .../splines/builder/bspline/dim3/BSplineController3D.java | 1 - 7 files changed, 10 deletions(-) diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java index a1f3fe8..97a94b4 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java @@ -1,7 +1,6 @@ package fr.radi3nt.spline.curve.curves.bezier; import fr.radi3nt.spline.curve.CharacteristicCurve; -import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController; public class CubicBezierCurve extends CharacteristicCurve { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java index 34aec89..2acc9d6 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java @@ -1,8 +1,6 @@ package fr.radi3nt.spline.splines.builder.bspline.dim1; import fr.radi3nt.spline.curve.curves.bcurve.BCurve; -import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; -import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve; import fr.radi3nt.spline.splines.CollectionSpline; import fr.radi3nt.spline.splines.Spline; import fr.radi3nt.spline.splines.builder.SplineBuilder; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java index ceb9db2..52e29eb 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java @@ -1,7 +1,6 @@ package fr.radi3nt.spline.splines.builder.bspline.dim1; import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; -import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; import fr.radi3nt.spline.splines.builder.PositionnedSplineController; public class BSplineController implements PositionnedSplineController { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java index da47015..0e1ef0e 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java @@ -1,7 +1,6 @@ package fr.radi3nt.spline.splines.builder.bspline.dim1; import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; -import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; public class DirectBCurveController implements BCurveController { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java index c68ea4e..c8e91eb 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java @@ -1,9 +1,6 @@ package fr.radi3nt.spline.splines.builder.bspline.dim1; import fr.radi3nt.spline.curve.curves.bcurve.BCurveController; -import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController; - -import java.util.concurrent.atomic.AtomicReference; public class InferredBCurveController implements BCurveController { diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java index b06535a..7e16247 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java @@ -2,7 +2,6 @@ import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineBuilder; -import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineBuilder; import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D; import fr.radi3nt.spline.splines.dimensions.Spline3D; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java index 6a7f89d..adccd63 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java @@ -2,7 +2,6 @@ import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineController; -import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineController; public class BSplineController3D { From f913b56a4a11b7e87c56e15d8c83811e438313f2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 2 May 2024 14:00:36 +0200 Subject: [PATCH 059/125] Math improvement (#16) * Made AABB class interface - Create SetAABB and VerticesAABB implementations * Added caching to VectorSmoothDynamics * Added copy() method to vectors * Added message to IllegalArgumentException * Split getMagnitude() by extracting getSquaredMagnitude() * Simplified zero() in ComponentsQuaternion * Improved as to how matrices are constructed * Added scalar() method to Matrix4x4 --- .../main/java/fr/radi3nt/maths/aabb/AABB.java | 27 ++---- .../fr/radi3nt/maths/aabb/AxisMapping.java | 32 ++++++- .../java/fr/radi3nt/maths/aabb/SetAABB.java | 74 ++++++++++++++++ .../fr/radi3nt/maths/aabb/VerticesAABB.java | 84 +++++++++++++++++++ .../advanced/matrix/ArrayMatrix3x3.java | 17 +++- .../advanced/matrix/ArrayMatrix4x4.java | 32 ++++++- .../components/advanced/matrix/Matrix4x4.java | 2 + .../quaternions/ComponentsQuaternion.java | 9 +- .../advanced/quaternions/Quaternion.java | 1 + .../arbitrary/OperatingVectorNf.java | 2 + .../maths/components/arbitrary/VectorNf.java | 11 +++ .../arbitrary/vector/ArrayVectorNf.java | 6 +- .../implementations/SimpleVector3f.java | 10 +++ .../implementations/SimpleVector4f.java | 11 +++ .../maths/dynamics/VectorSmoothDynamics.java | 25 ++++-- .../maths/sat/shape/VerticesSATShape.java | 3 +- 16 files changed, 308 insertions(+), 38 deletions(-) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java index fc2cf79..8197bce 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java @@ -1,26 +1,13 @@ package fr.radi3nt.maths.aabb; -public class AABB { +public interface AABB { - private final AxisMapping xMapping; - private final AxisMapping yMapping; - private final AxisMapping zMapping; + AxisMapping getxMapping(); + AxisMapping getxMapping(AxisMapping mapping); + AxisMapping getyMapping(); + AxisMapping getyMapping(AxisMapping mapping); + AxisMapping getzMapping(); + AxisMapping getzMapping(AxisMapping mapping); - public AABB(AxisMapping xMapping, AxisMapping yMapping, AxisMapping zMapping) { - this.xMapping = xMapping; - this.yMapping = yMapping; - this.zMapping = zMapping; - } - public AxisMapping getxMapping() { - return xMapping; - } - - public AxisMapping getyMapping() { - return yMapping; - } - - public AxisMapping getzMapping() { - return zMapping; - } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java index eb92f15..77d0bb2 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java @@ -2,15 +2,41 @@ public class AxisMapping { - private final double min; - private final double max; + private float min; + private float max; - public AxisMapping(double min, double max) { + public AxisMapping(float min, float max) { this.min = min; this.max = max; } + public void extend(float added) { + min-=added; + max+=added; + } + + public boolean inside(float pos) { + return this.min <= pos && this.max>=pos; + } + public boolean intersect(AxisMapping axisMapping) { return (min <= axisMapping.max && max >= axisMapping.min); } + + public boolean intersect(AxisMapping axisMapping, float offset) { + return (min+offset <= axisMapping.max && max+offset >= axisMapping.min); + } + + public float getMin() { + return min; + } + + public float getMax() { + return max; + } + + public void set(float min, float max) { + this.min = min; + this.max = max; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java new file mode 100644 index 0000000..c9058c2 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java @@ -0,0 +1,74 @@ +package fr.radi3nt.maths.aabb; + +public class SetAABB implements AABB { + + private final AxisMapping xMapping; + private final AxisMapping yMapping; + private final AxisMapping zMapping; + + public SetAABB(AxisMapping xMapping, AxisMapping yMapping, AxisMapping zMapping) { + this.xMapping = xMapping; + this.yMapping = yMapping; + this.zMapping = zMapping; + } + + public static SetAABB zero() { + return new SetAABB(new AxisMapping(0, 0), new AxisMapping(0, 0), new AxisMapping(0, 0)); + } + + public void copy(AABB aabb) { + copy(aabb.getxMapping(xMapping), aabb.getyMapping(yMapping), aabb.getzMapping(zMapping)); + } + + public void copy(AABB aabb, float added) { + copy(aabb.getxMapping(xMapping), aabb.getyMapping(yMapping), aabb.getzMapping(zMapping), added); + } + + + private void copy(AxisMapping x, AxisMapping y, AxisMapping z) { + copy(x.getMin(), x.getMax(), y.getMin(), y.getMax(), z.getMin(), z.getMax()); + } + + private void copy(AxisMapping x, AxisMapping y, AxisMapping z, float added) { + copy(x.getMin()-added, x.getMax()+added, y.getMin()-added, y.getMax()+added, z.getMin()-added, z.getMax()+added); + } + + public void extend(float added) { + xMapping.extend(added); + yMapping.extend(added); + zMapping.extend(added); + } + + public void copy(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) { + xMapping.set(minX, maxX); + yMapping.set(minY, maxY); + zMapping.set(minZ, maxZ); + } + + public AxisMapping getxMapping() { + return xMapping; + } + + @Override + public AxisMapping getxMapping(AxisMapping mapping) { + return xMapping; + } + + public AxisMapping getyMapping() { + return yMapping; + } + + @Override + public AxisMapping getyMapping(AxisMapping mapping) { + return yMapping; + } + + public AxisMapping getzMapping() { + return zMapping; + } + + @Override + public AxisMapping getzMapping(AxisMapping mapping) { + return zMapping; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java new file mode 100644 index 0000000..3b6584c --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java @@ -0,0 +1,84 @@ +package fr.radi3nt.maths.aabb; + +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class VerticesAABB implements AABB { + + private final Vector3f[] transformedVertices; + + public VerticesAABB(Vector3f[] vertices) { + transformedVertices = vertices; + } + + public AxisMapping getxMapping() { + float maxX = -Float.MAX_VALUE; + float minX = Float.MAX_VALUE; + + for (Vector3f currentVertex : transformedVertices) { + maxX = Math.max(maxX, currentVertex.getX()); + minX = Math.min(minX, currentVertex.getX()); + } + return new AxisMapping(minX, maxX); + } + + @Override + public AxisMapping getxMapping(AxisMapping mapping) { + float maxX = -Float.MAX_VALUE; + float minX = Float.MAX_VALUE; + for (Vector3f currentVertex : transformedVertices) { + maxX = Math.max(maxX, currentVertex.getX()); + minX = Math.min(minX, currentVertex.getX()); + } + mapping.set(minX, maxX); + return mapping; + } + + public AxisMapping getyMapping() { + float maxY = -Float.MAX_VALUE; + float minY = Float.MAX_VALUE; + + for (Vector3f currentVertex : transformedVertices) { + maxY = Math.max(maxY, currentVertex.getY()); + minY = Math.min(minY, currentVertex.getY()); + } + return new AxisMapping(minY, maxY); + } + + @Override + public AxisMapping getyMapping(AxisMapping mapping) { + float maxY = -Float.MAX_VALUE; + float minY = Float.MAX_VALUE; + + for (Vector3f currentVertex : transformedVertices) { + maxY = Math.max(maxY, currentVertex.getY()); + minY = Math.min(minY, currentVertex.getY()); + } + mapping.set(minY, maxY); + return mapping; + } + + public AxisMapping getzMapping() { + float maxZ = -Float.MAX_VALUE; + float minZ = Float.MAX_VALUE; + + for (Vector3f currentVertex : transformedVertices) { + maxZ = Math.max(maxZ, currentVertex.getZ()); + minZ = Math.min(minZ, currentVertex.getZ()); + } + return new AxisMapping(minZ, maxZ); + } + + @Override + public AxisMapping getzMapping(AxisMapping mapping) { + float maxZ = -Float.MAX_VALUE; + float minZ = Float.MAX_VALUE; + + for (Vector3f currentVertex : transformedVertices) { + maxZ = Math.max(maxZ, currentVertex.getZ()); + minZ = Math.min(minZ, currentVertex.getZ()); + } + mapping.set(minZ, maxZ); + return mapping; + } + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java index e845b17..8fb5f57 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -10,13 +10,14 @@ public class ArrayMatrix3x3 implements Matrix3x3 { - private final float[][] m = new float[3][3]; + private final float[][] m; public ArrayMatrix3x3() { - + m = new float[3][3]; } public ArrayMatrix3x3(ArrayMatrix3x3 copy) { + m = new float[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { set(i, j, copy.get(i, j)); @@ -24,12 +25,24 @@ public ArrayMatrix3x3(ArrayMatrix3x3 copy) { } } + public ArrayMatrix3x3(float[][] m) { + this.m = m; + } + public static ArrayMatrix3x3 newIdentity() { ArrayMatrix3x3 arrayMatrix4x4 = new ArrayMatrix3x3(); arrayMatrix4x4.identity(); return arrayMatrix4x4; } + public static ArrayMatrix3x3 from(float[] m) { + float[][] correctM = new float[][] {new float[3], new float[3], new float[3]}; + for (int i = 0; i < m.length; i++) { + correctM[i%3][i/3] = m[i]; + } + return new ArrayMatrix3x3(correctM); + } + @Override public void identity() { zero(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 19a2d51..c470e52 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -11,21 +11,28 @@ public class ArrayMatrix4x4 implements Matrix4x4 { - private final float[][] m = new float[4][4]; + private final float[][] m; public ArrayMatrix4x4(fr.radi3nt.maths.components.matrices.Matrix copy) { + m = new float[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { set(i, j, copy.get(i, j)); } } + } public ArrayMatrix4x4() { + m = new float[4][4]; + } + public ArrayMatrix4x4(float[][] m) { + this.m = m; } public ArrayMatrix4x4(ArrayMatrix4x4 copy) { + m = new float[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { set(i, j, copy.get(i, j)); @@ -33,6 +40,14 @@ public ArrayMatrix4x4(ArrayMatrix4x4 copy) { } } + public static ArrayMatrix4x4 from(float[] m) { + float[][] correctM = new float[][] {new float[4], new float[4], new float[4], new float[4]}; + for (int i = 0; i < m.length; i++) { + correctM[i%4][i/4] = m[i]; + } + return new ArrayMatrix4x4(correctM); + } + public static ArrayMatrix4x4 newIdentity() { ArrayMatrix4x4 arrayMatrix4x4 = new ArrayMatrix4x4(); arrayMatrix4x4.identity(); @@ -156,6 +171,21 @@ public Matrix4x4 duplicate() { return new ArrayMatrix4x4(this); } + @Override + public void scalar(Vector3f size) { + m[0][0]*=size.getX(); + m[0][1]*=size.getX(); + m[0][2]*=size.getX(); + + m[1][0]*=size.getY(); + m[1][1]*=size.getY(); + m[1][2]*=size.getY(); + + m[2][0]*=size.getZ(); + m[2][1]*=size.getZ(); + m[2][2]*=size.getZ(); + } + @Override public Quaternion getRotation() { return getCopySignRotation(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index c385a9a..ac1d1e5 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -38,4 +38,6 @@ public interface Matrix4x4 extends Matrix { void copy(Matrix result); Matrix4x4 duplicate(); + + void scalar(Vector3f size); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 8b2a361..6b25cf4 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -98,7 +98,7 @@ public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angle } public static Quaternion zero() { - return ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.zero()); + return new ComponentsQuaternion(0, 0, 0, 1); } public static Quaternion fromVec4(Vector4f response) { @@ -295,7 +295,12 @@ public float dot(Quaternion other) { @Override public float getMagnitude() { - return (float) sqrt(w * w + x * x + y * y + z * z); + return (float) sqrt(getSquaredMagnitude()); + } + + @Override + public float getSquaredMagnitude() { + return w * w + x * x + y * y + z * z; } @Override diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index be199a7..c7a8d66 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -46,6 +46,7 @@ public interface Quaternion { float dot(Quaternion other); float getMagnitude(); + float getSquaredMagnitude(); Quaternion getConjugate(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java index 71ca7a8..40a207d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/OperatingVectorNf.java @@ -15,4 +15,6 @@ public interface OperatingVectorNf { int size(); float length(); + + void copy(OperatingVectorNf other); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java index 87f170a..719e5f4 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/VectorNf.java @@ -15,4 +15,15 @@ public interface VectorNf extends Vector, OperatingVectorNf { void clamp(int row, float min, float max); int size(); + + VectorNf duplicate(); + + default void copy(OperatingVectorNf other) { + if (other.size()!=this.size()) { + throw new IllegalArgumentException("Other vector doesn't have the same size"); + } + for (int i = 0; i < this.size(); i++) { + this.set(i, other.get(i)); + } + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java index 7a7b027..ea035dd 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/arbitrary/vector/ArrayVectorNf.java @@ -14,7 +14,7 @@ public ArrayVectorNf(int size) { vector = new float[size]; } - private ArrayVectorNf(float[] vector) { + public ArrayVectorNf(float... vector) { this.vector = vector; } @@ -59,7 +59,7 @@ public ArrayVectorNf mul(float number) { @Override public ArrayVectorNf add(OperatingVectorNf other) { if (other.size()!=this.size()) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("This vector's size (" + size() +") does not match the argument vector size (" + other.size() + ")"); for (int i = 0; i < vector.length; i++) { vector[i]+=other.get(i); } @@ -69,7 +69,7 @@ public ArrayVectorNf add(OperatingVectorNf other) { @Override public ArrayVectorNf sub(OperatingVectorNf other) { if (other.size()!=this.size()) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("This vector's size (" + size() +") does not match the argument vector size (" + other.size() + ")"); for (int i = 0; i < vector.length; i++) { vector[i]-=other.get(i); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index 17b5cab..68f063c 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -251,6 +251,16 @@ public float length() { return (float) Math.sqrt(x * x + y * y + z * z); } + @Override + public void copy(OperatingVectorNf other) { + if (other.size()!=this.size()) { + throw new IllegalArgumentException("Other vector doesn't have the same size"); + } + x = other.get(0); + y = other.get(1); + z = other.get(2); + } + @Override public String toString() { return "SimpleVector3f{" + diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index efae448..941f802 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -173,6 +173,17 @@ public float length() { return (float) Math.sqrt(x * x + y * y + z * z + w * w); } + @Override + public void copy(OperatingVectorNf other) { + if (other.size()!=this.size()) { + throw new IllegalArgumentException("Other vector doesn't have the same size"); + } + x = other.get(0); + y = other.get(1); + z = other.get(2); + w = other.get(3); + } + @Override public String toString() { return "SimpleVector4f{" + diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java index f8ab14c..8a64728 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java @@ -7,6 +7,10 @@ public class VectorSmoothDynamics { private DynamicsConstants constants; protected T inputPrevious, inputCurrent; protected T response, responseDerivative; + + private final T inputDerivativeCache; + private final T responseDerivativeCache; + private float speed = 0; public VectorSmoothDynamics(DynamicsConstants constants, T start) { @@ -15,13 +19,16 @@ public VectorSmoothDynamics(DynamicsConstants constants, T start) { this.inputCurrent = (T) start.duplicate(); this.inputPrevious = (T) start.duplicate(); responseDerivative = (T) start.duplicate().mul(0); + inputDerivativeCache = (T) start.duplicate().mul(0); + responseDerivativeCache = (T) start.duplicate().mul(0); } public void update(float step) { if (step==0) return; - OperatingVectorNf inputDerivative = inputCurrent.duplicate().sub(inputPrevious).div(step); - inputPrevious = (T) inputCurrent.duplicate(); + inputDerivativeCache.copy(inputCurrent); + inputDerivativeCache.sub(inputPrevious).div(step); + inputPrevious.copy(inputCurrent); float k1Stable, k2Stable; if (systemIsAtHighSpeed(constants, step)) { k1Stable = constants.getK1(); @@ -31,10 +38,12 @@ public void update(float step) { k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); } - response.add(responseDerivative.duplicate().mul(step)); - //responseDerivative.add(inputDerivative.mul(constants.getK3()).add(inputCurrent).sub(response).sub(responseDerivative.duplicate().mul(k1Stable)).div(k2Stable).mul(step)); - OperatingVectorNf multipliedByTTerm = inputDerivative.mul(constants.getK3()).add(inputCurrent).sub(response).mul(step); - responseDerivative = (T) multipliedByTTerm.add(responseDerivative.duplicate().mul(k2Stable)).div(k2Stable+step*k1Stable); + responseDerivativeCache.copy(responseDerivative); + response.add(responseDerivativeCache.mul(step)); + responseDerivativeCache.copy(responseDerivative); + + OperatingVectorNf multipliedByTTerm = inputDerivativeCache.mul(constants.getK3()).add(inputCurrent).sub(response).mul(step); + responseDerivative.copy(multipliedByTTerm.add(responseDerivativeCache.mul(k2Stable)).div(k2Stable+step*k1Stable)); speed = responseDerivative.length(); } @@ -50,6 +59,10 @@ public void setInputCurrent(T inputCurrent) { this.inputCurrent = inputCurrent; } + public T getInputCurrent() { + return inputCurrent; + } + public T getResponse() { return response; } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java index dbf9e1a..f23e095 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java @@ -2,6 +2,7 @@ import fr.radi3nt.maths.aabb.AABB; import fr.radi3nt.maths.aabb.AxisMapping; +import fr.radi3nt.maths.aabb.SetAABB; import fr.radi3nt.maths.components.Vector3D; import fr.radi3nt.maths.sat.clip.ClipPlanes; import fr.radi3nt.maths.sat.clip.Edge; @@ -53,7 +54,7 @@ default AABB toAABB() { minZ = (float) Math.min(minZ, vertex.getZ()); } - aabb = new AABB( + aabb = new SetAABB( new AxisMapping(minX, maxX), new AxisMapping(minY, maxY), new AxisMapping(minZ, maxZ)); From d4e86e75d09826df68270676d777097da0f2a61c Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 2 May 2024 14:03:25 +0200 Subject: [PATCH 060/125] Cleanup in ResourceFile and JsonObject - Removed commented code - Refactored ResourceFile to allow final path variable --- .../fr/radi3nt/file/impl/ResourceFile.java | 29 +++++++++++++++---- .../main/java/fr/radi3nt/json/JsonObject.java | 28 ------------------ 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java index 22ccafb..7269708 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java @@ -4,13 +4,14 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Objects; public class ResourceFile implements ReadableFile { private static final String FILE_SEPARATOR = "/"; private static final String BASE_PATH = ""; - private String path; + private final String path; private final String name; public ResourceFile(String path) { @@ -20,10 +21,11 @@ public ResourceFile(String path) { } public ResourceFile(String... paths) { - this.path = BASE_PATH; + String path = BASE_PATH; for (final String part : paths) { - this.path += FILE_SEPARATOR + part; + path += FILE_SEPARATOR + part; } + this.path = path; final String[] dirs = this.path.split(FILE_SEPARATOR); this.name = dirs[dirs.length - 1]; } @@ -34,10 +36,11 @@ public ResourceFile(ResourceFile file, String subFile) { } public ResourceFile(ResourceFile file, String... subFiles) { - this.path = file.path; + String path = file.path; for (String part : subFiles) { - this.path += (FILE_SEPARATOR + part); + path += (FILE_SEPARATOR + part); } + this.path = path; String[] dirs = path.split(FILE_SEPARATOR); this.name = dirs[dirs.length - 1]; } @@ -75,4 +78,20 @@ public boolean isCreated() { return exists; } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ResourceFile)) return false; + + ResourceFile that = (ResourceFile) o; + return Objects.equals(path, that.path) && Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(path); + result = 31 * result + Objects.hashCode(name); + return result; + } } diff --git a/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java b/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java index 40a5900..7c18503 100644 --- a/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java +++ b/JsonHelper/src/main/java/fr/radi3nt/json/JsonObject.java @@ -173,34 +173,6 @@ public JsonObject merge(final JsonObject object) { return this; } - -/* - public JsonObject merge(final JsonObject object) { - if (object == null) { - throw new NullPointerException("object is null"); - } - ArrayList arrayList = new ArrayList<>(); - for (Member member : object) { - arrayList.add(member); - } - Collections.reverse(arrayList); - Member lastJson = new Member("null", new JsonString("null")); - for (Member member : arrayList) { - final int index = this.indexOf(member.getName()); - if (index!=0) { - JsonObject jsonObject= new JsonObject().add(member.getName(), member.getValue()); - jsonObject.add(lastJson.getName(), member.getValue()); - this.set(member.getName(), jsonObject); - } else { - this.add(member.getName(), member.getValue()); - } - lastJson=member; - } - return this; - } - - */ - public JsonValue get(final String name) { if (name == null) { throw new NullPointerException("name is null"); From 5b79dbecc9759bcff39bb1784785d2cab8a120e9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 Jul 2024 23:09:45 +0200 Subject: [PATCH 061/125] Improved pools (#17) Added different kind of pools --- .../maths/pool/ConcurrentQueuedPool.java | 25 +++++++++++++++++ .../maths/pool/ConcurrentVector3fPool.java | 22 +++++++++++++++ .../java/fr/radi3nt/maths/pool/ListPool.java | 28 +++++++++++++++++++ .../radi3nt/maths/pool/ListVector3fPool.java | 22 +++++++++++++++ .../fr/radi3nt/maths/pool/QueuedPool.java | 7 +++-- 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java new file mode 100644 index 0000000..820d200 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java @@ -0,0 +1,25 @@ +package fr.radi3nt.maths.pool; + +import java.util.Deque; +import java.util.concurrent.ConcurrentLinkedDeque; + +public abstract class ConcurrentQueuedPool implements ObjectPool { + + protected final Deque queue = new ConcurrentLinkedDeque<>(); + + @Override + public T borrow() { + T object = queue.pollFirst(); + if (object == null) + return create(); + + return object; + } + + protected abstract T create(); + + @Override + public void free(T object) { + queue.addFirst(object); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java new file mode 100644 index 0000000..bed93b5 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.pool; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ConcurrentVector3fPool extends ConcurrentQueuedPool { + + public ConcurrentVector3fPool() { + } + + public ConcurrentVector3fPool(int baseObjectAmount) { + for (int i = 0; i < baseObjectAmount; i++) { + queue.add(create()); + } + } + + @Override + protected Vector3f create() { + return new SimpleVector3f(); + } + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java new file mode 100644 index 0000000..94babe3 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java @@ -0,0 +1,28 @@ +package fr.radi3nt.maths.pool; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ListPool implements ObjectPool { + + protected final List queue = new ArrayList<>(); + + @Override + public T borrow() { + if (queue.isEmpty()) + return create(); + + T object = queue.remove(queue.size()-1); + if (object == null) + return create(); + + return object; + } + + protected abstract T create(); + + @Override + public void free(T object) { + queue.add(object); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java new file mode 100644 index 0000000..9981c96 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java @@ -0,0 +1,22 @@ +package fr.radi3nt.maths.pool; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ListVector3fPool extends ListPool { + + public ListVector3fPool() { + } + + public ListVector3fPool(int baseObjectAmount) { + for (int i = 0; i < baseObjectAmount; i++) { + queue.add(create()); + } + } + + @Override + protected Vector3f create() { + return new SimpleVector3f(); + } + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java index f5796a8..2088153 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java @@ -1,14 +1,15 @@ package fr.radi3nt.maths.pool; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.ArrayDeque; +import java.util.Deque; public abstract class QueuedPool implements ObjectPool { - protected final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); + protected final Deque queue = new ArrayDeque<>(); @Override public T borrow() { - T object = queue.poll(); + T object = queue.pollLast(); if (object == null) return create(); From eda332fff5d5f6db6cb88b430f5d1ad08e746885 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 Jul 2024 23:11:52 +0200 Subject: [PATCH 062/125] Added IllegalStateException when InputStream is null --- .../src/main/java/fr/radi3nt/file/impl/ResourceFile.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java index 7269708..d918d4a 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/impl/ResourceFile.java @@ -55,7 +55,10 @@ public String toString() { } public InputStream getInputStream() { - return ResourceFile.class.getResourceAsStream(path); + InputStream stream = ResourceFile.class.getResourceAsStream(path); + if (stream==null) + throw new IllegalStateException("Could not get resource '" + path + "', as it doesn't seem to exist"); + return stream; } public String getName() { From eb46584f366e2f069ca989938cef8dfd56e7ff38 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 Jul 2024 23:13:20 +0200 Subject: [PATCH 063/125] Removed AABB and SAT package from module MathsHelper --- .../main/java/fr/radi3nt/maths/aabb/AABB.java | 13 -- .../fr/radi3nt/maths/aabb/AxisMapping.java | 42 ----- .../java/fr/radi3nt/maths/aabb/SetAABB.java | 74 -------- .../fr/radi3nt/maths/aabb/VerticesAABB.java | 84 --------- .../fr/radi3nt/maths/sat/SatResolver.java | 82 --------- .../fr/radi3nt/maths/sat/shape/BoxSAT.java | 95 ---------- .../fr/radi3nt/maths/sat/shape/SATShape.java | 16 -- .../maths/sat/shape/TransformedBoxSAT.java | 145 --------------- .../maths/sat/shape/VerticesSATShape.java | 63 ------- .../shape/triangles/ComputingTriangleSAT.java | 103 ----------- .../shape/triangles/StoringTriangleSAT.java | 67 ------- .../sat/shape/triangles/TriangleSAT.java | 8 - .../sat/swept/CheepSweptSatResolver.java | 166 ------------------ .../sat/swept/EconomicSweptSatResolver.java | 118 ------------- .../radi3nt/maths/sat/swept/SweptResult.java | 79 --------- .../maths/sat/swept/SweptSatResolver.java | 110 ------------ 16 files changed, 1265 deletions(-) delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java deleted file mode 100644 index 8197bce..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AABB.java +++ /dev/null @@ -1,13 +0,0 @@ -package fr.radi3nt.maths.aabb; - -public interface AABB { - - AxisMapping getxMapping(); - AxisMapping getxMapping(AxisMapping mapping); - AxisMapping getyMapping(); - AxisMapping getyMapping(AxisMapping mapping); - AxisMapping getzMapping(); - AxisMapping getzMapping(AxisMapping mapping); - - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java deleted file mode 100644 index 77d0bb2..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/AxisMapping.java +++ /dev/null @@ -1,42 +0,0 @@ -package fr.radi3nt.maths.aabb; - -public class AxisMapping { - - private float min; - private float max; - - public AxisMapping(float min, float max) { - this.min = min; - this.max = max; - } - - public void extend(float added) { - min-=added; - max+=added; - } - - public boolean inside(float pos) { - return this.min <= pos && this.max>=pos; - } - - public boolean intersect(AxisMapping axisMapping) { - return (min <= axisMapping.max && max >= axisMapping.min); - } - - public boolean intersect(AxisMapping axisMapping, float offset) { - return (min+offset <= axisMapping.max && max+offset >= axisMapping.min); - } - - public float getMin() { - return min; - } - - public float getMax() { - return max; - } - - public void set(float min, float max) { - this.min = min; - this.max = max; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java deleted file mode 100644 index c9058c2..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/SetAABB.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.radi3nt.maths.aabb; - -public class SetAABB implements AABB { - - private final AxisMapping xMapping; - private final AxisMapping yMapping; - private final AxisMapping zMapping; - - public SetAABB(AxisMapping xMapping, AxisMapping yMapping, AxisMapping zMapping) { - this.xMapping = xMapping; - this.yMapping = yMapping; - this.zMapping = zMapping; - } - - public static SetAABB zero() { - return new SetAABB(new AxisMapping(0, 0), new AxisMapping(0, 0), new AxisMapping(0, 0)); - } - - public void copy(AABB aabb) { - copy(aabb.getxMapping(xMapping), aabb.getyMapping(yMapping), aabb.getzMapping(zMapping)); - } - - public void copy(AABB aabb, float added) { - copy(aabb.getxMapping(xMapping), aabb.getyMapping(yMapping), aabb.getzMapping(zMapping), added); - } - - - private void copy(AxisMapping x, AxisMapping y, AxisMapping z) { - copy(x.getMin(), x.getMax(), y.getMin(), y.getMax(), z.getMin(), z.getMax()); - } - - private void copy(AxisMapping x, AxisMapping y, AxisMapping z, float added) { - copy(x.getMin()-added, x.getMax()+added, y.getMin()-added, y.getMax()+added, z.getMin()-added, z.getMax()+added); - } - - public void extend(float added) { - xMapping.extend(added); - yMapping.extend(added); - zMapping.extend(added); - } - - public void copy(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) { - xMapping.set(minX, maxX); - yMapping.set(minY, maxY); - zMapping.set(minZ, maxZ); - } - - public AxisMapping getxMapping() { - return xMapping; - } - - @Override - public AxisMapping getxMapping(AxisMapping mapping) { - return xMapping; - } - - public AxisMapping getyMapping() { - return yMapping; - } - - @Override - public AxisMapping getyMapping(AxisMapping mapping) { - return yMapping; - } - - public AxisMapping getzMapping() { - return zMapping; - } - - @Override - public AxisMapping getzMapping(AxisMapping mapping) { - return zMapping; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java b/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java deleted file mode 100644 index 3b6584c..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/aabb/VerticesAABB.java +++ /dev/null @@ -1,84 +0,0 @@ -package fr.radi3nt.maths.aabb; - -import fr.radi3nt.maths.components.vectors.Vector3f; - -public class VerticesAABB implements AABB { - - private final Vector3f[] transformedVertices; - - public VerticesAABB(Vector3f[] vertices) { - transformedVertices = vertices; - } - - public AxisMapping getxMapping() { - float maxX = -Float.MAX_VALUE; - float minX = Float.MAX_VALUE; - - for (Vector3f currentVertex : transformedVertices) { - maxX = Math.max(maxX, currentVertex.getX()); - minX = Math.min(minX, currentVertex.getX()); - } - return new AxisMapping(minX, maxX); - } - - @Override - public AxisMapping getxMapping(AxisMapping mapping) { - float maxX = -Float.MAX_VALUE; - float minX = Float.MAX_VALUE; - for (Vector3f currentVertex : transformedVertices) { - maxX = Math.max(maxX, currentVertex.getX()); - minX = Math.min(minX, currentVertex.getX()); - } - mapping.set(minX, maxX); - return mapping; - } - - public AxisMapping getyMapping() { - float maxY = -Float.MAX_VALUE; - float minY = Float.MAX_VALUE; - - for (Vector3f currentVertex : transformedVertices) { - maxY = Math.max(maxY, currentVertex.getY()); - minY = Math.min(minY, currentVertex.getY()); - } - return new AxisMapping(minY, maxY); - } - - @Override - public AxisMapping getyMapping(AxisMapping mapping) { - float maxY = -Float.MAX_VALUE; - float minY = Float.MAX_VALUE; - - for (Vector3f currentVertex : transformedVertices) { - maxY = Math.max(maxY, currentVertex.getY()); - minY = Math.min(minY, currentVertex.getY()); - } - mapping.set(minY, maxY); - return mapping; - } - - public AxisMapping getzMapping() { - float maxZ = -Float.MAX_VALUE; - float minZ = Float.MAX_VALUE; - - for (Vector3f currentVertex : transformedVertices) { - maxZ = Math.max(maxZ, currentVertex.getZ()); - minZ = Math.min(minZ, currentVertex.getZ()); - } - return new AxisMapping(minZ, maxZ); - } - - @Override - public AxisMapping getzMapping(AxisMapping mapping) { - float maxZ = -Float.MAX_VALUE; - float minZ = Float.MAX_VALUE; - - for (Vector3f currentVertex : transformedVertices) { - maxZ = Math.max(maxZ, currentVertex.getZ()); - minZ = Math.min(minZ, currentVertex.getZ()); - } - mapping.set(minZ, maxZ); - return mapping; - } - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java deleted file mode 100644 index 62d7c3c..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/SatResolver.java +++ /dev/null @@ -1,82 +0,0 @@ -package fr.radi3nt.maths.sat; - -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; -import fr.radi3nt.maths.sat.shape.SATShape; - -public class SatResolver { - - private final SatProjectionProvider provider0; - private final SatProjectionProvider provider1; - - private final SATShape shape1; - private final SATShape shape2; - - private SatAxis msa = null; - private double penetration = Double.MAX_VALUE; - - public SatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2) { - this.provider0 = provider; - this.provider1 = provider.duplicate(); - this.shape1 = shape1; - this.shape2 = shape2; - } - - public boolean resolve() { - penetration = Double.MAX_VALUE; - msa = null; - - SatAxis[] axes1 = shape1.getAxes(); - SatAxis[] axes2 = shape2.getAxes(); - if (testOverlapOnAxes(axes1)) return false; - if (testOverlapOnAxes(axes2)) return false; - - SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); - return !testOverlapOnAxes(edgeAxis); - } - - private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { - int size = edges.length * others.length; - SatAxis[] axes = new SatAxis[size]; - int i = 0; - for (SatEdge edge : edges) { - for (SatEdge other : others) { - axes[i] = edge.axis(other); - i++; - } - } - return axes; - } - - private boolean testOverlapOnAxes(SatAxis[] axes) { - for (SatAxis axis : axes) { - if (axis.getNormal().lengthSquared() == 0 || Double.isNaN(axis.getNormal().lengthSquared())) - continue; - - SatProjection p1 = shape1.project(provider0, axis); - SatProjection p2 = shape2.project(provider1, axis); - - if (p1.noOverlap(p2)) - return true; - - double signedPenetration = p1.getOverlap(p2); - double penetration = Math.abs(signedPenetration); - if (this.penetration > penetration) { - this.msa = axis; - this.penetration = penetration; - } - } - - return false; - } - - public double getPenetration() { - return penetration; - } - - public SatAxis getMsa() { - return msa; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java deleted file mode 100644 index c3aa191..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/BoxSAT.java +++ /dev/null @@ -1,95 +0,0 @@ -package fr.radi3nt.maths.sat.shape; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.clip.AxisAndVertexIndex; -import fr.radi3nt.maths.sat.clip.ClipPlane; -import fr.radi3nt.maths.sat.clip.ClipPlanes; -import fr.radi3nt.maths.sat.clip.Edge; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; - -public class BoxSAT implements VerticesSATShape { - - private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ - new AxisAndVertexIndex(new Vector3D(1, 0, 0), 1), - new AxisAndVertexIndex(new Vector3D(0, 1, 0), 1), - new AxisAndVertexIndex(new Vector3D(0, 0, 1), 1), - new AxisAndVertexIndex(new Vector3D(-1, 0, 0), 0), - new AxisAndVertexIndex(new Vector3D(0, -1, 0), 0), - new AxisAndVertexIndex(new Vector3D(0, 0, -1), 0), - }; - - private static final SatAxis[] SAT_AXES = new SatAxis[]{ - new SatAxis(new Vector3D(1, 0, 0)), - new SatAxis(new Vector3D(0, 1, 0)), - new SatAxis(new Vector3D(0, 0, 1)) - }; - - private static final SatEdge[] SAT_EDGES = new SatEdge[]{ - new SatEdge(new Vector3D(1, 0, 0)), - new SatEdge(new Vector3D(0, 1, 0)), - new SatEdge(new Vector3D(0, 0, 1)) - }; - - private final Vector3D[] vertices; - - public BoxSAT(Vector3D min, Vector3D max) { - vertices = new Vector3D[]{ - min.clone(), - max.clone(), - new Vector3D(max.getX(), min.getY(), min.getZ()), - new Vector3D(max.getX(), max.getY(), min.getZ()), - new Vector3D(min.getX(), max.getY(), min.getZ()), - new Vector3D(min.getX(), max.getY(), max.getZ()), - new Vector3D(min.getX(), min.getY(), max.getZ()), - new Vector3D(max.getX(), min.getY(), max.getZ()) - }; - } - - @Override - public SatAxis[] getAxes() { - return SAT_AXES; - } - - @Override - public SatEdge[] getEdges() { - return SAT_EDGES; - } - - @Override - public ClipPlanes getClipPlanes() { - ClipPlane[] clipPlaneArray = new ClipPlane[6]; - for (int i = 0; i < SAT_CLIP_PLANES.length; i++) { - AxisAndVertexIndex satClipPlane = SAT_CLIP_PLANES[i]; - clipPlaneArray[i] = new ClipPlane(satClipPlane.getAxis(), vertices[satClipPlane.getIndex()]); - } - return new ClipPlanes(clipPlaneArray); - } - - @Override - public Vector3D[] getVertices() { - return vertices; - } - - @Override - public Edge[] getClipEdges() { - return new Edge[] { - new Edge(vertices[0], vertices[6]), - new Edge(vertices[0], vertices[4]), - new Edge(vertices[0], vertices[2]), - - new Edge(vertices[1], vertices[7]), - new Edge(vertices[1], vertices[5]), - new Edge(vertices[1], vertices[3]), - - new Edge(vertices[6], vertices[7]), - new Edge(vertices[7], vertices[2]), - - new Edge(vertices[5], vertices[4]), - new Edge(vertices[4], vertices[3]), - - new Edge(vertices[5], vertices[6]), - new Edge(vertices[3], vertices[2]) - }; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java deleted file mode 100644 index 8c9aff4..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/SATShape.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.radi3nt.maths.sat.shape; - -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; - -public interface SATShape { - - SatAxis[] getAxes(); - - SatEdge[] getEdges(); - - SatProjection project(SatProjectionProvider provider, SatAxis axis); - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java deleted file mode 100644 index 63f4922..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/TransformedBoxSAT.java +++ /dev/null @@ -1,145 +0,0 @@ -package fr.radi3nt.maths.sat.shape; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; -import fr.radi3nt.maths.components.vectors.Vector4f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; -import fr.radi3nt.maths.sat.clip.AxisAndVertexIndex; -import fr.radi3nt.maths.sat.clip.ClipPlane; -import fr.radi3nt.maths.sat.clip.ClipPlanes; -import fr.radi3nt.maths.sat.clip.Edge; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; - -public class TransformedBoxSAT implements VerticesSATShape { - - private static final AxisAndVertexIndex[] SAT_CLIP_PLANES = new AxisAndVertexIndex[]{ - new AxisAndVertexIndex(new Vector3D(1, 0, 0), 0), - new AxisAndVertexIndex(new Vector3D(0, 1, 0), 0), - new AxisAndVertexIndex(new Vector3D(0, 0, 1), 0), - new AxisAndVertexIndex(new Vector3D(-1, 0, 0), 1), - new AxisAndVertexIndex(new Vector3D(0, -1, 0), 1), - new AxisAndVertexIndex(new Vector3D(0, 0, -1), 1), - }; - - private final Vector3D[] vertices; - private Vector3D[] axis; - private SatAxis[] satAxes; - private Matrix4x4 transform; - - public TransformedBoxSAT(Vector3D min, Vector3D max, Matrix4x4 transform) { - this.transform = transform; - vertices = new Vector3D[]{ - min.clone(), - max.clone(), - new Vector3D(max.getX(), min.getY(), min.getZ()), - new Vector3D(max.getX(), max.getY(), min.getZ()), - new Vector3D(min.getX(), max.getY(), min.getZ()), - new Vector3D(min.getX(), max.getY(), max.getZ()), - new Vector3D(min.getX(), min.getY(), max.getZ()), - new Vector3D(max.getX(), min.getY(), max.getZ()) - }; - for (Vector3D vertex : vertices) { - Vector4f transformed = new SimpleVector4f((float) vertex.getX(), (float) vertex.getY(), (float) vertex.getZ(), 1); - transform.transform(transformed); - - vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); - } - computeBoxAxes(); - computeAxis(); - } - - public void set(Vector3D min, Vector3D max, Matrix4x4 transform) { - vertices[0].copy(min); - vertices[1].copy(max); - vertices[2].copy(max.getX(), min.getY(), min.getZ()); - vertices[3].copy(max.getX(), max.getY(), min.getZ()); - vertices[4].copy(min.getX(), max.getY(), min.getZ()); - vertices[5].copy(min.getX(), max.getY(), max.getZ()); - vertices[6].copy(min.getX(), min.getY(), max.getZ()); - vertices[7].copy(max.getX(), min.getY(), max.getZ()); - Vector4f transformed = new SimpleVector4f(); - for (Vector3D vertex : vertices) { - transformed.set((float) vertex.getX(), (float) vertex.getY(), (float) vertex.getZ(), 1); - transform.transform(transformed); - vertex.copy(transformed.getX(), transformed.getY(), transformed.getZ()); - } - this.transform = transform; - computeBoxAxes(); - computeAxis(); - } - - @Override - public SatAxis[] getAxes() { - return satAxes; - } - - private void computeAxis() { - satAxes = new SatAxis[3]; - Vector3D[] axis = this.axis; - for (int i = 0; i < satAxes.length; i++) { - satAxes[i] = new SatAxis(axis[i]); - } - } - - @Override - public SatEdge[] getEdges() { - return computeEdges(); - } - - @Override - public ClipPlanes getClipPlanes() { - ClipPlane[] clipPlaneArray = new ClipPlane[SAT_CLIP_PLANES.length]; - for (int i = 0; i < SAT_CLIP_PLANES.length; i++) { - AxisAndVertexIndex satClipPlane = SAT_CLIP_PLANES[i]; - Vector4f vector4f = new SimpleVector4f((float) satClipPlane.getAxis().getX(), (float) satClipPlane.getAxis().getY(), (float) satClipPlane.getAxis().getZ(), 0); - transform.transform(vector4f); - clipPlaneArray[i] = new ClipPlane(new Vector3D(vector4f.getX(), vector4f.getY(), vector4f.getZ()).normalize(), vertices[satClipPlane.getIndex()]); - } - return new ClipPlanes(clipPlaneArray); - } - - private SatEdge[] computeEdges() { - SatEdge[] edges = new SatEdge[3]; - Vector3D[] axis = computeBoxAxes(); - for (int i = 0; i < edges.length; i++) { - edges[i] = new SatEdge(axis[i]); - } - return edges; - } - - private Vector3D[] computeBoxAxes() { - axis = new Vector3D[3]; - axis[0] = vertices[6].clone().subtract(vertices[0]).normalize(); - axis[1] = vertices[4].clone().subtract(vertices[0]).normalize(); - axis[2] = vertices[2].clone().subtract(vertices[0]).normalize(); - return axis; - } - - @Override - public Vector3D[] getVertices() { - return vertices; - } - - @Override - public Edge[] getClipEdges() { - return new Edge[] { - new Edge(vertices[0], vertices[6]), - new Edge(vertices[0], vertices[4]), - new Edge(vertices[0], vertices[2]), - - new Edge(vertices[1], vertices[7]), - new Edge(vertices[1], vertices[5]), - new Edge(vertices[1], vertices[3]), - - new Edge(vertices[6], vertices[7]), - new Edge(vertices[7], vertices[2]), - - new Edge(vertices[5], vertices[4]), - new Edge(vertices[4], vertices[3]), - - new Edge(vertices[5], vertices[6]), - new Edge(vertices[3], vertices[2]) - }; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java deleted file mode 100644 index f23e095..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/VerticesSATShape.java +++ /dev/null @@ -1,63 +0,0 @@ -package fr.radi3nt.maths.sat.shape; - -import fr.radi3nt.maths.aabb.AABB; -import fr.radi3nt.maths.aabb.AxisMapping; -import fr.radi3nt.maths.aabb.SetAABB; -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.clip.ClipPlanes; -import fr.radi3nt.maths.sat.clip.Edge; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; - -public interface VerticesSATShape extends SATShape { - - @Override - default SatProjection project(SatProjectionProvider provider, SatAxis axis) { - Vector3D[] vertices = getVertices(); - - double min = axis.dot(vertices[0]); - double max = min; - for (int i = 1; i < vertices.length; i++) { - double p = axis.dot(vertices[i]); - min = Math.min(p, min); - max = Math.max(p, max); - } - - return provider.project(min, max); - } - - Vector3D[] getVertices(); - - ClipPlanes getClipPlanes(); - Edge[] getClipEdges(); - - default AABB toAABB() { - final AABB aabb; - float maxX = -Float.MAX_VALUE; - float minX = Float.MAX_VALUE; - - float maxY = -Float.MAX_VALUE; - float minY = Float.MAX_VALUE; - - float maxZ = -Float.MAX_VALUE; - float minZ = Float.MAX_VALUE; - - for (Vector3D vertex : getVertices()) { - maxX = (float) Math.max(maxX, vertex.getX()); - minX = (float) Math.min(minX, vertex.getX()); - - maxY = (float) Math.max(maxY, vertex.getY()); - minY = (float) Math.min(minY, vertex.getY()); - - maxZ = (float) Math.max(maxZ, vertex.getZ()); - minZ = (float) Math.min(minZ, vertex.getZ()); - } - - aabb = new SetAABB( - new AxisMapping(minX, maxX), - new AxisMapping(minY, maxY), - new AxisMapping(minZ, maxZ)); - return aabb; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java deleted file mode 100644 index f004318..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/ComputingTriangleSAT.java +++ /dev/null @@ -1,103 +0,0 @@ -package fr.radi3nt.maths.sat.shape.triangles; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; -import fr.radi3nt.maths.sat.clip.ClipPlane; -import fr.radi3nt.maths.sat.clip.ClipPlanes; -import fr.radi3nt.maths.sat.clip.Edge; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; - -import java.util.function.Consumer; - -public class ComputingTriangleSAT implements TriangleSAT { - - private Vector3f vert1; - private Vector3f vert2; - private Vector3f vert3; - private Vector3f triNormal; - - public ComputingTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { - this.vert1 = vert1; - this.vert2 = vert2; - this.vert3 = vert3; - this.triNormal = triNormal; - } - - public ComputingTriangleSAT() { - } - - public void set(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { - this.vert1 = copyOrSet(this.vert1, vert1); - this.vert2 = copyOrSet(this.vert2, vert2); - this.vert3 = copyOrSet(this.vert3, vert3); - this.triNormal = copyOrSet(this.triNormal, triNormal); - } - - public void set(Vector3f vert1, Vector3f vert2, Vector3f vert3, Consumer normal) { - this.vert1 = copyOrSet(this.vert1, vert1); - this.vert2 = copyOrSet(this.vert2, vert2); - this.vert3 = copyOrSet(this.vert3, vert3); - - if (triNormal==null) - triNormal = new SimpleVector3f(); - normal.accept(triNormal); - } - - private static Vector3f copyOrSet(Vector3f vert1, Vector3f vert11) { - if (vert1!=null) - vert1.copy(vert11); - else - return vert11; - return vert1; - } - - @Override - public Vector3D[] getVertices() { - Vector3D[] vertices = new Vector3D[3]; - for (int i = 0; i < 3; i++) { - Vector3f position = i == 0 ? vert1 : i==1 ? vert2 : vert3; - vertices[i] = new Vector3D(position.getX(), position.getY(), position.getZ()); - } - return vertices; - } - - @Override - public SatAxis[] getAxes() { - Vector3D normal = new Vector3D(triNormal.getX(), triNormal.getY(), triNormal.getZ()); - SatAxis faceAxis = new SatAxis(normal); - return new SatAxis[]{faceAxis}; - } - - @Override - public SatEdge[] getEdges() { - return new SatEdge[]{ - new SatEdge(sub(vert1, vert2)), - new SatEdge(sub(vert2, vert3)), - new SatEdge(sub(vert3, vert1)), - }; - } - - @Override - public Edge[] getClipEdges() { - Vector3D[] vertices = getVertices(); - return new Edge[] { - new Edge(vertices[0], vertices[1]), - new Edge(vertices[1], vertices[2]), - new Edge(vertices[2], vertices[0]) - }; - } - - @Override - public ClipPlanes getClipPlanes() { - ClipPlane[] clipPlaneArray = new ClipPlane[] { - new ClipPlane(getAxes()[0].getNormal(), new Vector3D(vert1)) - }; - return new ClipPlanes(clipPlaneArray); - } - - private Vector3D sub(Vector3f vert1, Vector3f vert2) { - return new Vector3D(vert1.getX()-vert2.getX(), vert1.getY()-vert2.getY(), vert1.getZ()-vert2.getZ()); - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java deleted file mode 100644 index 01627b1..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/StoringTriangleSAT.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.radi3nt.maths.sat.shape.triangles; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.sat.clip.ClipPlane; -import fr.radi3nt.maths.sat.clip.ClipPlanes; -import fr.radi3nt.maths.sat.clip.Edge; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; - -public class StoringTriangleSAT implements TriangleSAT { - - private final Vector3D[] vertices = new Vector3D[3]; - private final SatAxis[] satAxes; - private final SatEdge[] edges; - - public StoringTriangleSAT(Vector3f vert1, Vector3f vert2, Vector3f vert3, Vector3f triNormal) { - for (int i = 0; i < 3; i++) { - Vector3f position = i == 0 ? vert1 : i==1 ? vert2 : vert3; - vertices[i] = new Vector3D(position.getX(), position.getY(), position.getZ()); - } - - Vector3D normal = new Vector3D(triNormal.getX(), triNormal.getY(), triNormal.getZ()); - SatAxis faceAxis = new SatAxis(normal); - - satAxes = new SatAxis[]{faceAxis}; - - Vector3D[] vertices = getVertices(); - edges = new SatEdge[]{ - new SatEdge(vertices[0].clone().subtract(vertices[1])), - new SatEdge(vertices[1].clone().subtract(vertices[2])), - new SatEdge(vertices[2].clone().subtract(vertices[0])), - }; - } - - @Override - public Vector3D[] getVertices() { - return vertices; - } - - @Override - public SatAxis[] getAxes() { - return satAxes; - } - - @Override - public SatEdge[] getEdges() { - return edges; - } - - @Override - public Edge[] getClipEdges() { - return new Edge[] { - new Edge(vertices[0], vertices[1]), - new Edge(vertices[1], vertices[2]), - new Edge(vertices[2], vertices[0]) - }; - } - - @Override - public ClipPlanes getClipPlanes() { - ClipPlane[] clipPlaneArray = new ClipPlane[] { - new ClipPlane(getAxes()[0].getNormal(), vertices[0]) - }; - return new ClipPlanes(clipPlaneArray); - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java deleted file mode 100644 index 6c96d67..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/shape/triangles/TriangleSAT.java +++ /dev/null @@ -1,8 +0,0 @@ -package fr.radi3nt.maths.sat.shape.triangles; - -import fr.radi3nt.maths.sat.shape.VerticesSATShape; - -public interface TriangleSAT extends VerticesSATShape { - - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java deleted file mode 100644 index 814b0cb..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/CheepSweptSatResolver.java +++ /dev/null @@ -1,166 +0,0 @@ -package fr.radi3nt.maths.sat.swept; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; -import fr.radi3nt.maths.sat.shape.SATShape; - -public class CheepSweptSatResolver { - - private final SatProjectionProvider provider0; - private final SatProjectionProvider provider1; - private SATShape shape1; - private SATShape shape2; - - private Vector3D velocity; - private final Vector3D cacheCross = new Vector3D(); - - public CheepSweptSatResolver(SatProjectionProvider provider) { - this.provider0 = provider; - this.provider1 = provider.duplicate(); - } - - public void set(SATShape shape1, SATShape shape2, Vector3D velocity) { - this.shape1 = shape1; - this.shape2 = shape2; - this.velocity = velocity; - } - - public SweptResult resolve() { - SatAxis[] axes1 = shape1.getAxes(); - SatAxis[] axes2 = shape2.getAxes(); - // loop over the axes1 - - SweptResult shapeOne = testOverlapOnAxes(axes1); - if (shapeOne == null) - return SweptResult.NO_CONTACT; - // loop over the axes2 - SweptResult shapeTwo = testOverlapOnAxes(axes2); - if (shapeTwo == null) - return SweptResult.NO_CONTACT; - - SweptResult edges = testOverlapOnAxes(shape1.getEdges(), shape2.getEdges()); - if (edges == null) - return SweptResult.NO_CONTACT; - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - if (tEnter < shapeOne.getTEnter()) { - enterAxis = shapeOne.getEnterAxis(); - tEnter = shapeOne.getTEnter(); - } - - tLeave = Math.min(shapeOne.getTLeave(), tLeave); - - if (tEnter < shapeTwo.getTEnter()) { - enterAxis = shapeTwo.getEnterAxis(); - tEnter = shapeTwo.getTEnter(); - } - tLeave = Math.min(shapeTwo.getTLeave(), tLeave); - - if (tEnter < edges.getTEnter()) { - enterAxis = edges.getEnterAxis(); - tEnter = edges.getTEnter(); - } - tLeave = Math.min(edges.getTLeave(), tLeave); - - if (tEnter > tLeave) { - return SweptResult.NO_CONTACT; - } - - if (enterAxis!=null) - return new SweptResult(true, tEnter, tLeave, enterAxis); - return SweptResult.NO_CONTACT; - } - - private SweptResult testOverlapOnAxes(SatEdge[] edges, SatEdge[] others) { - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - for (SatEdge edge : edges) { - for (SatEdge other : others) { - SatAxis axis = edge.axis(other, cacheCross); - - // project both shapes onto the axis - SatProjection p1 = shape1.project(provider0, axis); - SatProjection p2 = shape2.project(provider1, axis); - // do the projections overlap? - - double speed = axis.dot(velocity); - if (speed == 0) { - if (p1.noOverlap(p2)) { - return null; - } else { - if (tEnter<0) { - tEnter = 0; - tLeave = 1; - enterAxis = axis; - } - } - continue; - } - - p1.sweptOverlap(p2, speed); - if (tEnter < p1.getTEnter()) { - enterAxis = axis.useNewNormalVector(new Vector3D()); - tEnter = p1.getTEnter(); - if (tEnter > 1) - return null; - } - tLeave = Math.min(p1.getTLeave(), tLeave); - if (tLeave < 0) - return null; - } - } - - if (enterAxis!=null) - return new SweptResult(true, tEnter, tLeave, enterAxis); - return SweptResult.NO_CONTACT; - } - - private SweptResult testOverlapOnAxes(SatAxis... axes) { - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - for (SatAxis axis : axes) { - // project both shapes onto the axis - SatProjection p1 = shape1.project(provider0, axis); - SatProjection p2 = shape2.project(provider1, axis); - // do the projections overlap? - - double speed = axis.dot(velocity); - if (speed == 0) { - if (p1.noOverlap(p2)) { - return null; - } else { - if (tEnter<0) { - tEnter = 0; - tLeave = 1; - enterAxis = axis; - } - } - continue; - } - - p1.sweptOverlap(p2, speed); - if (tEnter < p1.getTEnter()) { - enterAxis = axis; - tEnter = p1.getTEnter(); - if (tEnter > 1) - return null; - } - tLeave = Math.min(p1.getTLeave(), tLeave); - if (tLeave < 0) - return null; - } - - return new SweptResult(true, tEnter, tLeave, enterAxis); - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java deleted file mode 100644 index 167ede3..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/EconomicSweptSatResolver.java +++ /dev/null @@ -1,118 +0,0 @@ -package fr.radi3nt.maths.sat.swept; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; -import fr.radi3nt.maths.sat.shape.SATShape; - -public class EconomicSweptSatResolver { - - private final SatProjectionProvider provider0; - private final SatProjectionProvider provider1; - private final SATShape shape1; - private final SATShape shape2; - - private final Vector3D velocity; - - public EconomicSweptSatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2, Vector3D velocity) { - this.provider0 = provider; - this.provider1 = provider.duplicate(); - this.shape1 = shape1; - this.shape2 = shape2; - this.velocity = velocity; - } - - public SweptResult resolve() { - SatAxis[] axes1 = shape1.getAxes(); - SatAxis[] axes2 = shape2.getAxes(); - // loop over the axes1 - - SweptResult shapeOne = testOverlapOnAxes(axes1); - if (shapeOne == null) - return SweptResult.NO_CONTACT; - // loop over the axes2 - SweptResult shapeTwo = testOverlapOnAxes(axes2); - if (shapeTwo == null) - return SweptResult.NO_CONTACT; - - SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); - SweptResult edges = testOverlapOnAxes(edgeAxis); - if (edges == null) - return SweptResult.NO_CONTACT; - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - if (tEnter < shapeOne.getTEnter()) { - enterAxis = shapeOne.getEnterAxis(); - tEnter = shapeOne.getTEnter(); - } - - tLeave = Math.min(shapeOne.getTLeave(), tLeave); - - if (tEnter < shapeTwo.getTEnter()) { - enterAxis = shapeTwo.getEnterAxis(); - tEnter = shapeTwo.getTEnter(); - } - tLeave = Math.min(shapeTwo.getTLeave(), tLeave); - - if (tEnter < edges.getTEnter()) { - enterAxis = edges.getEnterAxis(); - tEnter = edges.getTEnter(); - } - tLeave = Math.min(edges.getTLeave(), tLeave); - - if (tEnter > tLeave) { - return SweptResult.NO_CONTACT; - } - - return new SweptResult(true, tEnter, tLeave, enterAxis); - } - - private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { - int size = edges.length * others.length; - SatAxis[] axes = new SatAxis[size]; - int i = 0; - for (SatEdge edge : edges) { - for (SatEdge other : others) { - axes[i] = edge.axis(other); - i++; - } - } - return axes; - } - - private SweptResult testOverlapOnAxes(SatAxis... axes) { - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - for (SatAxis axis : axes) { - // project both shapes onto the axis - SatProjection p1 = shape1.project(provider0, axis); - SatProjection p2 = shape2.project(provider1, axis); - // do the projections overlap? - - double speed = axis.dot(velocity); - if (speed == 0) { - if (p1.noOverlap(p2)) { - return null; - } - continue; - } - - p1.sweptOverlap(p2, speed); - if (tEnter < p1.getTEnter()) { - enterAxis = axis; - tEnter = p1.getTEnter(); - } - tLeave = Math.min(p1.getTLeave(), tLeave); - } - - return new SweptResult(true, tEnter, tLeave, enterAxis); - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java deleted file mode 100644 index a128d26..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptResult.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.radi3nt.maths.sat.swept; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.components.SatAxis; - -public class SweptResult { - - public static final SweptResult NO_CONTACT = new SweptResult(false, Double.MAX_VALUE, Double.MIN_VALUE, null); - - private boolean contact; - private double tEnter; - private double tLeave; - private SatAxis enterAxis; - private Vector3D contactPoint; - - public SweptResult() { - } - - - public SweptResult(double tEnter, double tLeave, SatAxis enterAxis) { - this.contact = true; - this.tEnter = tEnter; - this.tLeave = tLeave; - this.enterAxis = enterAxis; - } - - public SweptResult(boolean contact, double tEnter, double tLeave, SatAxis enterAxis) { - this.contact = contact; - this.tEnter = tEnter; - this.tLeave = tLeave; - this.enterAxis = enterAxis; - } - - public SweptResult(boolean contact, double tEnter, double tLeave, SatAxis enterAxis, Vector3D contactPoint) { - this.contact = contact; - this.tEnter = tEnter; - this.tLeave = tLeave; - this.enterAxis = enterAxis; - this.contactPoint = contactPoint; - } - - public void set(Vector3D vertex, boolean contact, double tEnter, double tLeave, SatAxis enterAxis) { - this.contact = contact; - this.tEnter = tEnter; - this.tLeave = tLeave; - this.enterAxis = enterAxis; - this.contactPoint = vertex; - } - - public Vector3D getContactPoint() { - return contactPoint; - } - - public boolean isContact() { - return contact; - } - - public double getTEnter() { - return tEnter; - } - - public double getTLeave() { - return tLeave; - } - - public SatAxis getEnterAxis() { - return enterAxis; - } - - @Override - public String toString() { - return "SweptResult{" + - "contact=" + contact + - ", tEnter=" + tEnter + - ", tLeave=" + tLeave + - ", enterAxis=" + enterAxis + - '}'; - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java deleted file mode 100644 index 17f823b..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/swept/SweptSatResolver.java +++ /dev/null @@ -1,110 +0,0 @@ -package fr.radi3nt.maths.sat.swept; - -import fr.radi3nt.maths.components.Vector3D; -import fr.radi3nt.maths.sat.components.SatAxis; -import fr.radi3nt.maths.sat.components.SatEdge; -import fr.radi3nt.maths.sat.projection.SatProjection; -import fr.radi3nt.maths.sat.projection.SatProjectionProvider; -import fr.radi3nt.maths.sat.shape.SATShape; - -public class SweptSatResolver { - - private final SatProjectionProvider provider0; - private final SatProjectionProvider provider1; - - private final SATShape shape1; - private final SATShape shape2; - - private final Vector3D velocity; - - public SweptSatResolver(SatProjectionProvider provider, SATShape shape1, SATShape shape2, Vector3D velocity) { - this.provider0 = provider; - this.provider1 = provider.duplicate(); - this.shape1 = shape1; - this.shape2 = shape2; - this.velocity = velocity; - } - - public SweptResult resolve() { - SatAxis[] axes1 = shape1.getAxes(); - SatAxis[] axes2 = shape2.getAxes(); - - SweptResult shapeOne = testOverlapOnAxes(axes1); - SweptResult shapeTwo = testOverlapOnAxes(axes2); - - SatAxis[] edgeAxis = computeAxesFromEdges(shape1.getEdges(), shape2.getEdges()); - SweptResult edges = testOverlapOnAxes(edgeAxis); - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - if (tEnter < shapeOne.getTEnter()) { - enterAxis = shapeOne.getEnterAxis(); - tEnter = shapeOne.getTEnter(); - } - - tLeave = Math.min(shapeOne.getTLeave(), tLeave); - - if (tEnter < shapeTwo.getTEnter()) { - enterAxis = shapeTwo.getEnterAxis(); - tEnter = shapeTwo.getTEnter(); - } - tLeave = Math.min(shapeTwo.getTLeave(), tLeave); - - if (tEnter < edges.getTEnter()) { - enterAxis = edges.getEnterAxis(); - tEnter = edges.getTEnter(); - } - tLeave = Math.min(edges.getTLeave(), tLeave); - - if (tEnter > tLeave) { - return SweptResult.NO_CONTACT; - } - - return new SweptResult(true, tEnter, tLeave, enterAxis); - } - - private SatAxis[] computeAxesFromEdges(SatEdge[] edges, SatEdge[] others) { - int size = edges.length * others.length; - SatAxis[] axes = new SatAxis[size]; - int i = 0; - for (SatEdge edge : edges) { - for (SatEdge other : others) { - axes[i] = edge.axis(other); - i++; - } - } - return axes; - } - - private SweptResult testOverlapOnAxes(SatAxis... axes) { - - double tEnter = -Double.MAX_VALUE; - double tLeave = Double.MAX_VALUE; - SatAxis enterAxis = null; - - for (SatAxis axis : axes) { - SatProjection p1 = shape1.project(provider0, axis); - SatProjection p2 = shape2.project(provider1, axis); - - double speed = axis.dot(velocity); - if (speed == 0) { - if (p1.noOverlap(p2)) { - tEnter = Double.MAX_VALUE; - tLeave = -Double.MAX_VALUE; - } - continue; - } - - p1.sweptOverlap(p2, speed); - if (tEnter < p1.getTEnter()) { - enterAxis = axis; - tEnter = p1.getTEnter(); - } - tLeave = Math.min(p1.getTLeave(), tLeave); - } - - return new SweptResult(true, tEnter, tLeave, enterAxis); - } -} From 852cf8278f77f382a8c221e29a388ce9777d79ee Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 Jul 2024 23:14:54 +0200 Subject: [PATCH 064/125] Added missing methods to SmoothDynamics, Vectors and Matrices --- .../advanced/matrix/ArrayMatrix4x4.java | 22 +++++++++++++++++++ .../components/advanced/matrix/Matrix4x4.java | 2 ++ .../maths/components/vectors/Vector2f.java | 3 +++ .../implementations/SimpleVector2f.java | 16 ++++++++++++++ .../maths/dynamics/FloatSmoothDynamics.java | 4 ++++ .../maths/dynamics/VectorSmoothDynamics.java | 9 ++++++++ 6 files changed, 56 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index c470e52..53b9a00 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -352,6 +352,28 @@ public void directionRotation(Vector3f direction, Vector3f up) { m[3][3] = 1.0f; } + public void orthographic(float right, float left, float top, float bottom, float near, float far) { + m[0][0] = 2 / (right - left); + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + + m[1][0] = 0; + m[1][1] = 2 / (top - bottom); + m[1][2] = 0; + m[1][3] = 0; + + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = -2 / (far - near); + m[2][3] = 0; + + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far - near); + m[3][3] = 1; + } + @Override public void transform(Vector4f toTransform) { float x = m[0][0] * toTransform.getX() + m[1][0] * toTransform.getY() + m[2][0] * toTransform.getZ() + m[3][0] * toTransform.getW(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index ac1d1e5..4e50221 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -31,6 +31,8 @@ public interface Matrix4x4 extends Matrix { void directionRotation(Vector3f direction, Vector3f up); + void orthographic(float right, float left, float top, float bottom, float near, float far); + void transform(Vector4f toTransform); void multiply(Matrix matrix); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java index c850418..f677c4d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java @@ -25,6 +25,9 @@ public interface Vector2f extends Vector { float dot(Vector2f vector2f); Vector2f normalize(); + Vector2f normalizeSafely(); float lengthSquared(); + + void copy(Vector2f vector2f); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java index 47eafbf..7b2911f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java @@ -110,11 +110,27 @@ public Vector2f normalize() { return div(length()); } + @Override + public Vector2f normalizeSafely() { + float length = length(); + if (length==0) + mul(0); + else + div(length); + return this; + } + @Override public float lengthSquared() { return x * x + y * y; } + @Override + public void copy(Vector2f vector2f) { + this.setX(vector2f.getX()); + this.setY(vector2f.getY()); + } + @Override public float length() { return (float) Math.sqrt(lengthSquared()); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java index 8edad7f..e7e0f56 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java @@ -45,6 +45,10 @@ public float getResponse() { return response; } + public float getInputCurrent() { + return inputCurrent; + } + private boolean systemIsAtHighSpeed(DynamicsConstants constants, float step) { return constants.getW()*step >= constants.getZ(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java index 8a64728..2ce81fe 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java @@ -81,6 +81,15 @@ public void setCurrent(T currentLocalPos) { speed = 0; } + public void reset(T currentLocalPos) { + response.copy(currentLocalPos); + inputCurrent.copy(currentLocalPos); + inputPrevious.copy(currentLocalPos); + + responseDerivative = (T) currentLocalPos.duplicate().mul(0); + speed = 0; + } + public T getInputPrevious() { return inputPrevious; } From 4781704ff17e2254e8fbbb7d98c1ee2527de5db5 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 7 Jul 2024 23:16:36 +0200 Subject: [PATCH 065/125] Overhauled BufferColorUtil and renamed to ColorUtil --- .../maths/colour/util/BufferColorUtil.java | 29 ---------- .../radi3nt/maths/colour/util/ColorUtil.java | 54 +++++++++++++++++++ 2 files changed, 54 insertions(+), 29 deletions(-) delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/BufferColorUtil.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/ColorUtil.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/BufferColorUtil.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/BufferColorUtil.java deleted file mode 100644 index dded21d..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/BufferColorUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.radi3nt.maths.colour.util; - -import java.nio.ByteBuffer; - -public class BufferColorUtil { - - public static void encode(ByteBuffer buffer, int byteOffset, float red, float green, float blue, float alpha) { - byteOffset = storeRGB(buffer, byteOffset, red, green, blue); - storeColor(buffer, byteOffset, alpha); - } - - public static int storeRGB(ByteBuffer buffer, int byteOffset, float red, float green, float blue) { - storeColor(buffer, byteOffset, red); - byteOffset += Byte.BYTES; - - storeColor(buffer, byteOffset, green); - byteOffset += Byte.BYTES; - - storeColor(buffer, byteOffset, blue); - byteOffset += Byte.BYTES; - - return byteOffset; - } - - public static void storeColor(ByteBuffer buffer, int byteOffset, float color) { - buffer.put(byteOffset, (byte) (color * Byte.MAX_VALUE * 2 - Byte.MAX_VALUE)); - } - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/ColorUtil.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/ColorUtil.java new file mode 100644 index 0000000..a0b7c2b --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/util/ColorUtil.java @@ -0,0 +1,54 @@ +package fr.radi3nt.maths.colour.util; + +import fr.radi3nt.maths.colour.colors.BasicColour; +import fr.radi3nt.maths.colour.colors.Colour; + +import java.nio.ByteBuffer; + +public final class ColorUtil { + + public static Colour hex2Rgb(String colorStr) { + return new BasicColour( + Integer.valueOf( colorStr.substring( 1, 3 ), 16 ), + Integer.valueOf( colorStr.substring( 3, 5 ), 16 ), + Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) ); + } + + public static void encode(ByteBuffer buffer, float red, float green, float blue, float alpha) { + storeRGB(buffer, red, green, blue); + storeQuantizedFloat(buffer, alpha); + } + + public static void encode(ByteBuffer buffer, int byteOffset, float red, float green, float blue, float alpha) { + byteOffset = storeRGB(buffer, byteOffset, red, green, blue); + storeQuantizedFloat(buffer, byteOffset, alpha); + } + + public static int storeRGB(ByteBuffer buffer, int byteOffset, float red, float green, float blue) { + storeQuantizedFloat(buffer, byteOffset, red); + byteOffset += Byte.BYTES; + + storeQuantizedFloat(buffer, byteOffset, green); + byteOffset += Byte.BYTES; + + storeQuantizedFloat(buffer, byteOffset, blue); + byteOffset += Byte.BYTES; + + return byteOffset; + } + + public static void storeRGB(ByteBuffer buffer, float red, float green, float blue) { + storeQuantizedFloat(buffer, red); + storeQuantizedFloat(buffer, green); + storeQuantizedFloat(buffer, blue); + } + + public static void storeQuantizedFloat(ByteBuffer buffer, float color) { + buffer.put((byte) (color * Byte.MAX_VALUE * 2 - Byte.MAX_VALUE)); + } + + public static void storeQuantizedFloat(ByteBuffer buffer, int byteOffset, float color) { + buffer.put(byteOffset, (byte) (color * Byte.MAX_VALUE * 2 - Byte.MAX_VALUE)); + } + +} From 96866defa7b50355195c9bc2c6b32d7a25d3b304 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 13 Jul 2024 14:09:55 +0200 Subject: [PATCH 066/125] Removed old matrices package --- .../advanced/matrix/ArrayMatrix4x4.java | 25 +- .../components/advanced/matrix/Matrix4x4.java | 1 + .../maths/components/matrices/Matrix.java | 53 -- .../components/matrices/ProjectionMatrix.java | 8 - .../maths/components/matrices/ViewMatrix.java | 9 - .../matrices/implementation/ArrayMatrix.java | 489 ------------------ .../implementation/MatrixCreator.java | 20 - 7 files changed, 16 insertions(+), 589 deletions(-) delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java delete mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 53b9a00..2643041 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -13,16 +13,6 @@ public class ArrayMatrix4x4 implements Matrix4x4 { private final float[][] m; - public ArrayMatrix4x4(fr.radi3nt.maths.components.matrices.Matrix copy) { - m = new float[4][4]; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - set(i, j, copy.get(i, j)); - } - } - - } - public ArrayMatrix4x4() { m = new float[4][4]; } @@ -374,6 +364,21 @@ public void orthographic(float right, float left, float top, float bottom, float m[3][3] = 1; } + @Override + public void perspective(float fov, float aspect, float near, float far) { + identity(); + + float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f)))); + float frustum_length = far - near; + + set(0, 0, y_scale); + set(1, 1, y_scale*aspect); + set(2, 2, -((far + near) / frustum_length)); + set(2, 3, -1); + set(3, 2, -((2 * near * far) / frustum_length)); + set(3, 3, 0); + } + @Override public void transform(Vector4f toTransform) { float x = m[0][0] * toTransform.getX() + m[1][0] * toTransform.getY() + m[2][0] * toTransform.getZ() + m[3][0] * toTransform.getW(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index 4e50221..ef201eb 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -32,6 +32,7 @@ public interface Matrix4x4 extends Matrix { void directionRotation(Vector3f direction, Vector3f up); void orthographic(float right, float left, float top, float bottom, float near, float far); + void perspective(float fov, float aspect, float near, float far); void transform(Vector4f toTransform); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java deleted file mode 100644 index 9bd9c27..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.radi3nt.maths.components.matrices; - -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.Vector4f; - -import java.nio.FloatBuffer; - -public interface Matrix { - - Matrix identity(); - Matrix zero(); - - Matrix translation(Vector3f vector3f); - - /** - * @param value Angle in radians - */ - Matrix rotation(float value, Vector3f axis); - /** - * @param rotation Angles in radians - */ - Matrix rotation(Vector3f rotation); - Matrix scaling(Vector3f scale); - - Matrix translate(Vector3f vector3f); - /** - * @param value Angle in radians - */ - Matrix rotate(float value, Vector3f axis); - - void rotationFromDirection(Vector3f direction, Vector3f up); - - Matrix scale(Vector3f scale); - - Matrix invert(); - Matrix transpose(); - - Vector4f transform(Vector4f vector4f); - - Matrix multiply(Matrix matrix); - - Matrix mul(Matrix matrix); - - Matrix set(int x, int y, float value); - - float get(int x, int y); - - Matrix store(FloatBuffer buffer); - - Matrix duplicate(); - - void copy(Matrix transform); -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java deleted file mode 100644 index a59ba17..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ProjectionMatrix.java +++ /dev/null @@ -1,8 +0,0 @@ -package fr.radi3nt.maths.components.matrices; - -public interface ProjectionMatrix extends Matrix { - - Matrix perspective(float fov, float aspect, float near, float far); - Matrix orthographic(float right, float left, float top, float bottom, float near, float far); - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java deleted file mode 100644 index 13ec6cd..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.radi3nt.maths.components.matrices; - -import fr.radi3nt.maths.components.vectors.Vector3f; - -public interface ViewMatrix extends Matrix { - - ViewMatrix view(Vector3f position, Vector3f rotation); - -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java deleted file mode 100644 index 29f0683..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java +++ /dev/null @@ -1,489 +0,0 @@ -package fr.radi3nt.maths.components.matrices.implementation; - -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; -import fr.radi3nt.maths.components.matrices.Matrix; -import fr.radi3nt.maths.components.matrices.ProjectionMatrix; -import fr.radi3nt.maths.components.matrices.ViewMatrix; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.Vector4f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; - -import java.nio.FloatBuffer; -import java.util.Arrays; - -public class ArrayMatrix implements Matrix, ProjectionMatrix, ViewMatrix { - - private float[][] m; - - ArrayMatrix(float[][] m) { - this.m = m; - } - - ArrayMatrix() { - this(new float[4][4]); - identity(); - } - - public static Matrix from(Matrix4x4 arrayMatrix4x4) { - ArrayMatrix arrayMatrix = new ArrayMatrix(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - arrayMatrix.set(i, j, arrayMatrix4x4.get(i, j)); - } - } - return arrayMatrix; - } - - public static Matrix fromTransposing(Matrix4x4 arrayMatrix4x4) { - ArrayMatrix arrayMatrix = new ArrayMatrix(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - arrayMatrix.set(i, j, arrayMatrix4x4.get(j, i)); - } - } - return arrayMatrix; - } - - - @Override - public Matrix identity() { - m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0; - m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0; - m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0; - m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; - - return this; - } - - @Override - public Matrix zero() { - m[0][0] = 0; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0; - m[1][0] = 0; m[1][1] = 0; m[1][2] = 0; m[1][3] = 0; - m[2][0] = 0; m[2][1] = 0; m[2][2] = 0; m[2][3] = 0; - m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 0; - - return this; - } - - @Override - public Matrix translation(Vector3f translation) { - identity(); - m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = translation.getX(); - m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = translation.getY(); - m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = translation.getZ(); - m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; - - return this; - } - - public static Matrix translate(Vector3f vec, Matrix src, Matrix dest) { - if (dest == null) { - dest = new ArrayMatrix(); - } - - dest.set(3, 0, dest.get(3, 0) + src.get(0, 0) * vec.getX() + src.get(1, 0) * vec.getY() + src.get(2, 0) * vec.getZ()); - dest.set(3, 1, dest.get(3, 1) + src.get(0, 1) * vec.getX() + src.get(1, 1) * vec.getY() + src.get(2, 1) * vec.getZ()); - dest.set(3, 2, dest.get(3, 2) + src.get(0, 2) * vec.getX() + src.get(1, 2) * vec.getY() + src.get(2, 2) * vec.getZ()); - dest.set(3, 3, dest.get(3, 3) + src.get(0, 3) * vec.getX() + src.get(1, 3) * vec.getY() + src.get(2, 3) * vec.getZ()); - return dest; - } - - @Override - public Matrix rotation(float value, Vector3f axis) { - identity(); - return rotate(value, axis, this, this); - } - - public static Matrix rotate(float angle, Vector3f axis, Matrix src, Matrix dest) { - if (dest == null) { - dest = new ArrayMatrix(); - } - - float c = (float) Math.cos(angle); - float s = (float) Math.sin(angle); - float oneminusc = 1.0F - c; - float xy = axis.getX() * axis.getY(); - float yz = axis.getY() * axis.getZ(); - float xz = axis.getX() * axis.getZ(); - float xs = axis.getX() * s; - float ys = axis.getY() * s; - float zs = axis.getZ() * s; - float f00 = axis.getX() * axis.getX() * oneminusc + c; - float f01 = xy * oneminusc + zs; - float f02 = xz * oneminusc - ys; - float f10 = xy * oneminusc - zs; - float f11 = axis.getY() * axis.getY() * oneminusc + c; - float f12 = yz * oneminusc + xs; - float f20 = xz * oneminusc + ys; - float f21 = yz * oneminusc - xs; - float f22 = axis.getZ() * axis.getZ() * oneminusc + c; - float t00 = src.get(0, 0) * f00 + src.get(1, 0) * f01 + src.get(2, 0) * f02; - float t01 = src.get(0, 1) * f00 + src.get(1, 1) * f01 + src.get(2, 1) * f02; - float t02 = src.get(0, 2) * f00 + src.get(1, 2) * f01 + src.get(2, 2) * f02; - float t03 = src.get(0, 3) * f00 + src.get(1, 3) * f01 + src.get(2, 3) * f02; - float t10 = src.get(0, 0) * f10 + src.get(1, 0) * f11 + src.get(2, 0) * f12; - float t11 = src.get(0, 1) * f10 + src.get(1, 1) * f11 + src.get(2, 1) * f12; - float t12 = src.get(0, 2) * f10 + src.get(1, 2) * f11 + src.get(2, 2) * f12; - float t13 = src.get(0, 3) * f10 + src.get(1, 3) * f11 + src.get(2, 3) * f12; - dest.set(2, 0, src.get(0, 0) * f20 + src.get(1, 0) * f21 + src.get(2, 0) * f22); - dest.set(2, 1, src.get(0, 1) * f20 + src.get(1, 1) * f21 + src.get(2, 1) * f22); - dest.set(2, 2, src.get(0, 2) * f20 + src.get(1, 2) * f21 + src.get(2, 2) * f22); - dest.set(2, 3, src.get(0, 3) * f20 + src.get(1, 3) * f21 + src.get(2, 3) * f22); - dest.set(0, 0, t00); - dest.set(0, 1, t01); - dest.set(0, 2, t02); - dest.set(0, 3, t03); - dest.set(1, 0, t10); - dest.set(1, 1, t11); - dest.set(1, 2, t12); - dest.set(1, 3, t13); - return dest; - } - - @Override - public Matrix rotation(Vector3f rotation) { - float x = rotation.getX(); - float y = rotation.getY(); - float z = rotation.getZ(); - - float sinX = (float) Math.sin(x); - float sinY = (float) Math.sin(y); - float sinZ = (float) Math.sin(z); - - float cosX = (float) Math.cos(x); - float cosY = (float) Math.cos(y); - float cosZ = (float) Math.cos(z); - - final float sinXsinY = sinX * sinY; - final float cosXsinY = cosX * sinY; - - m[0][0] = cosY * cosZ; - m[0][1] = cosY * sinZ; - m[0][2] = -sinY; - m[0][3] = 0f; - - m[1][0] = sinXsinY * cosZ - cosX * sinZ; - m[1][1] = sinXsinY * sinZ + cosX * cosZ; - m[1][2] = sinX * cosY; - m[1][3] = 0f; - - m[2][0] = cosXsinY * cosZ + sinX * sinZ; - m[2][1] = cosXsinY * sinZ - sinX * cosZ; - m[2][2] = cosX * cosY; - m[2][3] = 0f; - - m[3][0] = 0f; - m[3][1] = 0f; - m[3][2] = 0f; - m[3][3] = 1f; - - return this; - } - - @Override - public Matrix scaling(Vector3f scale) { - identity(); - return scale(scale, this, this); - } - - public static Matrix scale(Vector3f vec, Matrix src, Matrix dest) { - if (dest == null) { - dest = new ArrayMatrix(); - } - - dest.set(0, 0, src.get(0, 0)*vec.getX()); - dest.set(0, 1, src.get(0, 1)*vec.getX()); - dest.set(0, 2, src.get(0, 2)*vec.getX()); - dest.set(0, 3, src.get(0, 3)*vec.getX()); - - dest.set(1, 0, src.get(1, 0)*vec.getY()); - dest.set(1, 1, src.get(1, 1)*vec.getY()); - dest.set(1, 2, src.get(1, 2)*vec.getY()); - dest.set(1, 3, src.get(1, 3)*vec.getY()); - - dest.set(2, 0, src.get(2, 0)*vec.getZ()); - dest.set(2, 1, src.get(2, 1)*vec.getZ()); - dest.set(2, 2, src.get(2, 2)*vec.getZ()); - dest.set(2, 3, src.get(2, 3)*vec.getZ()); - - return dest; - } - - @Override - public Matrix translate(Vector3f vector3f) { - return translate(vector3f, this, this); - } - - @Override - public Matrix rotate(float value, Vector3f axis) { - return rotate(value, axis, this, this); - } - - @Override - public void rotationFromDirection(Vector3f direction, Vector3f up) { - Vector3f xaxis = up.duplicate().cross(direction); - xaxis.normalize(); - - Vector3f yaxis = direction.duplicate().cross(xaxis); - yaxis.normalize(); - - m[0][0] = xaxis.getX(); - m[0][1] = yaxis.getX(); - m[0][2] = direction.getX(); - - m[1][0] = xaxis.getY(); - m[1][1] = yaxis.getY(); - m[1][2] = direction.getY(); - - m[2][0] = xaxis.getZ(); - m[2][1] = yaxis.getZ(); - m[2][2] = direction.getZ(); - } - - @Override - public Matrix scale(Vector3f scale) { - return scale(scale, this, this); - } - - @Override - public Vector4f transform(Vector4f vector4f) { - float x = this.m[0][0] * vector4f.getX() + this.m[1][0] * vector4f.getY() + this.m[2][0] * vector4f.getZ() + this.m[3][0] * vector4f.getW(); - float y = this.m[0][1] * vector4f.getX() + this.m[1][1] * vector4f.getY() + this.m[2][1] * vector4f.getZ() + this.m[3][1] * vector4f.getW(); - float z = this.m[0][2] * vector4f.getX() + this.m[1][2] * vector4f.getY() + this.m[2][2] * vector4f.getZ() + this.m[3][2] * vector4f.getW(); - float w = this.m[0][3] * vector4f.getX() + this.m[1][3] * vector4f.getY() + this.m[2][3] * vector4f.getZ() + this.m[3][3] * vector4f.getW(); - return new SimpleVector4f(x, y, z, w); - } - - @Override - public Matrix invert() { - float s0 = get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1); - float s1 = get(0, 0) * get(1, 2) - get(1, 0) * get(0, 2); - float s2 = get(0, 0) * get(1, 3) - get(1, 0) * get(0, 3); - float s3 = get(0, 1) * get(1, 2) - get(1, 1) * get(0, 2); - float s4 = get(0, 1) * get(1, 3) - get(1, 1) * get(0, 3); - float s5 = get(0, 2) * get(1, 3) - get(1, 2) * get(0, 3); - - float c5 = get(2, 2) * get(3, 3) - get(3, 2) * get(2, 3); - float c4 = get(2, 1) * get(3, 3) - get(3, 1) * get(2, 3); - float c3 = get(2, 1) * get(3, 2) - get(3, 1) * get(2, 2); - float c2 = get(2, 0) * get(3, 3) - get(3, 0) * get(2, 3); - float c1 = get(2, 0) * get(3, 2) - get(3, 0) * get(2, 2); - float c0 = get(2, 0) * get(3, 1) - get(3, 0) * get(2, 1); - - - float div = (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); - if (div == 0) System.err.println("not invertible"); - - float invdet = 1.0f / div; - - ArrayMatrix invM = new ArrayMatrix(); - - invM.set(0, 0, (get(1, 1) * c5 - get(1, 2) * c4 + get(1, 3) * c3) * invdet); - invM.set(0, 1, (-get(0, 1) * c5 + get(0, 2) * c4 - get(0, 3) * c3) * invdet); - invM.set(0, 2, (get(3, 1) * s5 - get(3, 2) * s4 + get(3, 3) * s3) * invdet); - invM.set(0, 3, (-get(2, 1) * s5 + get(2, 2) * s4 - get(2, 3) * s3) * invdet); - - invM.set(1, 0, (-get(1, 0) * c5 + get(1, 2) * c2 - get(1, 3) * c1) * invdet); - invM.set(1, 1, (get(0, 0) * c5 - get(0, 2) * c2 + get(0, 3) * c1) * invdet); - invM.set(1, 2, (-get(3, 0) * s5 + get(3, 2) * s2 - get(3, 3) * s1) * invdet); - invM.set(1, 3, (get(2, 0) * s5 - get(2, 2) * s2 + get(2, 3) * s1) * invdet); - - invM.set(2, 0, (get(1, 0) * c4 - get(1, 1) * c2 + get(1, 3) * c0) * invdet); - invM.set(2, 1, (-get(0, 0) * c4 + get(0, 1) * c2 - get(0, 3) * c0) * invdet); - invM.set(2, 2, (get(3, 0) * s4 - get(3, 1) * s2 + get(3, 3) * s0) * invdet); - invM.set(2, 3, (-get(2, 0) * s4 + get(2, 1) * s2 - get(2, 3) * s0) * invdet); - - invM.set(3, 0, (-get(1, 0) * c3 + get(1, 1) * c1 - get(1, 2) * c0) * invdet); - invM.set(3, 1, (get(0, 0) * c3 - get(0, 1) * c1 + get(0, 2) * c0) * invdet); - invM.set(3, 2, (-get(3, 0) * s3 + get(3, 1) * s1 - get(3, 2) * s0) * invdet); - invM.set(3, 3, (get(2, 0) * s3 - get(2, 1) * s1 + get(2, 2) * s0) * invdet); - - this.m = invM.getM(); - - return this; - } - - @Override - public Matrix transpose() { - ArrayMatrix result = new ArrayMatrix(); - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - result.set(i, j, get(j, i)); - } - } - - this.m = result.getM(); - - return result; - } - - @Override - public Matrix multiply(Matrix matrix) { - ArrayMatrix res = new ArrayMatrix(); - - multiply(matrix, res); - - m = res.getM(); - - return this; - } - - @Override - public Matrix mul(Matrix matrix) { - Matrix res = new ArrayMatrix(); - - multiply(matrix, res); - - return res; - } - - private void multiply(Matrix matrix, Matrix res) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - res.set(i, j, this.get(i, 0) * matrix.get(0, j) + - this.get(i, 1) * matrix.get(1, j) + - this.get(i, 2) * matrix.get(2, j) + - this.get(i, 3) * matrix.get(3, j)); - } - } - } - - @Override - public Matrix perspective(float fov, float aspect, float near, float far) { - identity(); - - float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f)))); - float frustum_length = far - near; - - set(0, 0, y_scale); - set(1, 1, y_scale*aspect); - set(2, 2, -((far + near) / frustum_length)); - set(2, 3, -1); - set(3, 2, -((2 * near * far) / frustum_length)); - set(3, 3, 0); - - return this; - } - - public Matrix orthographic(float right, float left, float top, float bottom, float near, float far) { - identity(); - - m[0][0] = 2 / (right - left); - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - - m[1][0] = 0; - m[1][1] = 2 / (top - bottom); - m[1][2] = 0; - m[1][3] = 0; - - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = -2 / (far - near); - m[2][3] = 0; - - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -(far + near) / (far - near); - m[3][3] = 1; - - return this; - } - - @Override - public ViewMatrix view(Vector3f position, Vector3f rotation) { //todo rotation no need to negate ? - - Matrix rotX = MatrixCreator.createMatrix().rotation(-rotation.getX(), new SimpleVector3f(1, 0, 0)); - Matrix rotY = MatrixCreator.createMatrix().rotation(-rotation.getY(), new SimpleVector3f(0, 1, 0)); - Matrix rotZ = MatrixCreator.createMatrix().rotation(-rotation.getZ(), new SimpleVector3f(0, 0, 1)); - - Matrix translate = MatrixCreator.createMatrix().translation(new SimpleVector3f(-position.getX(), -position.getY(), -position.getZ())); - - identity(); - this.multiply(rotX.mul(rotY).mul(rotZ).mul(translate)); - - return this; - } - - @Override - public Matrix store(FloatBuffer buffer) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - buffer.put(m[i][j]); - } - } - return this; - } - - @Override - public Matrix set(int x, int y, float value) { - m[x][y]=value; - return this; - } - - @Override - public float get(int x, int y) { - return m[x][y]; - } - - public float[][] getM() { - return m; - } - - public void setM(float[][] m) { - this.m = m; - } - - @Override - public ViewMatrix duplicate() { - float[][] m2 = new float[4][4]; - - for (int x = 0; x < m.length; x++) { - System.arraycopy(m[x], 0, m2[x], 0, m[x].length); - } - - return new ArrayMatrix(m2); - } - - @Override - public void copy(Matrix transform) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - set(i, j, transform.get(i, j)); - } - } - } - - @Override - public String toString() { - StringBuilder stringBuilder = new StringBuilder("ArrayMatrix{" + - "\n"); - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - stringBuilder.append(m[i][j]).append(" "); - } - stringBuilder.append("\n"); - } - - stringBuilder.append("}"); - - return stringBuilder.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ArrayMatrix that = (ArrayMatrix) o; - return Arrays.deepEquals(m, that.m); - } - - @Override - public int hashCode() { - return Arrays.deepHashCode(m); - } -} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java deleted file mode 100644 index 1f057fb..0000000 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.radi3nt.maths.components.matrices.implementation; - -import fr.radi3nt.maths.components.matrices.Matrix; -import fr.radi3nt.maths.components.matrices.ProjectionMatrix; -import fr.radi3nt.maths.components.matrices.ViewMatrix; - -public class MatrixCreator { - - public static Matrix createMatrix() { - return new ArrayMatrix(); - } - - public static ProjectionMatrix createProjection() { - return new ArrayMatrix(); - } - - public static ViewMatrix createView() { - return new ArrayMatrix(); - } -} From b2897fe0db2a1ffbd341e92a94897eaff68934e3 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 13 Jul 2024 14:10:12 +0200 Subject: [PATCH 067/125] Added duplicate() to Vector4f --- .../main/java/fr/radi3nt/maths/components/vectors/Vector4f.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index d95dc5b..d4fed9f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -21,4 +21,6 @@ public interface Vector4f extends Vector, OperatingVectorNf { void set(Vector3f vector3f, int w); void set(float x, float y, float z, int w); + Vector4f duplicate(); + } From 966490cec6346058a644e876391ec7853601421f Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sat, 13 Jul 2024 14:10:29 +0200 Subject: [PATCH 068/125] Added Vector2D constructor --- .../components/vectors/implementations/SimpleVector2f.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java index 7b2911f..a022c55 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java @@ -1,5 +1,6 @@ package fr.radi3nt.maths.components.vectors.implementations; +import fr.radi3nt.maths.components.Vector2D; import fr.radi3nt.maths.components.vectors.Vector2f; import java.util.Objects; @@ -17,6 +18,11 @@ public SimpleVector2f(float x, float y) { public SimpleVector2f() { } + public SimpleVector2f(Vector2D vector) { + this.x = (float) vector.getX(); + this.y = (float) vector.getY(); + } + @Override public float getX() { return x; From ee935b159632d6eb3be3f6fde4fd8798db3ef4b5 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 4 Aug 2024 17:59:52 +0200 Subject: [PATCH 069/125] Fixed an issue with inverting ArrayMatrix3x3 --- .../advanced/matrix/ArrayMatrix3x3.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java index 8fb5f57..dde9822 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -97,15 +97,15 @@ public void invert() { ArrayMatrix3x3 invM = new ArrayMatrix3x3(); - set(0, 0, (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)) * invdet); - set(0, 1, (get(0, 2) * get(2, 1) - get(0, 1) * get(2, 2)) * invdet); - set(0, 2, (get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1)) * invdet); - set(1, 0, (get(1, 2) * get(2, 0) - get(1, 0) * get(2, 2)) * invdet); - set(1, 1, (get(0, 0) * get(2, 2) - get(0, 2) * get(2, 0)) * invdet); - set(1, 2, (get(1, 0) * get(0, 2) - get(0, 0) * get(1, 2)) * invdet); - set(2, 0, (get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1)) * invdet); - set(2, 1, (get(2, 0) * get(0, 1) - get(0, 0) * get(2, 1)) * invdet); - set(2, 2, (get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1)) * invdet); + invM.set(0, 0, (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)) * invdet); + invM.set(0, 1, (get(0, 2) * get(2, 1) - get(0, 1) * get(2, 2)) * invdet); + invM.set(0, 2, (get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1)) * invdet); + invM.set(1, 0, (get(1, 2) * get(2, 0) - get(1, 0) * get(2, 2)) * invdet); + invM.set(1, 1, (get(0, 0) * get(2, 2) - get(0, 2) * get(2, 0)) * invdet); + invM.set(1, 2, (get(1, 0) * get(0, 2) - get(0, 0) * get(1, 2)) * invdet); + invM.set(2, 0, (get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1)) * invdet); + invM.set(2, 1, (get(2, 0) * get(0, 1) - get(0, 0) * get(2, 1)) * invdet); + invM.set(2, 2, (get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1)) * invdet); this.copy(invM); } From e7eb1104e906683dd62436b9a17213eca56a0bf1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 4 Aug 2024 18:12:51 +0200 Subject: [PATCH 070/125] Made Vector2f implement OperatingVectorNf --- .../maths/components/vectors/Vector2f.java | 5 ++- .../implementations/SimpleVector2f.java | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java index f677c4d..74524aa 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java @@ -1,6 +1,8 @@ package fr.radi3nt.maths.components.vectors; -public interface Vector2f extends Vector { +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; + +public interface Vector2f extends Vector, OperatingVectorNf { float getX(); void setX(float x); @@ -22,6 +24,7 @@ public interface Vector2f extends Vector { Vector2f div(float mul); Vector2f clone(); + Vector2f duplicate(); float dot(Vector2f vector2f); Vector2f normalize(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java index a022c55..e8b12f5 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java @@ -1,6 +1,7 @@ package fr.radi3nt.maths.components.vectors.implementations; import fr.radi3nt.maths.components.Vector2D; +import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; import fr.radi3nt.maths.components.vectors.Vector2f; import java.util.Objects; @@ -23,6 +24,10 @@ public SimpleVector2f(Vector2D vector) { this.y = (float) vector.getY(); } + public SimpleVector2f(Vector2f vector) { + this.copy(vector); + } + @Override public float getX() { return x; @@ -84,6 +89,21 @@ public Vector2f mul(float mul) { return mul(mul, mul); } + @Override + public OperatingVectorNf add(OperatingVectorNf other) { + return add(other.get(0), other.get(1)); + } + + @Override + public OperatingVectorNf sub(OperatingVectorNf other) { + return sub(other.get(0), other.get(1)); + } + + @Override + public int size() { + return 2; + } + @Override public Vector2f div(Vector2f vector2f) { return div(vector2f.getX(), vector2f.getY()); @@ -96,6 +116,18 @@ public Vector2f div(float x, float y) { return this; } + @Override + public float get(int row) { + if (row>1 || row<0) + throw new UnsupportedOperationException(); + return row == 0 ? x : y; + } + + @Override + public Vector2f duplicate() { + return clone(); + } + @Override public Vector2f div(float mul) { return div(mul, mul); @@ -142,6 +174,11 @@ public float length() { return (float) Math.sqrt(lengthSquared()); } + @Override + public void copy(OperatingVectorNf other) { + this.copy(new SimpleVector2f(other.get(0), other.get(1))); + } + @Override public boolean equals(Object o) { if (this == o) return true; From 578df002e969072d5d628cb57f19b0b219e5772e Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 4 Aug 2024 18:58:03 +0200 Subject: [PATCH 071/125] Added CubicBezierSplineBuilder3D --- .../builder/bezier/dim3/BezierPoint3D.java | 32 +++++++++++++ .../dim3/CubicBezierSplineBuilder3D.java | 45 +++++++++++++++++++ .../dim3/CubicBezierSplineController3D.java | 19 ++++++++ 3 files changed, 96 insertions(+) create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java new file mode 100644 index 0000000..469b77a --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java @@ -0,0 +1,32 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim3; + +import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint; + +public class BezierPoint3D { + + private final BezierPoint xAxis; + private final BezierPoint yAxis; + private final BezierPoint zAxis; + + public BezierPoint3D(BezierPoint xAxis, BezierPoint yAxis, BezierPoint zAxis) { + this.xAxis = xAxis; + this.yAxis = yAxis; + this.zAxis = zAxis; + } + + public BezierPoint3D(float pointX, float pointControlBeforeX, float pointControlAfterX, float pointY, float pointControlBeforeY, float pointControlAfterY, float pointZ, float pointControlBeforeZ, float pointControlAfterZ) { + this(new BezierPoint(pointX, pointControlBeforeX, pointControlAfterX), new BezierPoint(pointY, pointControlBeforeY, pointControlAfterY), new BezierPoint(pointZ, pointControlBeforeZ, pointControlAfterZ)); + } + + public BezierPoint getXAxis() { + return xAxis; + } + + public BezierPoint getYAxis() { + return yAxis; + } + + public BezierPoint getZAxis() { + return zAxis; + } +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java new file mode 100644 index 0000000..b8feaf9 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java @@ -0,0 +1,45 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim3; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint; +import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineBuilder; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D; +import fr.radi3nt.spline.splines.dimensions.Spline3D; + +public class CubicBezierSplineBuilder3D { + + private final CubicBezierSplineBuilder[] splineBuilders = new CubicBezierSplineBuilder[3]; + + public static CubicBezierSplineBuilder3D fromTwoPoints(Vector3f pointA, Vector3f dirA, Vector3f pointB, Vector3f dirB) { + return new CubicBezierSplineBuilder3D( + new BezierPoint3D(pointA.getX(), 0, pointA.getX()+dirA.getX(), pointA.getY(), 0, pointA.getY()+dirA.getY(), pointA.getZ(), 0, pointA.getZ()+dirA.getZ()), + new BezierPoint3D(pointB.getX(), pointB.getX()+dirB.getX(), 0, pointB.getY(), pointB.getY()+dirB.getY(), 0, pointB.getZ(), pointB.getZ()+dirB.getZ(), 0) + ); + } + + public CubicBezierSplineBuilder3D(BezierPoint3D... positions) { + BezierPoint[] xPos = new BezierPoint[positions.length]; + BezierPoint[] yPos = new BezierPoint[positions.length]; + BezierPoint[] zPos = new BezierPoint[positions.length]; + + for (int i = 0; i < positions.length; i++) { + BezierPoint3D position = positions[i]; + xPos[i] = position.getXAxis(); + yPos[i] = position.getYAxis(); + zPos[i] = position.getZAxis(); + } + + splineBuilders[0] = new CubicBezierSplineBuilder(xPos); + splineBuilders[1] = new CubicBezierSplineBuilder(yPos); + splineBuilders[2] = new CubicBezierSplineBuilder(zPos); + } + + public Spline3D build() { + return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build()); + } + + public CubicBezierSplineController3D controller() { + return new CubicBezierSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller()); + } + +} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java new file mode 100644 index 0000000..cb72a86 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java @@ -0,0 +1,19 @@ +package fr.radi3nt.spline.splines.builder.bezier.dim3; + +import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineController; + +public class CubicBezierSplineController3D { + + private final CubicBezierSplineController[] controllers; + + public CubicBezierSplineController3D(CubicBezierSplineController... controllers) { + this.controllers = controllers; + } + + + public void setPosition(BezierPoint3D point, int index) { + controllers[0].setPoint(point.getXAxis(), index); + controllers[1].setPoint(point.getYAxis(), index); + controllers[2].setPoint(point.getZAxis(), index); + } +} From 762b7fb506a4fb86913cf26f13216a0981822f40 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 16 Aug 2024 16:53:47 +0200 Subject: [PATCH 072/125] Fixed Quaternion.fromEulerAngles() --- .../quaternions/ComponentsQuaternion.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 6b25cf4..bd7e57a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -80,21 +80,14 @@ public static Quaternion fromAxisAndAngle(Vector3f axis, Angle angle) { } public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angleZ) { - float sinPitch = (float) Math.sin(angleX.getRadiant() * 0.5F); - float cosPitch = (float) Math.cos(angleX.getRadiant() * 0.5F); - float sinYaw = (float) Math.sin(angleY.getRadiant() * 0.5F); - float cosYaw = (float) Math.cos(angleY.getRadiant() * 0.5F); - float sinRoll = (float) Math.sin(angleZ.getRadiant() * 0.5F); - float cosRoll = (float) Math.cos(angleZ.getRadiant() * 0.5F); - float cosPitchCosYaw = (cosPitch * cosYaw); - float sinPitchSinYaw = (sinPitch * sinYaw); - - float x = sinRoll * cosPitchCosYaw - cosRoll * sinPitchSinYaw; - float y = cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw; - float z = cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw; - float w = cosRoll * cosPitchCosYaw + sinRoll * sinPitchSinYaw; + Quaternion rotationX = ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(1, 0, 0), angleX); + Quaternion rotationY = ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), angleY); + Quaternion rotationZ = ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 0, 1), angleZ); - return new ComponentsQuaternion(x, y, z, w); + rotationX.multiply(rotationY); + rotationX.multiply(rotationZ); + + return rotationX; } public static Quaternion zero() { From efaa18fb8aefa036f7fa4a832a2f29f13c34ac9a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 16 Aug 2024 16:54:23 +0200 Subject: [PATCH 073/125] Fixed w component of Vector4f being an int --- .../java/fr/radi3nt/maths/components/vectors/Vector4f.java | 4 ++-- .../components/vectors/implementations/SimpleVector4f.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index d4fed9f..119e657 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -18,8 +18,8 @@ public interface Vector4f extends Vector, OperatingVectorNf { void normalize(); - void set(Vector3f vector3f, int w); - void set(float x, float y, float z, int w); + void set(Vector3f vector3f, float w); + void set(float x, float y, float z, float w); Vector4f duplicate(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 941f802..c180fb6 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -86,7 +86,7 @@ public void normalize() { } @Override - public void set(Vector3f vector3f, int w) { + public void set(Vector3f vector3f, float w) { setX(vector3f.getX()); setY(vector3f.getY()); setZ(vector3f.getZ()); @@ -94,7 +94,7 @@ public void set(Vector3f vector3f, int w) { } @Override - public void set(float x, float y, float z, int w) { + public void set(float x, float y, float z, float w) { setX(x); setY(y); setZ(z); From 908bc143cd6d812673a09ca799c3ae166d1b51c5 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Fri, 16 Aug 2024 16:54:49 +0200 Subject: [PATCH 074/125] Added useful methods in SplineHelper --- .../spline/splines/CollectionSpline.java | 14 +++++++++-- .../fr/radi3nt/spline/splines/Spline.java | 1 + .../dimensions/EncapsulatingSpline2D.java | 25 +++++++++++++++++++ .../spline/splines/dimensions/Spline2D.java | 7 ++++++ .../cardinal/CardinalUsingHermitSpline.java | 5 ++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java index 5d14546..56321eb 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java @@ -16,18 +16,28 @@ public CollectionSpline(List curves) { @Override public float interpolate(float t) { - int index = (int) Math.nextDown(t); + int index = (int) Math.floor(t); + if (t==curves.size()) + index = curves.size()-1; Curve curve = getCurveAtIndex(index); return curve.interpolate(t-index); } @Override public float velocity(float t) { - int index = (int) Math.nextDown(t); + int index = (int) Math.floor(t); + if (t==curves.size()) + index = curves.size()-1; + Curve curve = getCurveAtIndex(index); return curve.velocity(t-index); } + @Override + public int getSegmentCount() { + return curves.size(); + } + protected Curve getCurveAtIndex(int index) { checkForValidIndex(index); return curves.get(index); diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java index 2bf2d7b..4686aa0 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java @@ -5,4 +5,5 @@ public interface Spline { float interpolate(float t); float velocity(float t); + int getSegmentCount(); } diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java index 3b8f140..a49e34e 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java @@ -15,11 +15,31 @@ public EncapsulatingSpline2D(Spline... splines) { } + @Override + public float interpolateX(float t) { + return splines[0].interpolate(t); + } + + @Override + public float interpolateY(float t) { + return splines[1].interpolate(t); + } + @Override public Vector2f interpolate(float t) { return new SimpleVector2f(interpolateIndex(0, t), interpolateIndex(1, t)); } + @Override + public float velocityX(float t) { + return splines[0].velocity(t); + } + + @Override + public float velocityY(float t) { + return splines[1].velocity(t); + } + private float interpolateIndex(int index, float t) { return splines[index].interpolate(t); } @@ -29,6 +49,11 @@ public Vector2f velocity(float t) { return new SimpleVector2f(velocityIndex(0, t), velocityIndex(1, t)); } + @Override + public int getSegmentCount() { + return splines[0].getSegmentCount(); + } + private float velocityIndex(int index, float t) { return splines[index].velocity(t); } diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java index 4d041c2..e16a0dd 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java @@ -4,7 +4,14 @@ public interface Spline2D { + float interpolateX(float t); + float interpolateY(float t); + Vector2f interpolate(float t); + float velocityX(float t); + float velocityY(float t); Vector2f velocity(float t); + int getSegmentCount(); + } diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java index a17ba10..66938a7 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java @@ -40,4 +40,9 @@ public float interpolate(float t) { public float velocity(float t) { return hermiteSpline.velocity(t); } + + @Override + public int getSegmentCount() { + return hermiteSpline.getSegmentCount(); + } } From 0c20866405c44df2b3591b7039a99ab524c26aba Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 22:48:03 +0200 Subject: [PATCH 075/125] Removed redundant .toFile().toPath() --- FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java b/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java index 72a8228..93ed6fb 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/impl/NioFile.java @@ -33,12 +33,12 @@ public boolean isCreated() { @Override public InputStream getInputStream() throws IOException { - return Files.newInputStream(path.toFile().toPath()); + return Files.newInputStream(path); } @Override public OutputStream getOutputSteam() throws IOException { - return Files.newOutputStream(path.toFile().toPath()); + return Files.newOutputStream(path); } @Override From 037de2732efd5a395342d753158a5be2166836f3 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 22:48:23 +0200 Subject: [PATCH 076/125] Generalised Installer.java --- .../fr/radi3nt/file/util/CopyFileVisitor.java | 35 ++++++++++++ .../java/fr/radi3nt/file/util/Installer.java | 55 ------------------- .../file/util/RecursiveResourceVisitor.java | 35 ++++++++++++ 3 files changed, 70 insertions(+), 55 deletions(-) create mode 100644 FileHelper/src/main/java/fr/radi3nt/file/util/CopyFileVisitor.java delete mode 100644 FileHelper/src/main/java/fr/radi3nt/file/util/Installer.java create mode 100644 FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java diff --git a/FileHelper/src/main/java/fr/radi3nt/file/util/CopyFileVisitor.java b/FileHelper/src/main/java/fr/radi3nt/file/util/CopyFileVisitor.java new file mode 100644 index 0000000..1b4a08c --- /dev/null +++ b/FileHelper/src/main/java/fr/radi3nt/file/util/CopyFileVisitor.java @@ -0,0 +1,35 @@ +package fr.radi3nt.file.util; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; + +public class CopyFileVisitor extends SimpleFileVisitor { + + private final Path target; + private final Path source; + + public CopyFileVisitor(Path target, Path source) { + this.target = target; + this.source = source; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + Path dst = resolve(dir); + Files.createDirectories(dst); + return super.preVisitDirectory(dir, attrs); + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path dst = resolve(file); + Files.copy(Files.newInputStream(file), dst, StandardCopyOption.REPLACE_EXISTING); + return super.visitFile(file, attrs); + } + + private Path resolve(Path path) { + return target.resolve(source.relativize(path).toString()); + } + +} diff --git a/FileHelper/src/main/java/fr/radi3nt/file/util/Installer.java b/FileHelper/src/main/java/fr/radi3nt/file/util/Installer.java deleted file mode 100644 index 2684a39..0000000 --- a/FileHelper/src/main/java/fr/radi3nt/file/util/Installer.java +++ /dev/null @@ -1,55 +0,0 @@ -package fr.radi3nt.file.util; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; - -public class Installer extends SimpleFileVisitor { - - public static void installResources(Path dst, Class cls, String root) throws URISyntaxException, IOException { - URL location = cls.getProtectionDomain().getCodeSource().getLocation(); - if (location.getProtocol().equals("file")) { - Path path = Paths.get(location.toURI()); - if (location.getPath().endsWith(".jar")) { - try (FileSystem fs = FileSystems.newFileSystem(path, null)) { - installResources(dst, fs.getPath("/" + root)); - } - } else { - installResources(dst, path.resolve(root)); - } - } else { - throw new IllegalArgumentException("Not supported: " + location); - } - } - - private static void installResources(Path dst, Path src) throws IOException { - Files.walkFileTree(src, new Installer(dst, src)); - } - - private final Path target, source; - - private Installer(Path dst, Path src) { - target = dst; - source = src; - } - - private Path resolve(Path path) { - return target.resolve(source.relativize(path).toString()); - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path dst = resolve(dir); - Files.createDirectories(dst); - return super.preVisitDirectory(dir, attrs); - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Path dst = resolve(file); - Files.copy(Files.newInputStream(file), dst, StandardCopyOption.REPLACE_EXISTING); - return super.visitFile(file, attrs); - } -} \ No newline at end of file diff --git a/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java b/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java new file mode 100644 index 0000000..46ae6f5 --- /dev/null +++ b/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java @@ -0,0 +1,35 @@ +package fr.radi3nt.file.util; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.*; + +public final class RecursiveResourceVisitor { + + public static void consume(VisitorSupplier consumer, Class cls, String root) throws URISyntaxException, IOException { + URL location = cls.getProtectionDomain().getCodeSource().getLocation(); + if (location.getProtocol().equals("file")) { + Path path = Paths.get(location.toURI()); + if (location.getPath().endsWith(".jar")) { + try (FileSystem fs = FileSystems.newFileSystem(path, null)) { + walkTree(consumer, fs.getPath("/" + root)); + } + } else { + walkTree(consumer, path.resolve(root)); + } + } else { + throw new IllegalArgumentException("Not supported: " + location); + } + } + + private static void walkTree(VisitorSupplier visitor, Path src) throws IOException { + Files.walkFileTree(src, visitor.get(src)); + } + + public interface VisitorSupplier { + + FileVisitor get(Path src); + + } +} \ No newline at end of file From 43456da5059f2b5b92c9c3127203038a6fa1da59 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 22:51:33 +0200 Subject: [PATCH 077/125] Made variable in WriterConfig final --- .../java/fr/radi3nt/json/WriterConfig.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/JsonHelper/src/main/java/fr/radi3nt/json/WriterConfig.java b/JsonHelper/src/main/java/fr/radi3nt/json/WriterConfig.java index 2f25478..0866f8a 100644 --- a/JsonHelper/src/main/java/fr/radi3nt/json/WriterConfig.java +++ b/JsonHelper/src/main/java/fr/radi3nt/json/WriterConfig.java @@ -3,18 +3,14 @@ import java.io.Writer; public abstract class WriterConfig { - public static WriterConfig MINIMAL; - public static WriterConfig PRETTY_PRINT; - static { - WriterConfig.MINIMAL = new WriterConfig() { - @Override - JsonWriter createWriter(final Writer writer) { - return new JsonWriter(writer); - } - }; - WriterConfig.PRETTY_PRINT = PrettyPrint.indentWithSpaces(2); - } + public static final WriterConfig MINIMAL = new WriterConfig() { + @Override + JsonWriter createWriter(final Writer writer) { + return new JsonWriter(writer); + } + }; + public static final WriterConfig PRETTY_PRINT = PrettyPrint.indentWithSpaces(2); abstract JsonWriter createWriter(final Writer p0); } From eaf8d0bef0585de5e11d2528a72ca5f27eba5d00 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:03:21 +0200 Subject: [PATCH 078/125] Fixed Quaternion.fromEulerAngles() --- .../advanced/quaternions/ComponentsQuaternion.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index bd7e57a..8c76516 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -84,10 +84,10 @@ public static Quaternion fromEulerAngles(Angle angleX, Angle angleY, Angle angle Quaternion rotationY = ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), angleY); Quaternion rotationZ = ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 0, 1), angleZ); - rotationX.multiply(rotationY); - rotationX.multiply(rotationZ); + rotationZ.multiply(rotationY); + rotationZ.multiply(rotationX); - return rotationX; + return rotationZ; } public static Quaternion zero() { From 917892ea6200ea5ae0ab13f6d54f4591ce8864eb Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:03:40 +0200 Subject: [PATCH 079/125] Added getRotationComponentAboutAxis() --- .../quaternions/ComponentsQuaternion.java | 18 ++++++++++++++++++ .../advanced/quaternions/Quaternion.java | 3 +++ 2 files changed, 21 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 8c76516..da253c1 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -98,6 +98,24 @@ public static Quaternion fromVec4(Vector4f response) { return new ComponentsQuaternion(response.getX(), response.getY(), response.getZ(), response.getW()); } + @Override + public Quaternion getRotationComponentAboutAxis( + Vector3f direction) { + Vector3f rotationAxis = new SimpleVector3f(this.x, this.y, this.z); + float dotProd = direction.dot(rotationAxis); + // Shortcut calculation of `projection` requires `direction` to be normalized + Vector3f projection = direction.duplicate().mul(dotProd); + ComponentsQuaternion twist = new ComponentsQuaternion( + projection.getX(), projection.getY(), projection.getZ(), this.w); + twist.normalise(); + if (dotProd < 0.0) { + // Ensure `twist` points towards `direction` + twist.w = -twist.w; + // Rotation angle `twist.angle()` is now reliable + } + return twist; + } + @Override public Vector3f getAxisOrDefault(Vector3f axis) { float sinFromCos = (float) sqrt(Math.max(0, 1 - w * w)); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index c7a8d66..2e659de 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -54,6 +54,9 @@ public interface Quaternion { void copy(Quaternion rotation); + Quaternion getRotationComponentAboutAxis( + Vector3f direction); + Vector3f getAxisOrDefault(Vector3f axis); Vector3f getVector(); From 7bbe11b9f7c053455921283e4042e470f8f9ba6a Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:04:50 +0200 Subject: [PATCH 080/125] Fixed getCopySignRotation --- .../components/advanced/matrix/ArrayMatrix4x4.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 2643041..0a8a19d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -182,13 +182,13 @@ public Quaternion getRotation() { } private Quaternion getCopySignRotation() { - float w = (float) (Math.sqrt(Math.max(0, 1 + m[0][0] + m[1][1] + m[2][2])) / 2); - float x = (float) (Math.sqrt(Math.max(0, 1 + m[0][0] - m[1][1] - m[2][2])) / 2); - float y = (float) (Math.sqrt(Math.max(0, 1 - m[0][0] + m[1][1] - m[2][2])) / 2); - float z = (float) (Math.sqrt(Math.max(0, 1 - m[0][0] - m[1][1] + m[2][2])) / 2); - x *= Math.signum(m[2][1] - m[1][2]); - y *= Math.signum(m[0][2] - m[2][0]); - z *= Math.signum(m[1][0] - m[0][1]); + float w = (float) (sqrt(Math.max(0, 1 + m[0][0] + m[1][1] + m[2][2])) / 2); + float x = (float) (sqrt(Math.max(0, 1 + m[0][0] - m[1][1] - m[2][2])) / 2); + float y = (float) (sqrt(Math.max(0, 1 - m[0][0] + m[1][1] - m[2][2])) / 2); + float z = (float) (sqrt(Math.max(0, 1 - m[0][0] - m[1][1] + m[2][2])) / 2); + x = copySign(x, m[1][2] - m[2][1]); + y = copySign(y, m[2][0] - m[0][2]); + z = copySign(z, m[0][1] - m[1][0]); return new ComponentsQuaternion(x, y, z, w); } From 62b219801c841142cd5840880968ca8d8a43d307 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:05:35 +0200 Subject: [PATCH 081/125] Replaced getCopySignRotation() with more reliable method --- .../advanced/matrix/ArrayMatrix4x4.java | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 0a8a19d..bd73cb0 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -9,6 +9,9 @@ import java.util.Arrays; +import static java.lang.Math.copySign; +import static java.lang.Math.sqrt; + public class ArrayMatrix4x4 implements Matrix4x4 { private final float[][] m; @@ -178,17 +181,42 @@ public void scalar(Vector3f size) { @Override public Quaternion getRotation() { - return getCopySignRotation(); - } - - private Quaternion getCopySignRotation() { - float w = (float) (sqrt(Math.max(0, 1 + m[0][0] + m[1][1] + m[2][2])) / 2); - float x = (float) (sqrt(Math.max(0, 1 + m[0][0] - m[1][1] - m[2][2])) / 2); - float y = (float) (sqrt(Math.max(0, 1 - m[0][0] + m[1][1] - m[2][2])) / 2); - float z = (float) (sqrt(Math.max(0, 1 - m[0][0] - m[1][1] + m[2][2])) / 2); - x = copySign(x, m[1][2] - m[2][1]); - y = copySign(y, m[2][0] - m[0][2]); - z = copySign(z, m[0][1] - m[1][0]); + return getOtherRotation(); + } + + private Quaternion getOtherRotation() { + float x; + float y; + float z; + float w; + float trace = m[0][0] + m[1][1] + m[2][2]; // I removed + 1.0f; see discussion with Ethan + if( trace > 0 ) {// I changed M_EPSILON to 0 + float s = (float) (0.5f / sqrt(trace+ 1.0f)); + w = 0.25f / s; + x = (m[1][2] - m[2][1]) * s; + y = (m[2][0] - m[0][2]) * s; + z = (m[0][1] - m[1][0]) * s; + } else { + if ( m[0][0] > m[1][1] && m[0][0] > m[2][2] ) { + float s = (float) (2.0f * sqrt( 1.0f + m[0][0] - m[1][1] - m[2][2])); + w = (m[1][2] - m[2][1]) / s; + x = 0.25f * s; + y = (m[0][1] + m[1][0] ) / s; + z = (m[0][2] + m[2][0] ) / s; + } else if (m[1][1] > m[2][2]) { + float s = (float) (2.0f * sqrt( 1.0f + m[1][1] - m[0][0] - m[2][2])); + w = (m[2][0] - m[0][2]) / s; + x = (m[0][1] + m[1][0] ) / s; + y = 0.25f * s; + z = (m[1][2] + m[2][1] ) / s; + } else { + float s = (float) (2.0f * sqrt( 1.0f + m[2][2] - m[0][0] - m[1][1] )); + w = (m[0][1] - m[1][0]) / s; + x = (m[0][2] + m[2][0] ) / s; + y = (m[1][2] + m[2][1] ) / s; + z = 0.25f * s; + } + } return new ComponentsQuaternion(x, y, z, w); } From 95f148e461f1d29eab5cf828563aab0c2273b184 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:05:52 +0200 Subject: [PATCH 082/125] Added toString() to JavaMathAngle --- .../components/advanced/matrix/angle/JavaMathAngle.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java index b29399f..211e4b5 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java @@ -52,4 +52,11 @@ public double getDegree() { public void setDegree(double degree) { angleValueInRadiant = Math.toRadians(degree); } + + @Override + public String toString() { + return "JavaMathAngle{" + + "angleValueInRadiant=" + angleValueInRadiant + + '}'; + } } From 94e06aa42284a1b8ee42a836c5e3cb61037dfd62 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:06:34 +0200 Subject: [PATCH 083/125] Fixed CollectionSpline for edge cases --- .../fr/radi3nt/spline/splines/CollectionSpline.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java index 56321eb..951453f 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java @@ -17,8 +17,11 @@ public CollectionSpline(List curves) { @Override public float interpolate(float t) { int index = (int) Math.floor(t); - if (t==curves.size()) + if (t==curves.size()) { index = curves.size()-1; + if (curves.isEmpty()) + index = 0; + } Curve curve = getCurveAtIndex(index); return curve.interpolate(t-index); } @@ -26,8 +29,11 @@ public float interpolate(float t) { @Override public float velocity(float t) { int index = (int) Math.floor(t); - if (t==curves.size()) + if (t==curves.size()) { index = curves.size()-1; + if (curves.isEmpty()) + index = 0; + } Curve curve = getCurveAtIndex(index); return curve.velocity(t-index); From 2fa1b5774cd5bebeeee8536ed63d7710ca9be985 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:10:23 +0200 Subject: [PATCH 084/125] Removed AnimationHelper module --- AnimationHelper/.gitignore | 38 ---------- AnimationHelper/pom.xml | 40 ---------- .../java/fr/radi3nt/animations/Animation.java | 8 -- .../animations/channels/AnimationChannel.java | 7 -- .../channels/ChanneledAnimation.java | 33 --------- .../AbstractTransformAnimationChannel.java | 31 -------- ...odularObjectTransformAnimationChannel.java | 64 ---------------- .../ParentTransformAnimationChannel.java | 9 --- .../object/TransformAnimationChannel.java | 11 --- .../rotation/QuaternionAnimationChannel.java | 24 ------ .../QuaternionObjectInterpolation.java | 22 ------ .../RotationXEulerAnimationChannel.java | 26 ------- .../RotationYEulerAnimationChannel.java | 26 ------- .../RotationZEulerAnimationChannel.java | 26 ------- .../object/scale/ScaleAnimationChannel.java | 21 ------ .../scale/ScaleObjectInterpolation.java | 20 ----- .../scale/ScaleSeparatedAnimationChannel.java | 27 ------- .../TranslationAnimationChannel.java | 25 ------- .../TranslationObjectInterpolation.java | 20 ----- .../TranslationSeparatedAnimationChannel.java | 28 ------- .../channels/single/FloatInterpolation.java | 20 ----- .../anim/AnimFormatAnimationImporter.java | 55 -------------- .../animation/AnimationChannelBuilder.java | 10 --- .../spline/BezierKeyedSplineBuilder.java | 67 ----------------- .../object/ObjectInterpolation.java | 7 -- .../timing/EasingInterpolationTiming.java | 17 ----- .../timing/InterpolationTiming.java | 7 -- .../timing/ShiftedInterpolationTiming.java | 17 ----- .../timing/Spline2DInterpolationTiming.java | 73 ------------------- .../timing/SplineInterpolationTiming.java | 17 ----- .../timeline/state/AnimatedState.java | 11 --- .../timeline/state/SplineAnimatedState.java | 34 --------- .../timeline/state/TypedAnimatedState.java | 39 ---------- .../timeline/time/ChannelTimeline.java | 7 -- .../timeline/time/SetAnimationTimeline.java | 15 ---- .../timeline/time/TypedChannelTimeline.java | 66 ----------------- pom.xml | 1 - 37 files changed, 969 deletions(-) delete mode 100644 AnimationHelper/.gitignore delete mode 100644 AnimationHelper/pom.xml delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java delete mode 100644 AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java diff --git a/AnimationHelper/.gitignore b/AnimationHelper/.gitignore deleted file mode 100644 index 5ff6309..0000000 --- a/AnimationHelper/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store \ No newline at end of file diff --git a/AnimationHelper/pom.xml b/AnimationHelper/pom.xml deleted file mode 100644 index de1ef36..0000000 --- a/AnimationHelper/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - 4.0.0 - - fr.radi3nt - JavaUtil - 1.0 - - - AnimationHelper - - - 8 - 8 - UTF-8 - - - - fr.radi3nt - MathsHelper - 1.0 - compile - - - fr.radi3nt - SplineHelper - 1.0 - compile - - - fr.radi3nt - FileHelper - 1.0 - compile - - - - \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java deleted file mode 100644 index d44ac25..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/Animation.java +++ /dev/null @@ -1,8 +0,0 @@ -package fr.radi3nt.animations; - -public interface Animation { - - void transform(float time); - float getAnimationTime(); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java deleted file mode 100644 index 16c4843..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/AnimationChannel.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.animations.channels; - -public interface AnimationChannel { - - void transformation(float time); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java deleted file mode 100644 index 9d69989..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/ChanneledAnimation.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.radi3nt.animations.channels; - -import fr.radi3nt.animations.Animation; - -import java.util.ArrayList; -import java.util.Arrays; - -public class ChanneledAnimation implements Animation { - - private final Iterable channels; - private final float animationTime; - - public ChanneledAnimation(Iterable channels, float animationTime) { - this.channels = channels; - this.animationTime = animationTime; - } - - public ChanneledAnimation(float animationTime, AnimationChannel... channels) { - this(new ArrayList<>(Arrays.asList(channels)), animationTime); - } - - @Override - public void transform(float time) { - for (AnimationChannel channel : channels) { - channel.transformation(time); - } - } - - @Override - public float getAnimationTime() { - return animationTime; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java deleted file mode 100644 index c6ea87e..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/AbstractTransformAnimationChannel.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.radi3nt.animations.channels.object; - -import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; - -public abstract class AbstractTransformAnimationChannel implements TransformAnimationChannel { - - protected final Matrix4x4 transform = ArrayMatrix4x4.newIdentity(); - protected ParentTransformAnimationChannel parent; - - @Override - public void setParent(ParentTransformAnimationChannel transform) { - parent = transform; - } - - @Override - public void transformation(float time) { - applyLocalToParent(); - } - - private void applyLocalToParent() { - if (parent!=null) { - parent.getCurrentTransform().multiply(transform); - } - } - - @Override - public Matrix4x4 getLocalTransform() { - return transform; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java deleted file mode 100644 index 32b39d5..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ModularObjectTransformAnimationChannel.java +++ /dev/null @@ -1,64 +0,0 @@ -package fr.radi3nt.animations.channels.object; - -import fr.radi3nt.animations.channels.AnimationChannel; -import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -public class ModularObjectTransformAnimationChannel extends AbstractTransformAnimationChannel implements ParentTransformAnimationChannel { - - private final Matrix4x4 current = ArrayMatrix4x4.newIdentity(); - private final Collection channels = new ArrayList<>(); - - public ModularObjectTransformAnimationChannel() { - - } - - public ModularObjectTransformAnimationChannel(Collection channels) { - this.channels.addAll(channels); - setChildTransform(); - } - - public ModularObjectTransformAnimationChannel(TransformAnimationChannel... channels) { - this.channels.addAll(Arrays.asList(channels)); - setChildTransform(); - } - - public void addChannel(TransformAnimationChannel channel) { - channel.setParent(this); - channels.add(channel); - } - - public void addChannels(Collection channels) { - this.channels.addAll(channels); - for (TransformAnimationChannel channel : channels) { - channel.setParent(this); - } - } - - @Override - public void transformation(float time) { - transform.identity(); - for (AnimationChannel channel : channels) { - current.identity(); - channel.transformation(time); - transform.multiply(current); - } - if (parent!=null) - parent.getCurrentTransform().multiply(transform); - } - - private void setChildTransform() { - for (TransformAnimationChannel channel : channels) { - channel.setParent(this); - } - } - - @Override - public Matrix4x4 getCurrentTransform() { - return current; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java deleted file mode 100644 index b2e5979..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/ParentTransformAnimationChannel.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.radi3nt.animations.channels.object; - -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; - -public interface ParentTransformAnimationChannel extends TransformAnimationChannel { - - Matrix4x4 getCurrentTransform(); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java deleted file mode 100644 index b7596f4..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/TransformAnimationChannel.java +++ /dev/null @@ -1,11 +0,0 @@ -package fr.radi3nt.animations.channels.object; - -import fr.radi3nt.animations.channels.AnimationChannel; -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; - -public interface TransformAnimationChannel extends AnimationChannel { - - void setParent(ParentTransformAnimationChannel transform); - Matrix4x4 getLocalTransform(); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java deleted file mode 100644 index 843c1ff..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionAnimationChannel.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.radi3nt.animations.channels.object.rotation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; - -public class QuaternionAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline quaternionTimeline; - - public QuaternionAnimationChannel(ChannelTimeline quaternionTimeline) { - this.quaternionTimeline = quaternionTimeline; - } - - @Override - public void transformation(float time) { - transform.quaternionRotation(quaternionTimeline.state(time)); - super.transformation(time); - } - - public ChannelTimeline getQuaternionTimeline() { - return quaternionTimeline; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java deleted file mode 100644 index bc740d6..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/QuaternionObjectInterpolation.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.radi3nt.animations.channels.object.rotation; - -import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; -import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; -import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; - -public class QuaternionObjectInterpolation implements ObjectInterpolation { - - private final InterpolationTiming interpolationTiming; - - public QuaternionObjectInterpolation(InterpolationTiming interpolationTiming) { - this.interpolationTiming = interpolationTiming; - } - - @Override - public Quaternion interpolate(Quaternion start, Quaternion end, float t) { - float time = interpolationTiming.getTransformedTime(t); - Quaternion result = start.duplicate(); - result.interpolate(end, time); - return result; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java deleted file mode 100644 index 5cbb9f0..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationXEulerAnimationChannel.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.radi3nt.animations.channels.object.rotation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; -import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class RotationXEulerAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline rotationX; - - public RotationXEulerAnimationChannel(ChannelTimeline rotationX) { - this.rotationX = rotationX; - } - - @Override - public void transformation(float time) { - transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(1, 0, 0), JavaMathAngle.fromDegree(rotationX.state(time)))); - super.transformation(time); - } - - public ChannelTimeline getRotationX() { - return rotationX; - } -} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java deleted file mode 100644 index b07a6a9..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationYEulerAnimationChannel.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.radi3nt.animations.channels.object.rotation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; -import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class RotationYEulerAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline rotationY; - - public RotationYEulerAnimationChannel(ChannelTimeline rotationY) { - this.rotationY = rotationY; - } - - @Override - public void transformation(float time) { - transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 1, 0), JavaMathAngle.fromDegree(rotationY.state(time)))); - super.transformation(time); - } - - public ChannelTimeline getRotationY() { - return rotationY; - } -} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java deleted file mode 100644 index ad776ca..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/rotation/RotationZEulerAnimationChannel.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.radi3nt.animations.channels.object.rotation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; -import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class RotationZEulerAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline rotationZ; - - public RotationZEulerAnimationChannel(ChannelTimeline rotationZ) { - this.rotationZ = rotationZ; - } - - @Override - public void transformation(float time) { - transform.quaternionRotation(ComponentsQuaternion.fromAxisAndAngle(new SimpleVector3f(0, 0, 1), JavaMathAngle.fromDegree(rotationZ.state(time)))); - super.transformation(time); - } - - public ChannelTimeline getRotationZ() { - return rotationZ; - } -} \ No newline at end of file diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java deleted file mode 100644 index 3228b07..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleAnimationChannel.java +++ /dev/null @@ -1,21 +0,0 @@ -package fr.radi3nt.animations.channels.object.scale; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.vectors.Vector3f; - -public class ScaleAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline translationsTimeline; - - public ScaleAnimationChannel(ChannelTimeline translationsTimeline) { - this.translationsTimeline = translationsTimeline; - } - - @Override - public void transformation(float time) { - transform.scale(translationsTimeline.state(time)); - super.transformation(time); - } - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java deleted file mode 100644 index 6de07ff..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleObjectInterpolation.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.radi3nt.animations.channels.object.scale; - -import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; -import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; -import fr.radi3nt.maths.components.vectors.Vector3f; - -public class ScaleObjectInterpolation implements ObjectInterpolation { - - private final InterpolationTiming interpolationTiming; - - public ScaleObjectInterpolation(InterpolationTiming interpolationTiming) { - this.interpolationTiming = interpolationTiming; - } - - @Override - public Vector3f interpolate(Vector3f start, Vector3f end, float t) { - float time = interpolationTiming.getTransformedTime(t); - return start.duplicate().mul(1-time).add(end.duplicate().mul(time)); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java deleted file mode 100644 index 5477656..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/scale/ScaleSeparatedAnimationChannel.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.radi3nt.animations.channels.object.scale; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class ScaleSeparatedAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline xTimeline; - private final ChannelTimeline yTimeline; - private final ChannelTimeline zTimeline; - - public ScaleSeparatedAnimationChannel(ChannelTimeline xTimeline, ChannelTimeline yTimeline, ChannelTimeline zTimeline) { - this.xTimeline = xTimeline; - this.yTimeline = yTimeline; - this.zTimeline = zTimeline; - } - - @Override - public void transformation(float time) { - Vector3f scale = new SimpleVector3f(xTimeline.state(time), yTimeline.state(time), zTimeline.state(time)); - transform.scale(scale); - super.transformation(time); - } - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java deleted file mode 100644 index 3952bd5..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationAnimationChannel.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.radi3nt.animations.channels.object.translation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.channels.object.TransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; -import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; -import fr.radi3nt.maths.components.vectors.Vector3f; - -public class TranslationAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline translationsTimeline; - private final Matrix4x4 transform = ArrayMatrix4x4.newIdentity(); - private TransformAnimationChannel parent; - - public TranslationAnimationChannel(ChannelTimeline translationsTimeline) { - this.translationsTimeline = translationsTimeline; - } - - @Override - public void transformation(float time) { - transform.translation(translationsTimeline.state(time)); - super.transformation(time); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java deleted file mode 100644 index 226b632..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationObjectInterpolation.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.radi3nt.animations.channels.object.translation; - -import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; -import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; -import fr.radi3nt.maths.components.vectors.Vector3f; - -public class TranslationObjectInterpolation implements ObjectInterpolation { - - private final InterpolationTiming interpolationTiming; - - public TranslationObjectInterpolation(InterpolationTiming interpolationTiming) { - this.interpolationTiming = interpolationTiming; - } - - @Override - public Vector3f interpolate(Vector3f start, Vector3f end, float t) { - float time = interpolationTiming.getTransformedTime(t); - return start.duplicate().mul(1-time).add(end.duplicate().mul(time)); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java deleted file mode 100644 index 85861a1..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/object/translation/TranslationSeparatedAnimationChannel.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.radi3nt.animations.channels.object.translation; - -import fr.radi3nt.animations.channels.object.AbstractTransformAnimationChannel; -import fr.radi3nt.animations.timeline.time.ChannelTimeline; -import fr.radi3nt.maths.components.vectors.Vector3f; -import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; - -public class TranslationSeparatedAnimationChannel extends AbstractTransformAnimationChannel { - - private final ChannelTimeline xTimeline; - private final ChannelTimeline yTimeline; - private final ChannelTimeline zTimeline; - - public TranslationSeparatedAnimationChannel(ChannelTimeline xTimeline, ChannelTimeline yTimeline, ChannelTimeline zTimeline) { - this.xTimeline = xTimeline; - this.yTimeline = yTimeline; - this.zTimeline = zTimeline; - } - - @Override - public void transformation(float time) { - Vector3f translation = new SimpleVector3f(xTimeline.state(time), yTimeline.state(time), zTimeline.state(time)); - transform.translation(translation); - - super.transformation(time); - } - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java deleted file mode 100644 index ecbce5e..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/channels/single/FloatInterpolation.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.radi3nt.animations.channels.single; - -import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; -import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; - -public class FloatInterpolation implements ObjectInterpolation { - - private final InterpolationTiming interpolationTiming; - - public FloatInterpolation(InterpolationTiming interpolationTiming) { - this.interpolationTiming = interpolationTiming; - } - - @Override - public Float interpolate(Float start, Float end, float t) { - float time = interpolationTiming.getTransformedTime(t); - return start*(1-time)+end*time; - } - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java deleted file mode 100644 index 88e8797..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java +++ /dev/null @@ -1,55 +0,0 @@ -package fr.radi3nt.animations.importing.anim; - -import fr.radi3nt.animations.importing.anim.animation.AnimationBody; -import fr.radi3nt.animations.importing.anim.animation.AnimationBodyBuilder; -import fr.radi3nt.animations.importing.anim.content.AnimFileContent; -import fr.radi3nt.animations.importing.anim.header.AnimHeader; -import fr.radi3nt.animations.importing.anim.header.AnimHeaderBuilder; - -public class AnimFormatAnimationImporter { - - private final AnimFileContent animFileContent; - private final AnimHeaderBuilder headerBuilder; - private final AnimationBodyBuilder bodyBuilder; - - public AnimFormatAnimationImporter(AnimFileContent animFileContent, AnimHeaderBuilder headerBuilder, AnimationBodyBuilder bodyBuilder) { - this.animFileContent = animFileContent; - this.headerBuilder = headerBuilder; - this.bodyBuilder = bodyBuilder; - } - - public AnimImportedResult importFromContent() { - AnimHeader animHeader = headerBuilder.build(animFileContent); - AnimationBody animationBody = bodyBuilder.build(animFileContent, animHeader); - - return new AnimImportedResult(animHeader, animationBody); - } - - - public static class AnimImportedResult { - - private final AnimHeader header; - private final AnimationBody animationBody; - - public AnimImportedResult(AnimHeader header, AnimationBody animationBody) { - this.header = header; - this.animationBody = animationBody; - } - - public AnimHeader getHeader() { - return header; - } - - public AnimationBody getAnimationBody() { - return animationBody; - } - - @Override - public String toString() { - return "AnimImportedResult{" + - "header=" + header + - ", animationBody=" + animationBody + - '}'; - } - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java deleted file mode 100644 index cea8634..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationChannelBuilder.java +++ /dev/null @@ -1,10 +0,0 @@ -package fr.radi3nt.animations.importing.anim.animation; - -import fr.radi3nt.animations.channels.AnimationChannel; -import fr.radi3nt.animations.importing.anim.animation.data.AnimData; - -public interface AnimationChannelBuilder { - - AnimationChannel create(String inputType, String channelName, String objectName, AnimData animData); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java deleted file mode 100644 index 5c84a86..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.radi3nt.animations.importing.anim.animation.spline; - -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.spline.curve.Curve; -import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; -import fr.radi3nt.spline.splines.CollectionSpline; -import fr.radi3nt.spline.splines.Spline; -import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; -import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D; -import fr.radi3nt.spline.splines.dimensions.Spline2D; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class BezierKeyedSplineBuilder implements KeyedSplineBuilder { - - private final Map curveHandleDataBuilderMap; - - public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap) { - this.curveHandleDataBuilderMap = curveHandleDataBuilderMap; - } - - @Override - public Spline2D build(List keyData, float animFrameRate) { - List xCurves = new ArrayList<>(); - List yCurves = new ArrayList<>(); - Spline xSpline = new CollectionSpline(xCurves); - Spline ySpline = new CollectionSpline(yCurves); - for (int i = 0; i < keyData.size()-1; i++) { - KeyData start = keyData.get(i); - KeyData end = keyData.get(i+1); - - InterpolationType startSplineType = start.getOutInterpolation(); - InterpolationType endSplineType = end.getInInterpolation(); - - CurveHandleData startCurveData = curveHandleDataBuilderMap.get(startSplineType).buildStartHandleData(keyData, i, start, end); - CurveHandleData endCurveData = curveHandleDataBuilderMap.get(endSplineType).buildEndHandleData(keyData, i, start, end); - - CubicBezierCurve curveX = new CubicBezierCurve(new DirectCubicBezierCurveController( - start.getIn()/animFrameRate, - end.getIn()/animFrameRate, - (start.getIn()+calcPosX(startCurveData))/animFrameRate, - (end.getIn()-calcPosX(endCurveData))/animFrameRate)); - CubicBezierCurve curveY = new CubicBezierCurve(new DirectCubicBezierCurveController( - start.getOut(), - end.getOut(), - start.getOut()+calcPosY(startCurveData), - end.getOut()-calcPosY(endCurveData))); - xCurves.add(curveX); - yCurves.add(curveY); - } - - return new EncapsulatingSpline2D(xSpline, ySpline); - } - - - private float calcPosX(CurveHandleData curveHandleData) { - return (float) (Math.cos(Math.toRadians(curveHandleData.getTangentAngle()))*curveHandleData.getTangentWeight()); - } - - private float calcPosY(CurveHandleData curveHandleData) { - return (float) (Math.sin(Math.toRadians(curveHandleData.getTangentAngle()))*curveHandleData.getTangentWeight()); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java deleted file mode 100644 index 59fee84..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/object/ObjectInterpolation.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.object; - -public interface ObjectInterpolation { - - T interpolate(T start, T end, float t); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java deleted file mode 100644 index 74631cb..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/EasingInterpolationTiming.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.timing; - -import fr.radi3nt.maths.Easing; - -public class EasingInterpolationTiming implements InterpolationTiming { - - private final Easing easing; - - public EasingInterpolationTiming(Easing easing) { - this.easing = easing; - } - - @Override - public float getTransformedTime(float time) { - return easing.ease(time, 0, 1, 1); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java deleted file mode 100644 index c075c81..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/InterpolationTiming.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.timing; - -public interface InterpolationTiming { - - float getTransformedTime(float time); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java deleted file mode 100644 index 1eac444..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/ShiftedInterpolationTiming.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.timing; - -public class ShiftedInterpolationTiming implements InterpolationTiming { - - private final InterpolationTiming encapsulated; - private final float shiftT; - - public ShiftedInterpolationTiming(InterpolationTiming encapsulated, float shiftT) { - this.encapsulated = encapsulated; - this.shiftT = shiftT; - } - - @Override - public float getTransformedTime(float time) { - return encapsulated.getTransformedTime(time+shiftT); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java deleted file mode 100644 index 48265db..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/Spline2DInterpolationTiming.java +++ /dev/null @@ -1,73 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.timing; - -import fr.radi3nt.maths.components.vectors.Vector2f; -import fr.radi3nt.spline.splines.dimensions.Spline2D; - -public class Spline2DInterpolationTiming implements InterpolationTiming { - - private static final float X_TOLERANCE = 0.001f; - private static final int MAX_LOOP = 10_000; - private final Spline2D spline; - private final float splineLength; - private final int keyAmount; - - private final float startState; - private final float endState; - - public Spline2DInterpolationTiming(Spline2D spline, float splineLength, int keyAmount) { - this.spline = spline; - this.splineLength = splineLength; - this.keyAmount = keyAmount; - endState = spline.interpolate(keyAmount).getY(); - startState = spline.interpolate(0).getY(); - } - - public Spline2DInterpolationTiming(Spline2D spline, float splineLength) { - this(spline, splineLength, 1); - } - - public Spline2DInterpolationTiming(Spline2D spline) { - this(spline, 1f); - } - - @Override - public float getTransformedTime(float time) { - if (time>=1f) - return endState; - if (time<=0f) - return startState; - - Vector2f point = findPointWithX(time*splineLength); - return point.getY(); - } - - private Vector2f findPointWithX(float xTarget) { - - float lower = 0; - float upper = keyAmount; - float percent = (upper + lower) / 2; - - //get initial x - Vector2f result = spline.interpolate(percent); - float x = result.getX(); - - //loop until completion - int loopAmount = 0; - while(Math.abs(xTarget - x) > X_TOLERANCE && loopAmount x) - lower = percent; - else - upper = percent; - - percent = (upper + lower) / 2; - result = spline.interpolate(percent); - x = result.getX(); - loopAmount++; - } - - if (loopAmount==MAX_LOOP) - System.out.println("Exceeding for time " + xTarget); - - return result; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java deleted file mode 100644 index 713242f..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/interpolation/timing/SplineInterpolationTiming.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.radi3nt.animations.timeline.interpolation.timing; - -import fr.radi3nt.spline.splines.Spline; - -public class SplineInterpolationTiming implements InterpolationTiming { - - private final Spline spline; - - public SplineInterpolationTiming(Spline spline) { - this.spline = spline; - } - - @Override - public float getTransformedTime(float time) { - return spline.interpolate(time); - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java deleted file mode 100644 index c08d027..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/AnimatedState.java +++ /dev/null @@ -1,11 +0,0 @@ -package fr.radi3nt.animations.timeline.state; - -public interface AnimatedState { - - T getStartState(); - T getEndState(); - - T interpolate(float timeStartingAtBit); - float getTimeLength(); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java deleted file mode 100644 index ec39b12..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/SplineAnimatedState.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.radi3nt.animations.timeline.state; - -import fr.radi3nt.animations.timeline.interpolation.timing.InterpolationTiming; - -public class SplineAnimatedState implements AnimatedState { - - private final InterpolationTiming interpolation; - private final float length; - - public SplineAnimatedState(InterpolationTiming interpolation, float length) { - this.interpolation = interpolation; - this.length = length; - } - - @Override - public Float getStartState() { - return interpolation.getTransformedTime(0); - } - - @Override - public Float getEndState() { - return interpolation.getTransformedTime(1f); - } - - @Override - public Float interpolate(float timeStartingAtBit) { - return interpolation.getTransformedTime(timeStartingAtBit/length); - } - - @Override - public float getTimeLength() { - return length; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java deleted file mode 100644 index bea83ec..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/state/TypedAnimatedState.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.radi3nt.animations.timeline.state; - -import fr.radi3nt.animations.timeline.interpolation.object.ObjectInterpolation; - -public class TypedAnimatedState implements AnimatedState { - - private final T start; - private final T end; - - private final ObjectInterpolation interpolation; - private final float length; - - public TypedAnimatedState(T start, T end, ObjectInterpolation interpolation, float length) { - this.start = start; - this.end = end; - this.interpolation = interpolation; - this.length = length; - } - - @Override - public T getStartState() { - return start; - } - - @Override - public T getEndState() { - return end; - } - - @Override - public T interpolate(float timeStartingAtBit) { - return interpolation.interpolate(start, end, timeStartingAtBit/getTimeLength()); - } - - @Override - public float getTimeLength() { - return length; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java deleted file mode 100644 index 79a47ef..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/ChannelTimeline.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.radi3nt.animations.timeline.time; - -public interface ChannelTimeline { - - T state(float time); - -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java deleted file mode 100644 index 2533320..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/SetAnimationTimeline.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.radi3nt.animations.timeline.time; - -public class SetAnimationTimeline implements ChannelTimeline { - - private final T value; - - public SetAnimationTimeline(T value) { - this.value = value; - } - - @Override - public T state(float time) { - return value; - } -} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java b/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java deleted file mode 100644 index 4a2a7da..0000000 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/timeline/time/TypedChannelTimeline.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.radi3nt.animations.timeline.time; - -import fr.radi3nt.animations.timeline.state.AnimatedState; - -import java.util.List; - -public class TypedChannelTimeline implements ChannelTimeline { - - private final List> states; - - public TypedChannelTimeline(List> states) { - this.states = states; - } - - @Override - public T state(float time) { - if (time<0) - return states.get(0).getStartState(); - - TimeResult result = getAnimatedStateAtTime(time); - - if (timeIsOutOfAnimation(result)) - return states.get(states.size()-1).getEndState(); - - AnimatedState animatedState = result.animatedState; - - float timeStartingAtBit = time-result.currentTime; - return animatedState.interpolate(timeStartingAtBit); - } - - public float getTimelineLength() { - float currentTime = 0; - for (AnimatedState state : states) { - float stateTime = state.getTimeLength(); - currentTime+=stateTime; - } - return currentTime; - } - - private boolean timeIsOutOfAnimation(TimeResult result) { - return result==null; - } - - private TimeResult getAnimatedStateAtTime(float time) { - float currentTime = 0; - for (AnimatedState state : states) { - float stateTime = state.getTimeLength(); - if (currentTime<=time && time animatedState; - private final float currentTime; - - private TimeResult(AnimatedState animatedState, float currentTime) { - this.animatedState = animatedState; - this.currentTime = currentTime; - } - } -} diff --git a/pom.xml b/pom.xml index 7afa99e..cbaf497 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,6 @@ LanguageHelperV2 DataStructures SplineHelper - AnimationHelper InverseKinematics Pathfinding From 3e059724120f402da22789aa7cfaa7ec80f321f1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:13:35 +0200 Subject: [PATCH 085/125] Added Animations and AnimationsImport modules --- Animations/pom.xml | 34 ++++++ .../fr/radi3nt/animations/AnimationClip.java | 19 ++++ .../animations/ProcessedAnimation.java | 24 ++++ .../channels/ChannelIdentifier.java | 45 ++++++++ .../animations/channels/KeyframeChannel.java | 7 ++ .../channels/actors/AnimationActor.java | 4 + .../actors/AnimationTransformActor.java | 18 +++ .../EasingInterpolationData.java | 17 +++ .../interpolation/InterpolationData.java | 7 ++ .../interpolation/PlotInterpolationData.java | 80 ++++++++++++++ .../KeyframeSplitEulerXYZRotationChannel.java | 26 +++++ ...KeyframeSplitInterpolationDataChannel.java | 17 +++ .../types/KeyframeSplitVectorChannel.java | 25 +++++ .../types/KeyframeTranslateChannel.java | 47 ++++++++ .../timeline/AnimationTimeline.java | 14 +++ .../timeline/ReplacingAnimationTimeline.java | 49 +++++++++ .../timeline/layers/AnimationLayer.java | 18 +++ .../animations/timeline/layers/LayerMode.java | 9 ++ AnimationsImport/pom.xml | 40 +++++++ .../anim/AnimFormatAnimationImporter.java | 100 +++++++++++++++++ .../anim/animation/AnimationBody.java | 0 .../anim/animation/AnimationBodyBuilder.java | 0 .../FailureSafeAnimationBodyBuilder.java | 11 +- .../anim/animation/data/AnimData.java | 0 .../anim/animation/data/ChannelInfo.java | 8 +- .../anim/animation/data/ChannelType.java | 0 .../animation/data/key/CurveHandleData.java | 0 .../animation/data/key/InterpolationType.java | 0 .../anim/animation/data/key/KeyData.java | 22 ++-- .../animation/data/key/KeyframesData.java | 0 .../spline/BezierKeyedSplineBuilder.java | 103 ++++++++++++++++++ .../spline/CurveHandleDataBuilder.java | 0 .../animation/spline/KeyedSplineBuilder.java | 0 .../spline/handle/AutoHandleDataBuilder.java | 0 .../spline/handle/FixedHandleDataBuilder.java | 0 .../handle/GeneratedHandleDataBuilder.java | 16 +-- .../anim/content/AnimFileContent.java | 0 .../anim/content/ReadableAnimFileContent.java | 3 +- .../importing/anim/header/AnimHeader.java | 0 .../anim/header/AnimHeaderBuilder.java | 0 .../header/FailureSafeAnimHeaderBuilder.java | 0 .../importing/anim/units/AngularUnit.java | 0 .../importing/anim/units/AnimUnit.java | 0 .../importing/anim/units/LinearUnit.java | 0 .../importing/anim/units/TimeUnit.java | 0 .../importing/anim/units/UnitType.java | 0 pom.xml | 2 + 47 files changed, 740 insertions(+), 25 deletions(-) create mode 100644 Animations/pom.xml create mode 100644 Animations/src/main/java/fr/radi3nt/animations/AnimationClip.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/ChannelIdentifier.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/KeyframeChannel.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationActor.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationTransformActor.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/EasingInterpolationData.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/InterpolationData.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/PlotInterpolationData.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java create mode 100644 AnimationsImport/pom.xml create mode 100644 AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java (91%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java (78%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java (69%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java (100%) create mode 100644 AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java (71%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/content/AnimFileContent.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/content/ReadableAnimFileContent.java (95%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/header/AnimHeader.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/header/AnimHeaderBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/header/FailureSafeAnimHeaderBuilder.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/units/AngularUnit.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/units/AnimUnit.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/units/LinearUnit.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/units/TimeUnit.java (100%) rename {AnimationHelper => AnimationsImport}/src/main/java/fr/radi3nt/animations/importing/anim/units/UnitType.java (100%) diff --git a/Animations/pom.xml b/Animations/pom.xml new file mode 100644 index 0000000..8e7b4c1 --- /dev/null +++ b/Animations/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + Animations + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + fr.radi3nt + SplineHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/Animations/src/main/java/fr/radi3nt/animations/AnimationClip.java b/Animations/src/main/java/fr/radi3nt/animations/AnimationClip.java new file mode 100644 index 0000000..fe04e22 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/AnimationClip.java @@ -0,0 +1,19 @@ +package fr.radi3nt.animations; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.channels.KeyframeChannel; + +import java.util.Map; + +public class AnimationClip { + + public final float duration; + public final Map> channels; + + public AnimationClip(float duration, Map> channels) { + this.duration = duration; + this.channels = channels; + } + + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java b/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java new file mode 100644 index 0000000..40d45fe --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java @@ -0,0 +1,24 @@ +package fr.radi3nt.animations; + +public class ProcessedAnimation { + + public final AnimationClip animationClip; + private final boolean looping; + private float relativeTime; + + public ProcessedAnimation(AnimationClip animationClip, boolean looping) { + this.animationClip = animationClip; + this.looping = looping; + } + + public float getRelativeTime() { + return relativeTime; + } + + public void incrementTime(float delta) { + relativeTime+=delta; + if (relativeTime>animationClip.duration && looping) + relativeTime-=animationClip.duration; + } + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/ChannelIdentifier.java b/Animations/src/main/java/fr/radi3nt/animations/channels/ChannelIdentifier.java new file mode 100644 index 0000000..2483d97 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/ChannelIdentifier.java @@ -0,0 +1,45 @@ +package fr.radi3nt.animations.channels; + +import java.util.Objects; + +public class ChannelIdentifier { + + public final String objectName; + public final String channelType; + + public ChannelIdentifier(String objectName, String channelType) { + this.objectName = objectName; + this.channelType = channelType; + } + + public static ChannelIdentifier translation(String objectName) { + return new ChannelIdentifier(objectName, "translate"); + } + + + public static ChannelIdentifier rotation(String objectName) { + return new ChannelIdentifier(objectName, "rotate"); + } + + + public static ChannelIdentifier scale(String objectName) { + return new ChannelIdentifier(objectName, "scale"); + } + + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ChannelIdentifier)) return false; + + ChannelIdentifier that = (ChannelIdentifier) o; + return Objects.equals(objectName, that.objectName) && Objects.equals(channelType, that.channelType); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(objectName); + result = 31 * result + Objects.hashCode(channelType); + return result; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/KeyframeChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/KeyframeChannel.java new file mode 100644 index 0000000..ba08860 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/KeyframeChannel.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.channels; + +public interface KeyframeChannel { + + A transform(float t); + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationActor.java b/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationActor.java new file mode 100644 index 0000000..cff6813 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationActor.java @@ -0,0 +1,4 @@ +package fr.radi3nt.animations.channels.actors; + +public interface AnimationActor { +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationTransformActor.java b/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationTransformActor.java new file mode 100644 index 0000000..df24997 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/actors/AnimationTransformActor.java @@ -0,0 +1,18 @@ +package fr.radi3nt.animations.channels.actors; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface AnimationTransformActor extends AnimationActor { + + void setTranslation(Vector3f translation); + void setRotation(Quaternion rotation); + void setScale(Vector3f scale); + + Matrix4x4 getTransform(); + Vector3f getTranslation(); + Quaternion getRotation(); + Vector3f getScale(); + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/EasingInterpolationData.java b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/EasingInterpolationData.java new file mode 100644 index 0000000..1b2e3b2 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/EasingInterpolationData.java @@ -0,0 +1,17 @@ +package fr.radi3nt.animations.channels.interpolation; + +import fr.radi3nt.maths.Easing; + +public class EasingInterpolationData implements InterpolationData { + + private final Easing easing; + + public EasingInterpolationData(Easing easing) { + this.easing = easing; + } + + @Override + public float interpolate(float t) { + return easing.ease(t, 0, 1, 1); + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/InterpolationData.java b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/InterpolationData.java new file mode 100644 index 0000000..3417fc9 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/InterpolationData.java @@ -0,0 +1,7 @@ +package fr.radi3nt.animations.channels.interpolation; + +public interface InterpolationData { + + float interpolate(float t); + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/PlotInterpolationData.java b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/PlotInterpolationData.java new file mode 100644 index 0000000..4dcb218 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/interpolation/PlotInterpolationData.java @@ -0,0 +1,80 @@ +package fr.radi3nt.animations.channels.interpolation; + +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import static java.lang.Math.abs; + +public class PlotInterpolationData implements InterpolationData { + + private static final float EPSILON = 1e-5f; + private final float[] plotted; + private final float plotInterval; + + public PlotInterpolationData(float[] plotted, float plotInterval) { + this.plotted = plotted; + this.plotInterval = plotInterval; + } + + public static PlotInterpolationData create(Spline2D spline, float splineDuration, int splineSegments, float splineOffset, int points) { + float[] plots = new float[points]; + float lastT = 0; + + float plotInterval = splineDuration/(points-1f); + + for (int i = 0; i < points; i++) { + float x = i*plotInterval + splineOffset; + float correspondingT = lastT = newtonRaphsonMethod(x, lastT, spline, splineSegments); + plots[i] = spline.interpolateY(correspondingT); + } + return new PlotInterpolationData(plots, plotInterval); + } + + private static float newtonRaphsonMethod(float expectedX, float startT, Spline2D spline, int splineSegments) { + float currentGuess = startT; + for (int i = 0; i < 50; i++) { + if (currentGuess>=splineSegments) + currentGuess = splineSegments; + if (currentGuess<0) + currentGuess = 0; + float value = spline.interpolateX(currentGuess); + if (closeEnough(value, expectedX)) { + break; + } + float vel = spline.velocityX(currentGuess); + if (vel==0) + vel = EPSILON; //preventing catastrophic failure + currentGuess = currentGuess - (value-expectedX)/(vel); + } + + if (currentGuess>=splineSegments) + currentGuess = splineSegments; + if (currentGuess<0) + currentGuess = 0; + + return currentGuess; + } + + private static boolean closeEnough(float currentGuess, float expectedX) { + return abs(currentGuess-expectedX)=plotted.length) + return plotted[plotted.length-1]; + + if (indexPlusOne>=plotted.length) + return plotted[index]; + + float startValue = plotted[index]; + float endValue = plotted[indexPlusOne]; + float relativeTime = (t-index*plotInterval)/plotInterval; + + return relativeTime*endValue+(1-relativeTime)*startValue; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java new file mode 100644 index 0000000..29732cf --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java @@ -0,0 +1,26 @@ +package fr.radi3nt.animations.channels.types; + +import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; + +public class KeyframeSplitEulerXYZRotationChannel extends KeyframeSplitInterpolationDataChannel { + + private final float relativeDuration; + + public KeyframeSplitEulerXYZRotationChannel(InterpolationData[] interpolationData, float relativeDuration) { + super(interpolationData); + this.relativeDuration = relativeDuration; + } + + @Override + public Quaternion transform(float t) { + float transformedTime = t/ relativeDuration; + float x = interpolationData[0]==null ? 0 : interpolationData[0].interpolate(transformedTime); + float y = interpolationData[1]==null ? 0 : interpolationData[1].interpolate(transformedTime); + float z = interpolationData[2]==null ? 0 : interpolationData[2].interpolate(transformedTime); + + return ComponentsQuaternion.fromEulerAngles(JavaMathAngle.fromDegree(x), JavaMathAngle.fromDegree(y), JavaMathAngle.fromDegree(z)); + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java new file mode 100644 index 0000000..2b8c24d --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java @@ -0,0 +1,17 @@ +package fr.radi3nt.animations.channels.types; + +import fr.radi3nt.animations.channels.KeyframeChannel; +import fr.radi3nt.animations.channels.interpolation.InterpolationData; + +public abstract class KeyframeSplitInterpolationDataChannel implements KeyframeChannel { + + protected final InterpolationData[] interpolationData; + + protected KeyframeSplitInterpolationDataChannel(InterpolationData[] interpolationData) { + this.interpolationData = interpolationData; + } + + public InterpolationData[] getInterpolationData() { + return interpolationData; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java new file mode 100644 index 0000000..c06b008 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java @@ -0,0 +1,25 @@ +package fr.radi3nt.animations.channels.types; + +import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class KeyframeSplitVectorChannel extends KeyframeSplitInterpolationDataChannel { + + private final float relativeDuration; + + public KeyframeSplitVectorChannel(InterpolationData[] interpolationData, float relativeDuration) { + super(interpolationData); + this.relativeDuration = relativeDuration; + } + + @Override + public Vector3f transform(float t) { + float transformedTime = t/ relativeDuration; + float x = interpolationData[0].interpolate(transformedTime); + float y = interpolationData[1].interpolate(transformedTime); + float z = interpolationData[2].interpolate(transformedTime); + return new SimpleVector3f(x, y, z); + } + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java new file mode 100644 index 0000000..b3ae5fa --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java @@ -0,0 +1,47 @@ +package fr.radi3nt.animations.channels.types; + +import fr.radi3nt.animations.channels.KeyframeChannel; +import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class KeyframeTranslateChannel implements KeyframeChannel { + + private final InterpolationData interpolationData; + private final Vector3f[] positions; + private final float[] times; + + public KeyframeTranslateChannel(InterpolationData interpolationData, Vector3f[] positions, float[] times) { + this.interpolationData = interpolationData; + this.positions = positions; + this.times = times; + } + + @Override + public Vector3f transform(float t) { + float lastTime = 0; + int lastTimeIndex = 0; + float nextTime = 0; + for (int i = 0; i < times.length; i++) { + float time = times[i]; + nextTime = time; + if (time > t) + break; + lastTime = time; + lastTimeIndex = i; + } + if (lastTimeIndex==positions.length) + return positions[positions.length-1]; + + int nextTimeIndex = lastTimeIndex+1; + + float duration = nextTime - lastTime; + + float interpolated = interpolationData.interpolate((t-lastTime) / duration); + + Vector3f start = positions[lastTimeIndex]; + Vector3f end = positions[nextTimeIndex]; + + return start.duplicate().mul(1-interpolated).add(end.duplicate().mul(interpolated)); + } + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java new file mode 100644 index 0000000..0269e91 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java @@ -0,0 +1,14 @@ +package fr.radi3nt.animations.timeline; + +import fr.radi3nt.animations.channels.ChannelIdentifier; + +import java.util.Collection; + +public interface AnimationTimeline { + + void update(float delta); + + T getAnimatedPropertyOrDefault(ChannelIdentifier channelIdentifier, T defaultResult); + + Collection getAvailableObjects(); +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java new file mode 100644 index 0000000..9678f09 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java @@ -0,0 +1,49 @@ +package fr.radi3nt.animations.timeline; + +import fr.radi3nt.animations.AnimationClip; +import fr.radi3nt.animations.ProcessedAnimation; +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.channels.KeyframeChannel; + +import java.util.*; + +public class ReplacingAnimationTimeline implements AnimationTimeline { + + private final List processedAnimations = new ArrayList<>(); + + public void addAnimation(AnimationClip animationClip, boolean looping) { + processedAnimations.add(new ProcessedAnimation(animationClip, looping)); + } + + @Override + public void update(float delta) { + for (ProcessedAnimation processedAnimation : processedAnimations) { + processedAnimation.incrementTime(delta); + } + } + + @Override + public T getAnimatedPropertyOrDefault(ChannelIdentifier identifier, T defaultResult) { + KeyframeChannel lastChannel = null; + float t = 0; + + for (ProcessedAnimation processedAnimation : processedAnimations) { + lastChannel = processedAnimation.animationClip.channels.get(identifier); + t = processedAnimation.getRelativeTime(); + } + + return lastChannel==null ? defaultResult : (T) lastChannel.transform(t); + } + + @Override + public Collection getAvailableObjects() { + Set objects = new HashSet<>(); + for (ProcessedAnimation processedAnimation : processedAnimations) { + for (ChannelIdentifier channelIdentifier : processedAnimation.animationClip.channels.keySet()) { + objects.add(channelIdentifier.objectName); + } + } + + return objects; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java new file mode 100644 index 0000000..fdfbaaf --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java @@ -0,0 +1,18 @@ +package fr.radi3nt.animations.timeline.layers; + +import fr.radi3nt.animations.ProcessedAnimation; + +import java.util.ArrayList; +import java.util.List; + +public class AnimationLayer { + + private final List animations = new ArrayList<>(); + private final LayerMode layerMode; + + public AnimationLayer(LayerMode layerMode) { + this.layerMode = layerMode; + } + + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java new file mode 100644 index 0000000..ef81e4b --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java @@ -0,0 +1,9 @@ +package fr.radi3nt.animations.timeline.layers; + +public enum LayerMode { + + REPLACE, + ADD, + MULTIPLY + +} diff --git a/AnimationsImport/pom.xml b/AnimationsImport/pom.xml new file mode 100644 index 0000000..d3a3c92 --- /dev/null +++ b/AnimationsImport/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + AnimationsImport + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + SplineHelper + 1.0 + compile + + + fr.radi3nt + FileHelper + 1.0 + compile + + + fr.radi3nt + Animations + 1.0 + compile + + + + \ No newline at end of file diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java new file mode 100644 index 0000000..c7405ac --- /dev/null +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java @@ -0,0 +1,100 @@ +package fr.radi3nt.animations.importing.anim; + +import fr.radi3nt.animations.AnimationClip; +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.animations.channels.interpolation.PlotInterpolationData; +import fr.radi3nt.animations.channels.types.KeyframeSplitEulerXYZRotationChannel; +import fr.radi3nt.animations.channels.types.KeyframeSplitInterpolationDataChannel; +import fr.radi3nt.animations.channels.types.KeyframeSplitVectorChannel; +import fr.radi3nt.animations.importing.anim.animation.AnimationBody; +import fr.radi3nt.animations.importing.anim.animation.AnimationBodyBuilder; +import fr.radi3nt.animations.importing.anim.animation.data.AnimData; +import fr.radi3nt.animations.importing.anim.animation.data.ChannelInfo; +import fr.radi3nt.animations.importing.anim.content.AnimFileContent; +import fr.radi3nt.animations.importing.anim.header.AnimHeader; +import fr.radi3nt.animations.importing.anim.header.AnimHeaderBuilder; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class AnimFormatAnimationImporter { + + private final AnimHeaderBuilder headerBuilder; + private final AnimationBodyBuilder bodyBuilder; + + public AnimFormatAnimationImporter(AnimHeaderBuilder headerBuilder, AnimationBodyBuilder bodyBuilder) { + this.headerBuilder = headerBuilder; + this.bodyBuilder = bodyBuilder; + } + + public AnimImportedResult importFromContent(AnimFileContent animFileContent) { + AnimHeader animHeader = headerBuilder.build(animFileContent); + AnimationBody animationBody = bodyBuilder.build(animFileContent, animHeader); + + return new AnimImportedResult(animHeader, animationBody); + } + + + public static class AnimImportedResult { + + private static final float POINTS_PER_SECONDS = 60; + private final AnimHeader header; + private final AnimationBody animationBody; + + public AnimImportedResult(AnimHeader header, AnimationBody animationBody) { + this.header = header; + this.animationBody = animationBody; + } + + public AnimationClip toClip() { + float duration = header.getEndFrameTime()/header.getTimeUnit().getFrameEquivalent(); + + Map> channels = new HashMap<>(); + + for (Map.Entry channelInfoAnimDataEntry : animationBody.getAnimData().entrySet()) { + AnimData value = channelInfoAnimDataEntry.getValue(); + ChannelInfo key = channelInfoAnimDataEntry.getKey(); + Supplier> channelSupplier = createChanneSupplier(key); + KeyframeSplitInterpolationDataChannel keyframeChannel = channels.computeIfAbsent(new ChannelIdentifier(key.getObjectName(), key.getMainChannelType()), (c) -> channelSupplier.get()); + Spline2D spline = value.getKeyframesData().getDataSpline(); + keyframeChannel.getInterpolationData()[key.getAttributeInt()] = PlotInterpolationData.create(spline, duration, spline.getSegmentCount(), 0, (int) Math.nextUp(duration*POINTS_PER_SECONDS)); + } + + return new AnimationClip(duration, channels); + } + + private static Supplier> createChanneSupplier(ChannelInfo key) { + Supplier> channelSupplier = null; + switch (key.getMainChannelType()) { + case "rotate": + channelSupplier = () -> new KeyframeSplitEulerXYZRotationChannel(new InterpolationData[3], 1f); + break; + case "translate": + case "scale": + channelSupplier = () -> new KeyframeSplitVectorChannel(new InterpolationData[3], 1f); + break; + } + return channelSupplier; + } + + + public AnimHeader getHeader() { + return header; + } + + public AnimationBody getAnimationBody() { + return animationBody; + } + + @Override + public String toString() { + return "AnimImportedResult{" + + "header=" + header + + ", animationBody=" + animationBody + + '}'; + } + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBody.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/AnimationBodyBuilder.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java similarity index 91% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java index 08be077..ff3c17d 100644 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java @@ -38,14 +38,17 @@ public AnimationBody build(AnimFileContent content, AnimHeader header) { if (splitLine.length<=5) continue; + String fullChannelType = splitLine[1]; String mainChannelType = fullChannelType.split("\\.")[0]; String leafChannelType = splitLine[2]; String objectName = splitLine[3]; + int attributeInt = Integer.parseInt(splitLine[6]); + AnimData animData = buildAnimData(content, header); - animDataMap.put(new ChannelInfo(fullChannelType, mainChannelType, leafChannelType, objectName), animData); + animDataMap.put(new ChannelInfo(fullChannelType, mainChannelType, leafChannelType, attributeInt, objectName), animData); } return new AnimationBody(animDataMap); @@ -80,8 +83,8 @@ private KeyframesData buildKeysData(AnimFileContent content, AnimHeader header) if (line.startsWith("}")) break; String[] splitLine = line.split(" "); - int in = Integer.parseInt(splitLine[0]); - float out = Float.parseFloat(splitLine[1]); + float frameIndex = Float.parseFloat(splitLine[0]); + float correspondingValue = Float.parseFloat(splitLine[1]); InterpolationType inInterpolation = InterpolationType.valueOf(splitLine[2].toUpperCase()); InterpolationType outInterpolation = InterpolationType.valueOf(splitLine[3].toUpperCase()); boolean tanLocked = stringToBool(splitLine[4]); @@ -96,7 +99,7 @@ private KeyframesData buildKeysData(AnimFileContent content, AnimHeader header) curveHandleData[i] = new CurveHandleData(Float.parseFloat(tanAngle), Float.parseFloat(tanWeight)); } - keyData.add(new KeyData(in, out, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData)); + keyData.add(new KeyData(frameIndex, correspondingValue, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData)); } content.nextLine(); return new KeyframesData(keyData, splineBuilder.build(keyData, header.getTimeUnit().getFrameEquivalent())); diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java similarity index 78% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java index 2243c8a..5b359bd 100644 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelInfo.java @@ -5,13 +5,15 @@ public class ChannelInfo { private final String fullChannelType; private final String mainChannelType; private final String leafChannelType; + private final int attributeInt; private final String objectName; - public ChannelInfo(String fullChannelType, String mainChannelType, String leafChannelType, String objectName) { + public ChannelInfo(String fullChannelType, String mainChannelType, String leafChannelType, int attributeInt, String objectName) { this.fullChannelType = fullChannelType; this.mainChannelType = mainChannelType; this.leafChannelType = leafChannelType; + this.attributeInt = attributeInt; this.objectName = objectName; } @@ -27,6 +29,10 @@ public String getLeafChannelType() { return leafChannelType; } + public int getAttributeInt() { + return attributeInt; + } + public String getObjectName() { return objectName; } diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/ChannelType.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java similarity index 69% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java index eaa7d23..cf047e6 100644 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java @@ -4,8 +4,8 @@ public class KeyData { - private final int in; - private final float out; + private final float frameIndex; + private final float correspondingData; private final InterpolationType inInterpolation; private final InterpolationType outInterpolation; @@ -16,9 +16,9 @@ public class KeyData { private final CurveHandleData[] curveHandleData; - public KeyData(int in, float out, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) { - this.in = in; - this.out = out; + public KeyData(float frameIndex, float correspondingData, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) { + this.frameIndex = frameIndex; + this.correspondingData = correspondingData; this.inInterpolation = inInterpolation; this.outInterpolation = outInterpolation; this.tangentLocked = tangentLocked; @@ -26,12 +26,12 @@ public KeyData(int in, float out, InterpolationType inInterpolation, Interpolati this.curveHandleData = curveHandleData; } - public int getIn() { - return in; + public float getFrameIndex() { + return frameIndex; } - public float getOut() { - return out; + public float getCorrespondingData() { + return correspondingData; } public InterpolationType getInInterpolation() { @@ -57,8 +57,8 @@ public CurveHandleData[] getCurveHandleData() { @Override public String toString() { return "KeyData{" + - "in=" + in + - ", out=" + out + + "frameIndex=" + frameIndex + + ", correspondingData=" + correspondingData + ", inInterpolation=" + inInterpolation + ", outInterpolation=" + outInterpolation + ", tangentLocked=" + tangentLocked + diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java new file mode 100644 index 0000000..ce4d270 --- /dev/null +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java @@ -0,0 +1,103 @@ +package fr.radi3nt.animations.importing.anim.animation.spline; + +import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; +import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; +import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.animations.importing.anim.animation.spline.handle.AutoHandleDataBuilder; +import fr.radi3nt.animations.importing.anim.animation.spline.handle.FixedHandleDataBuilder; +import fr.radi3nt.animations.importing.anim.animation.spline.handle.GeneratedHandleDataBuilder; +import fr.radi3nt.spline.curve.Curve; +import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; +import fr.radi3nt.spline.splines.CollectionSpline; +import fr.radi3nt.spline.splines.Spline; +import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController; +import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.*; + +public class BezierKeyedSplineBuilder implements KeyedSplineBuilder { + + + private static final Map DEFAULT_MAP = new HashMap<>(); + static { + DEFAULT_MAP.put(InterpolationType.FIXED, new FixedHandleDataBuilder()); + DEFAULT_MAP.put(InterpolationType.AUTO, new AutoHandleDataBuilder()); + DEFAULT_MAP.put(InterpolationType.SPLINE, new GeneratedHandleDataBuilder()); + } + + public static final Map DEFAULT_INTERPOLATIONS = Collections.unmodifiableMap(DEFAULT_MAP); + + + private final Map curveHandleDataBuilderMap; + private final float scaleX; + private final float scaleY; + + public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap, float scaleX, float scaleY) { + this.curveHandleDataBuilderMap = curveHandleDataBuilderMap; + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + public static KeyedSplineBuilder newDefault(float scaleX, float scaleY) { + return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, scaleX, scaleY); + } + + @Override + public Spline2D build(List keyData, float animFrameRate) { + List xCurves = new ArrayList<>(); + List yCurves = new ArrayList<>(); + Spline xSpline = new CollectionSpline(xCurves); + Spline ySpline = new CollectionSpline(yCurves); + for (int i = 0; i < keyData.size()-1; i++) { + KeyData start = keyData.get(i); + KeyData end = keyData.get(i+1); + + InterpolationType startSplineType = start.getOutInterpolation(); + InterpolationType endSplineType = end.getInInterpolation(); + + CurveHandleData startCurveData = curveHandleDataBuilderMap.get(startSplineType).buildStartHandleData(keyData, i, start, end); + CurveHandleData endCurveData = curveHandleDataBuilderMap.get(endSplineType).buildEndHandleData(keyData, i, start, end); + + float cappedStartLength = capTangentLength(end.getFrameIndex()-start.getFrameIndex(), startCurveData); + float cappedEndLength = capTangentLength(end.getFrameIndex()-start.getFrameIndex(), endCurveData); + + float startXPointControl =(start.getFrameIndex()+calcPosX(startCurveData, cappedStartLength)); + float endXPointControl = (end.getFrameIndex()-calcPosX(endCurveData, cappedEndLength)); + + float startYPointControl = (start.getCorrespondingData()+calcPosY(startCurveData, cappedStartLength)); + float endYPointControl = (end.getCorrespondingData()-calcPosY(endCurveData, cappedEndLength)); + + CubicBezierCurve curveX = new CubicBezierCurve(new DirectCubicBezierCurveController( + start.getFrameIndex()*scaleX/animFrameRate, + end.getFrameIndex()*scaleX/animFrameRate, + startXPointControl*scaleX/animFrameRate, + endXPointControl*scaleX/animFrameRate)); + CubicBezierCurve curveY = new CubicBezierCurve(new DirectCubicBezierCurveController( + start.getCorrespondingData()*scaleY, + end.getCorrespondingData()*scaleY, + startYPointControl*scaleY, + endYPointControl*scaleY)); + + xCurves.add(curveX); + yCurves.add(curveY); + } + + return new EncapsulatingSpline2D(xSpline, ySpline); + } + + + private float capTangentLength(float frameDelta, CurveHandleData curveHandleData) { + float angleProjected = (float) Math.cos(Math.toRadians(curveHandleData.getTangentAngle())); + float maxLength = frameDelta/angleProjected; + return Math.min(curveHandleData.getTangentWeight(), maxLength); + } + + private float calcPosX(CurveHandleData curveHandleData, float length) { + return (float) (Math.cos(Math.toRadians(curveHandleData.getTangentAngle()))*length); + } + + private float calcPosY(CurveHandleData curveHandleData, float length) { + return (float) (Math.sin(Math.toRadians(curveHandleData.getTangentAngle()))*length); + } +} diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java similarity index 100% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java diff --git a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java similarity index 71% rename from AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java rename to AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java index 9cce199..4651cd9 100644 --- a/AnimationHelper/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java @@ -11,16 +11,16 @@ public class GeneratedHandleDataBuilder implements CurveHandleDataBuilder { @Override public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) { - Vector2f endPos = new SimpleVector2f(end.getIn(), end.getOut()); - Vector2f beforeOnePos = new SimpleVector2f(start.getIn(), end.getOut()); + Vector2f endPos = new SimpleVector2f(end.getFrameIndex(), end.getCorrespondingData()); + Vector2f beforeOnePos = new SimpleVector2f(start.getFrameIndex(), end.getCorrespondingData()); float closeness = 0.5f; float lengthMultiplier = 2; if (i!=0) { lengthMultiplier = 1f; KeyData startBefore = keyData.get(i-1); - beforeOnePos = new SimpleVector2f(startBefore.getIn(), startBefore.getOut()); - closeness = (start.getIn()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX()); + beforeOnePos = new SimpleVector2f(startBefore.getFrameIndex(), startBefore.getCorrespondingData()); + closeness = (start.getFrameIndex()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX()); } Vector2f direction = endPos.clone().sub(beforeOnePos.clone()); @@ -32,8 +32,8 @@ public CurveHandleData buildStartHandleData(List keyData, int i, KeyDat @Override public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) { - Vector2f startPos = new SimpleVector2f(start.getIn(), start.getOut()); - Vector2f afterEndPos = new SimpleVector2f(end.getIn(), end.getOut()); + Vector2f startPos = new SimpleVector2f(start.getFrameIndex(), start.getCorrespondingData()); + Vector2f afterEndPos = new SimpleVector2f(end.getFrameIndex(), end.getCorrespondingData()); float closeness = 0.5f; float lengthMultiplier = 2; @@ -41,8 +41,8 @@ public CurveHandleData buildEndHandleData(List keyData, int i, KeyData if (iSplineHelper InverseKinematics Pathfinding + AnimationsImport + Animations From 32cbd15018ff86e94a0903c55c9bbd20a36603fc Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:14:57 +0200 Subject: [PATCH 086/125] Optimised imports --- .../radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java | 1 - 1 file changed, 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index bd73cb0..1524525 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -9,7 +9,6 @@ import java.util.Arrays; -import static java.lang.Math.copySign; import static java.lang.Math.sqrt; public class ArrayMatrix4x4 implements Matrix4x4 { From 88ef8ad5e1df72cae92c3d316a7dc55c77777c29 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:17:15 +0200 Subject: [PATCH 087/125] Added glTF module --- glTF/pom.xml | 40 ++++++++ .../java/fr/radi3nt/gltf/GltfAllImporter.java | 39 ++++++++ .../java/fr/radi3nt/gltf/data/GlTFResult.java | 49 ++++++++++ .../gltf/data/attributes/GlTFAttribute.java | 10 ++ .../radi3nt/gltf/data/buffer/GlTFBuffer.java | 63 ++++++++++++ .../data/buffer/accessor/BufferAccessor.java | 47 +++++++++ .../buffer/accessor/GlTFAccessorType.java | 19 ++++ .../buffer/accessor/GlTFComponentType.java | 29 ++++++ .../gltf/data/buffer/view/BufferView.java | 30 ++++++ .../fr/radi3nt/gltf/data/mesh/GlTFMesh.java | 20 ++++ .../fr/radi3nt/gltf/data/mesh/Primitive.java | 59 +++++++++++ .../gltf/data/mesh/material/GlTFMaterial.java | 14 +++ .../mesh/material/GlTFMaterialIndexer.java | 9 ++ .../gltf/data/scene/GlTFAbstractNode.java | 29 ++++++ .../fr/radi3nt/gltf/data/scene/GlTFNode.java | 39 ++++++++ .../fr/radi3nt/gltf/data/scene/GlTFScene.java | 8 ++ .../gltf/data/scene/GlTFTransform.java | 97 +++++++++++++++++++ .../fr/radi3nt/gltf/data/skins/GlTFSkin.java | 50 ++++++++++ .../gltf/importer/AccessorsImporter.java | 58 +++++++++++ .../gltf/importer/BuffersImporter.java | 33 +++++++ .../radi3nt/gltf/importer/GlTFImporter.java | 10 ++ .../gltf/importer/MaterialsImporter.java | 23 +++++ .../radi3nt/gltf/importer/MeshesImporter.java | 46 +++++++++ .../radi3nt/gltf/importer/NodesImporter.java | 44 +++++++++ .../radi3nt/gltf/importer/ScenesImporter.java | 29 ++++++ .../radi3nt/gltf/importer/SkinsImporter.java | 39 ++++++++ .../radi3nt/gltf/importer/ViewImporter.java | 26 +++++ pom.xml | 1 + 28 files changed, 960 insertions(+) create mode 100644 glTF/pom.xml create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java diff --git a/glTF/pom.xml b/glTF/pom.xml new file mode 100644 index 0000000..9998786 --- /dev/null +++ b/glTF/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + glTF + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + fr.radi3nt + FileHelper + 1.0 + compile + + + fr.radi3nt + JsonHelper + 1.0 + compile + + + + \ No newline at end of file diff --git a/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java new file mode 100644 index 0000000..47ab73e --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java @@ -0,0 +1,39 @@ +package fr.radi3nt.gltf; + +import fr.radi3nt.file.impl.ResourceFile; +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.importer.*; +import fr.radi3nt.json.Json; +import fr.radi3nt.json.JsonValue; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; + +public class GltfAllImporter { + + + public GlTFResult importFile(String filePath, String fileName) throws IOException { + GlTFResult result = new GlTFResult(); + + + Collection importers = new ArrayList<>(); + { + importers.add(new AccessorsImporter()); + importers.add(new MaterialsImporter()); + importers.add(new MeshesImporter()); + importers.add(new NodesImporter()); + importers.add(new ScenesImporter()); + importers.add(new SkinsImporter()); + importers.add(new ViewImporter()); + } + importers.add(new BuffersImporter(filePath)); + + JsonValue parsed = Json.parse(new InputStreamReader(new ResourceFile(filePath + "/" + fileName).getInputStream())); + importers.parallelStream().forEach(importer -> {importer.parse(parsed.asObject(), result);}); + + return result; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java b/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java new file mode 100644 index 0000000..6051071 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java @@ -0,0 +1,49 @@ +package fr.radi3nt.gltf.data; + +import fr.radi3nt.gltf.data.buffer.GlTFBuffer; +import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor; +import fr.radi3nt.gltf.data.buffer.view.BufferView; +import fr.radi3nt.gltf.data.mesh.GlTFMesh; +import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial; +import fr.radi3nt.gltf.data.scene.GlTFNode; +import fr.radi3nt.gltf.data.scene.GlTFScene; +import fr.radi3nt.gltf.data.skins.GlTFSkin; + +import java.util.Arrays; + +public class GlTFResult { + + public GlTFScene[] scenes; + public GlTFNode[] nodes; + + public GlTFMesh[] meshes; + public GlTFSkin[] skins; + public GlTFMaterial[] materials; + + public BufferAccessor[] bufferAccessors; + public BufferView[] bufferViews; + public GlTFBuffer[] buffers; + + @Override + public String toString() { + return "GlTFResult{" + + "scenes=" + Arrays.toString(scenes) + + ", nodes=" + Arrays.toString(nodes) + + ", meshes=" + Arrays.toString(meshes) + + ", skins=" + Arrays.toString(skins) + + ", materials=" + Arrays.toString(materials) + + ", bufferAccessors=" + Arrays.toString(bufferAccessors) + + ", bufferViews=" + Arrays.toString(bufferViews) + + ", buffers=" + Arrays.toString(buffers) + + '}'; + } + + public GlTFNode getNodeByName(String name) { + for (GlTFNode node : nodes) { + if (node.getName().equals(name)) { + return node; + } + } + return null; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java new file mode 100644 index 0000000..0cc5a95 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java @@ -0,0 +1,10 @@ +package fr.radi3nt.gltf.data.attributes; + +public enum GlTFAttribute { + + POSITION, + NORMAL, + JOINTS_0, + WEIGHTS_0 + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java new file mode 100644 index 0000000..3dcdade --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java @@ -0,0 +1,63 @@ +package fr.radi3nt.gltf.data.buffer; + +import fr.radi3nt.file.files.ReadableFile; +import sun.misc.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class GlTFBuffer { + + private final ReadableFile readableFile; + private final long byteLength; + + public GlTFBuffer(ReadableFile readableFile, long byteLength) { + this.readableFile = readableFile; + this.byteLength = byteLength; + } + + public ByteBuffer read(long offset, int length) { + try { + return tryReading(offset, length); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private ByteBuffer tryReading(long offset, int length) throws IOException { + InputStream inputStream = readableFile.getInputStream(); + long totalSkipped = 0; + while (totalSkipped < offset) { + totalSkipped+=inputStream.skip(offset -totalSkipped); + } + byte[] bytes = IOUtils.readNBytes(inputStream, length); + inputStream.close(); + + ByteBuffer wrap = ByteBuffer.wrap(bytes); + wrap.order(ByteOrder.LITTLE_ENDIAN); + return wrap; + } + + public void read(long offset, int length, ByteBuffer resultBuff) { + try { + tryReading(offset, length, resultBuff); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + private void tryReading(long offset, int length, ByteBuffer result) throws IOException { + InputStream inputStream = readableFile.getInputStream(); + long totalSkipped = 0; + while (totalSkipped < offset) { + totalSkipped+=inputStream.skip(offset -totalSkipped); + } + byte[] bytes = IOUtils.readNBytes(inputStream, length); + inputStream.close(); + + result.put(bytes); + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java new file mode 100644 index 0000000..c878c20 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java @@ -0,0 +1,47 @@ +package fr.radi3nt.gltf.data.buffer.accessor; + +import fr.radi3nt.gltf.data.GlTFResult; + +import java.nio.ByteBuffer; + +public class BufferAccessor { + + private final int bufferView; + private final GlTFComponentType componentType; + private final GlTFAccessorType type; + private final int count; + + private final float[] min; + private final float[] max; + + public BufferAccessor(int bufferView, GlTFComponentType componentType, GlTFAccessorType type, int count, float[] min, float[] max) { + this.bufferView = bufferView; + this.componentType = componentType; + this.type = type; + this.count = count; + this.min = min; + this.max = max; + } + + public ByteBuffer getBuffer(GlTFResult result) { + ByteBuffer buffer = result.bufferViews[bufferView].getBuffer(result); + buffer.limit(getByteSize()); + return buffer; + } + + public void getBuffer(GlTFResult result, ByteBuffer buffer) { + result.bufferViews[bufferView].getBuffer(result, buffer); + } + + public GlTFAccessorType getType() { + return type; + } + + public int getByteSize() { + return count*type.amount()*componentType.bytes(); + } + + public int getCount() { + return count; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java new file mode 100644 index 0000000..deb79ee --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java @@ -0,0 +1,19 @@ +package fr.radi3nt.gltf.data.buffer.accessor; + +public enum GlTFAccessorType { + + SCALAR(1), + VEC3(3), + VEC4(4), + MAT4(16); + + private final int amount; + + GlTFAccessorType(int amount) { + this.amount = amount; + } + + public int amount() { + return amount; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java new file mode 100644 index 0000000..b76333c --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java @@ -0,0 +1,29 @@ +package fr.radi3nt.gltf.data.buffer.accessor; + +public enum GlTFComponentType { + + GL_FLOAT(5126, 4), + GL_UNSIGNED_BYTE(5121, 1), + GL_UNSIGNED_SHORT(5123, 2), + + ; + + private final int id; + private final int bytes; + + GlTFComponentType(int id, int bytes) { + this.id = id; + this.bytes = bytes; + } + + public static GlTFComponentType fromId(int componentType) { + for (GlTFComponentType value : values()) { + if (value.id==componentType) return value; + } + return null; + } + + public int bytes() { + return bytes; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java new file mode 100644 index 0000000..c0698c1 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java @@ -0,0 +1,30 @@ +package fr.radi3nt.gltf.data.buffer.view; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.buffer.GlTFBuffer; + +import java.nio.ByteBuffer; + +public class BufferView { + + private final int buffer; + private final int length; + private final long offset; + + public BufferView(int buffer, int length, long offset) { + this.buffer = buffer; + this.length = length; + this.offset = offset; + } + + public ByteBuffer getBuffer(GlTFResult result) { + GlTFBuffer currentBuffer = result.buffers[buffer]; + + return currentBuffer.read(offset, length); + } + + public void getBuffer(GlTFResult result, ByteBuffer resultBuff) { + GlTFBuffer currentBuffer = result.buffers[buffer]; + currentBuffer.read(offset, length, resultBuff); + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java new file mode 100644 index 0000000..149b5f1 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java @@ -0,0 +1,20 @@ +package fr.radi3nt.gltf.data.mesh; + +public class GlTFMesh { + + private final String name; + private final Primitive[] primitives; + + public GlTFMesh(String name, Primitive[] primitives) { + this.name = name; + this.primitives = primitives; + } + + public String getName() { + return name; + } + + public Primitive[] getPrimitives() { + return primitives; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java new file mode 100644 index 0000000..c2609a9 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java @@ -0,0 +1,59 @@ +package fr.radi3nt.gltf.data.mesh; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.attributes.GlTFAttribute; +import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor; +import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial; + +import java.nio.ByteBuffer; +import java.util.Map; + +public class Primitive { + + private final Map attributesToAccessors; + private final int indicesAccessor; + private final int materialSlot; + + public Primitive(Map attributesToAccessors, int indicesAccessor, int materialSlot) { + this.attributesToAccessors = attributesToAccessors; + this.indicesAccessor = indicesAccessor; + this.materialSlot = materialSlot; + } + + public ByteBuffer get(GlTFAttribute attributes, GlTFResult result) { + BufferAccessor bufferAccessor = getAccessor(attributes, result); + return bufferAccessor.getBuffer(result); + } + + public void get(GlTFAttribute attributes, GlTFResult result, ByteBuffer buffer) { + getAccessor(attributes, result).getBuffer(result, buffer); + } + + public int getByteSize(GlTFAttribute attribute, GlTFResult result) { + BufferAccessor bufferAccessor = getAccessor(attribute, result); + return bufferAccessor.getByteSize(); + } + + public int getCount(GlTFAttribute attribute, GlTFResult result) { + BufferAccessor bufferAccessor = getAccessor(attribute, result); + return bufferAccessor.getCount(); + } + + private BufferAccessor getAccessor(GlTFAttribute attribute, GlTFResult result) { + int accessor = attributesToAccessors.get(attribute); + return result.bufferAccessors[accessor]; + } + + public ByteBuffer getIndices(GlTFResult result) { + return result.bufferAccessors[indicesAccessor].getBuffer(result); + } + + public int getCount(GlTFResult result) { + return result.bufferAccessors[indicesAccessor].getCount(); + } + + public GlTFMaterial getMaterial(GlTFResult result) { + return result.materials[materialSlot]; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java new file mode 100644 index 0000000..77369e4 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java @@ -0,0 +1,14 @@ +package fr.radi3nt.gltf.data.mesh.material; + +public class GlTFMaterial { + + private final String name; + + public GlTFMaterial(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java new file mode 100644 index 0000000..883fb3a --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java @@ -0,0 +1,9 @@ +package fr.radi3nt.gltf.data.mesh.material; + +import fr.radi3nt.gltf.data.GlTFResult; + +public interface GlTFMaterialIndexer { + + int getIndex(GlTFMaterial material, GlTFResult result); + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java new file mode 100644 index 0000000..76c10a6 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java @@ -0,0 +1,29 @@ +package fr.radi3nt.gltf.data.scene; + +import fr.radi3nt.gltf.data.GlTFResult; + +public class GlTFAbstractNode { + + private final String name; + private final int[] children; + + public GlTFAbstractNode(String name, int[] children) { + this.name = name; + this.children = children; + } + + public String getName() { + return name; + } + + public GlTFNode[] getChildren(GlTFResult result) { + if (this.children==null) + return new GlTFNode[0]; + + GlTFNode[] children = new GlTFNode[this.children.length]; + for (int i = 0; i < children.length; i++) { + children[i] = result.nodes[this.children[i]]; + } + return children; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java new file mode 100644 index 0000000..fa680ec --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java @@ -0,0 +1,39 @@ +package fr.radi3nt.gltf.data.scene; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.mesh.GlTFMesh; +import fr.radi3nt.gltf.data.skins.GlTFSkin; + +public class GlTFNode extends GlTFAbstractNode { + + private final GlTFTransform localTransform; + + private final int meshIndex; + private final int skinIndex; + + public GlTFNode(String name, int[] children, GlTFTransform localTransform, int meshIndex, int skinIndex) { + super(name, children); + this.localTransform = localTransform; + this.meshIndex = meshIndex; + this.skinIndex = skinIndex; + } + + public GlTFTransform getLocalTransform() { + return localTransform; + } + + public GlTFMesh getMesh(GlTFResult result) { + if (meshIndex==-1) + return null; + return result.meshes[meshIndex]; + } + + public int getMeshIndex() { + return meshIndex; + } + + public GlTFSkin getSkin(GlTFResult result) { + return result.skins[skinIndex]; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java new file mode 100644 index 0000000..577da9c --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java @@ -0,0 +1,8 @@ +package fr.radi3nt.gltf.data.scene; + +public class GlTFScene extends GlTFAbstractNode { + + public GlTFScene(String name, int[] children) { + super(name, children); + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java new file mode 100644 index 0000000..3d6353e --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java @@ -0,0 +1,97 @@ +package fr.radi3nt.gltf.data.scene; + +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; +import fr.radi3nt.json.JsonValue; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +import java.util.function.Supplier; + +public class GlTFTransform { + + private final Vector3f translation; + private final Quaternion rotation; + private final Vector3f scale; + + public GlTFTransform(Vector3f translation, Quaternion rotation, Vector3f scale) { + this.translation = translation; + this.rotation = rotation; + this.scale = scale; + } + + public Matrix4x4 toMatrix() { + Matrix4x4 result = ArrayMatrix4x4.newIdentity(); + result.quaternionRotation(rotation); + result.translation(translation); + result.scalar(scale); + return result; + } + + public Vector3f transform(Vector3f original) { + Vector3f result = original.duplicate(); + result.mul(scale); + rotation.transform(result); + result.add(translation); + return result; + } + + public Vector3f transformOrientation(Vector3f original) { + Vector3f result = original.duplicate(); + rotation.transform(result); + return result; + } + + public Vector3f getTranslation() { + return translation; + } + + public Quaternion getRotation() { + return rotation; + } + + public Vector3f getScale() { + return scale; + } + + public static GlTFTransform parse(JsonObject nodeJson) { + Vector3f translation = parseTranslation(nodeJson); + Quaternion rotation = parseRotation(nodeJson); + Vector3f scale = parseScale(nodeJson); + + return new GlTFTransform(translation, rotation, scale); + } + + private static Vector3f parseScale(JsonObject nodeJson) { + JsonValue value = nodeJson.get("scale"); + return parseVector(value, () -> new SimpleVector3f(1f, 1f, 1f)); + } + + private static Quaternion parseRotation(JsonObject nodeJson) { + JsonValue value = nodeJson.get("rotation"); + if (value == null) { + return ComponentsQuaternion.zero(); + } + + JsonArray valueArray = value.asArray(); + return new ComponentsQuaternion(valueArray.get(0).asFloat(), valueArray.get(1).asFloat(), valueArray.get(2).asFloat(), valueArray.get(3).asFloat()); + } + + private static Vector3f parseTranslation(JsonObject nodeJson) { + JsonValue value = nodeJson.get("translation"); + return parseVector(value, SimpleVector3f::new); + } + + private static Vector3f parseVector(JsonValue value, Supplier defaultVec) { + if (value == null) { + return defaultVec.get(); + } + + JsonArray valueArray = value.asArray(); + return new SimpleVector3f(valueArray.get(0).asFloat(), valueArray.get(1).asFloat(), valueArray.get(2).asFloat()); + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java b/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java new file mode 100644 index 0000000..0c52693 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java @@ -0,0 +1,50 @@ +package fr.radi3nt.gltf.data.skins; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.scene.GlTFNode; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +import java.nio.ByteBuffer; + +public class GlTFSkin { + + private final String name; + private final int inverseBindMatricesAccessorIndex; + private final int[] joints; + + public GlTFSkin(String name, int inverseBindMatricesAccessorIndex, int[] joints) { + this.name = name; + this.inverseBindMatricesAccessorIndex = inverseBindMatricesAccessorIndex; + this.joints = joints; + } + + public String getName() { + return name; + } + + public GlTFNode[] getJoints(GlTFResult result) { + GlTFNode[] nodes = new GlTFNode[joints.length]; + for (int i = 0; i < joints.length; i++) { + nodes[i] = result.nodes[joints[i]]; + } + return nodes; + } + + public Matrix4x4[] getInverseBindMatrices(GlTFResult result) { + ByteBuffer buffer = result.bufferAccessors[inverseBindMatricesAccessorIndex].getBuffer(result); + Matrix4x4[] matrices = new Matrix4x4[joints.length]; + for (int jointIndex = 0; jointIndex < joints.length; jointIndex++) { + float[] mat = new float[4*4]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float value = buffer.getFloat(); + mat[i+j*4] = value; + } + } + Matrix4x4 inverseBind = ArrayMatrix4x4.from(mat); + matrices[jointIndex] = inverseBind; + } + return matrices; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java new file mode 100644 index 0000000..222f6c4 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java @@ -0,0 +1,58 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor; +import fr.radi3nt.gltf.data.buffer.accessor.GlTFAccessorType; +import fr.radi3nt.gltf.data.buffer.accessor.GlTFComponentType; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; +import fr.radi3nt.json.JsonValue; + +public class AccessorsImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + + JsonArray accessorsJson = file.get("accessors").asArray(); + BufferAccessor[] accessors = new BufferAccessor[accessorsJson.size()]; + for (int i = 0; i < accessors.length; i++) { + JsonObject accessorJson = accessorsJson.get(i).asObject(); + int bufferView = accessorJson.getInt("bufferView", -1); + GlTFComponentType componentType = GlTFComponentType.fromId(accessorJson.getInt("componentType", -1)); + int count = accessorJson.getInt("count", 0); + GlTFAccessorType accessorType = GlTFAccessorType.valueOf(accessorJson.getString("type")); + + float[] min = getMin(accessorJson); + float[] max = getMax(accessorJson); + + accessors[i] = new BufferAccessor(bufferView, componentType, accessorType, count, min, max); + } + + result.bufferAccessors = accessors; + } + + private float[] getMin(JsonObject accessorJson) { + JsonValue value = accessorJson.get("min"); + if (value==null) + return null; + + return parseArray(value); + } + + private float[] getMax(JsonObject accessorJson) { + JsonValue value = accessorJson.get("max"); + if (value==null) + return null; + + return parseArray(value); + } + + private static float[] parseArray(JsonValue value) { + JsonArray array = value.asArray(); + float[] floats = new float[array.size()]; + for (int i = 0; i < array.size(); i++) { + floats[i] = array.get(i).asFloat(); + } + return floats; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java new file mode 100644 index 0000000..2cbc8b6 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java @@ -0,0 +1,33 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.file.files.ReadableFile; +import fr.radi3nt.file.impl.ResourceFile; +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.buffer.GlTFBuffer; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; + +public class BuffersImporter implements GlTFImporter { + + private final String basePath; + + public BuffersImporter(String basePath) { + this.basePath = basePath; + } + + public void parse(JsonObject file, GlTFResult result) { + + JsonArray buffersJson = file.get("buffers").asArray(); + GlTFBuffer[] buffers = new GlTFBuffer[buffersJson.size()]; + for (int i = 0; i < buffersJson.size(); i++) { + JsonObject bufferJson = buffersJson.get(i).asObject(); + long byteLength = bufferJson.getLong("byteLength", 0); + ReadableFile uri = new ResourceFile(basePath + "/" + bufferJson.getString("uri")); + buffers[i] = new GlTFBuffer(uri, byteLength); + } + + result.buffers = buffers; + + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java new file mode 100644 index 0000000..94d8b44 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java @@ -0,0 +1,10 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.json.JsonObject; + +public interface GlTFImporter { + + void parse(JsonObject file, GlTFResult result); + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java new file mode 100644 index 0000000..923965c --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java @@ -0,0 +1,23 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; + +public class MaterialsImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + + JsonArray materialsJson = file.get("materials").asArray(); + GlTFMaterial[] materials = new GlTFMaterial[materialsJson.size()]; + for (int i = 0; i < materialsJson.size(); i++) { + JsonObject materialJson = materialsJson.get(i).asObject(); + String name = materialJson.getString("name", "unnamed"); + materials[i] = new GlTFMaterial(name); + } + + result.materials = materials; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java new file mode 100644 index 0000000..9041c8a --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java @@ -0,0 +1,46 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.attributes.GlTFAttribute; +import fr.radi3nt.gltf.data.mesh.GlTFMesh; +import fr.radi3nt.gltf.data.mesh.Primitive; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; + +import java.util.HashMap; +import java.util.Map; + +public class MeshesImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + JsonArray meshesJson = file.get("meshes").asArray(); + GlTFMesh[] meshes = new GlTFMesh[meshesJson.size()]; + for (int i = 0; i < meshesJson.size(); i++) { + JsonObject meshJson = meshesJson.get(i).asObject(); + String name = meshJson.getString("name", "unnamed"); + + JsonArray primitivesJson = meshJson.get("primitives").asArray(); + Primitive[] primitives = new Primitive[primitivesJson.size()]; + for (int j = 0; j < primitivesJson.size(); j++) { + JsonObject primitiveJson = primitivesJson.get(j).asObject(); + JsonObject attributes = primitiveJson.get("attributes").asObject(); + Map attributesMap = new HashMap<>(); + for (JsonObject.Member attribute : attributes) { + GlTFAttribute glTFAttribute = GlTFAttribute.valueOf(attribute.getName()); + int accessorIndex = attribute.getValue().asInt(); + attributesMap.put(glTFAttribute, accessorIndex); + } + + int indicesIndex = primitiveJson.getInt("indices", -1); + int material = primitiveJson.getInt("material", -1); + + primitives[j] = new Primitive(attributesMap, indicesIndex, material); + } + + meshes[i] = new GlTFMesh(name, primitives); + } + + result.meshes = meshes; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java new file mode 100644 index 0000000..3d2bb5d --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java @@ -0,0 +1,44 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.scene.GlTFNode; +import fr.radi3nt.gltf.data.scene.GlTFTransform; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; +import fr.radi3nt.json.JsonValue; + +public class NodesImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + JsonArray nodesJsonArray = file.get("nodes").asArray(); + GlTFNode[] nodes = new GlTFNode[nodesJsonArray.size()]; + for (int i = 0; i < nodesJsonArray.size(); i++) { + JsonObject nodeJson = nodesJsonArray.get(i).asObject(); + + String name = nodeJson.getString("name", "undefined"); + int meshIndex = nodeJson.getInt("mesh", -1); + int skinIndex = nodeJson.getInt("skin", -1); + + int[] children = getChildrenOrNull(nodeJson); + GlTFTransform transform = GlTFTransform.parse(nodeJson); + + nodes[i] = new GlTFNode(name, children, transform, meshIndex, skinIndex); + } + + result.nodes = nodes; + } + + private static int[] getChildrenOrNull(JsonObject nodeJson) { + JsonValue childrenJson = nodeJson.get("children"); + if (childrenJson == null) { + return null; + } + JsonArray childrenJsonArray = childrenJson.asArray(); + int[] children = new int[childrenJsonArray.size()]; + for (int j = 0; j < childrenJsonArray.size(); j++) { + children[j] = childrenJsonArray.get(j).asInt(); + } + return children; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java new file mode 100644 index 0000000..7cadc94 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java @@ -0,0 +1,29 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.scene.GlTFScene; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; + +public class ScenesImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + JsonArray scenesJson = file.get("scenes").asArray(); + GlTFScene[] scenes = new GlTFScene[scenesJson.size()]; + for (int i = 0; i < scenesJson.size(); i++) { + JsonObject sceneJson = scenesJson.get(i).asObject(); + String sceneName = sceneJson.asObject().getString("name"); + JsonArray nodesJson = sceneJson.asObject().get("nodes").asArray(); + int[] nodes = new int[nodesJson.size()]; + for (int j = 0; j < nodesJson.size(); j++) { + nodes[j] = nodesJson.get(j).asInt(); + } + + GlTFScene currentScene = new GlTFScene(sceneName, nodes); + scenes[i] = currentScene; + } + + result.scenes = scenes; + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java new file mode 100644 index 0000000..9e93d01 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java @@ -0,0 +1,39 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.skins.GlTFSkin; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; +import fr.radi3nt.json.JsonValue; + +public class SkinsImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + + JsonValue skinsValue = file.get("skins"); + if (skinsValue==null) + return; + JsonArray skinsJson = skinsValue.asArray(); + + GlTFSkin[] skins = new GlTFSkin[skinsJson.size()]; + for (int i = 0; i < skins.length; i++) { + JsonObject skinJson = skinsJson.get(i).asObject(); + + String name = skinJson.getString("name", "unnamed"); + + JsonArray jointsJson = skinJson.get("joints").asArray(); + int[] joints = new int[jointsJson.size()]; + for (int j = 0; j < joints.length; j++) { + joints[j] = jointsJson.get(j).asInt(); + } + + int inverseBindMatrixAccessorIndex = skinJson.get("inverseBindMatrices").asInt(); + + skins[i] = new GlTFSkin(name, inverseBindMatrixAccessorIndex, joints); + } + + result.skins = skins; + + } + +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java new file mode 100644 index 0000000..bbc44c7 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java @@ -0,0 +1,26 @@ +package fr.radi3nt.gltf.importer; + +import fr.radi3nt.gltf.data.GlTFResult; +import fr.radi3nt.gltf.data.buffer.view.BufferView; +import fr.radi3nt.json.JsonArray; +import fr.radi3nt.json.JsonObject; + +public class ViewImporter implements GlTFImporter { + + public void parse(JsonObject file, GlTFResult result) { + + JsonArray bufferViewsJson = file.get("bufferViews").asArray(); + BufferView[] bufferViews = new BufferView[bufferViewsJson.size()]; + for (int i = 0; i < bufferViewsJson.size(); i++) { + JsonObject viewJson = bufferViewsJson.get(i).asObject(); + int buffer = viewJson.getInt("buffer", -1); + int byteLength = viewJson.getInt("byteLength", 0); + long byteOffset = viewJson.getLong("byteOffset", 0); + bufferViews[i] = new BufferView(buffer, byteLength, byteOffset); + } + + result.bufferViews = bufferViews; + + } + +} diff --git a/pom.xml b/pom.xml index 0bbb57d..1d6fb8c 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,7 @@ Pathfinding AnimationsImport Animations + glTF From ca56bef424383a4be050ba6a2beb905b94ced3b4 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:17:43 +0200 Subject: [PATCH 088/125] Added Armature module --- Armature/pom.xml | 34 +++++++++ .../radi3nt/armatures/armature/Armature.java | 15 ++++ .../armatures/armature/ListArmature.java | 56 ++++++++++++++ .../radi3nt/armatures/armature/bone/Bone.java | 20 +++++ .../armatures/armature/bone/ParentBone.java | 74 +++++++++++++++++++ .../armatures/armature/driver/BoneDriver.java | 16 ++++ .../armature/driver/BoneRestData.java | 39 ++++++++++ .../armature/driver/ParentedBoneDriver.java | 63 ++++++++++++++++ .../driver/WorldIndependentBoneDriver.java | 60 +++++++++++++++ .../driver/WorldRestedBoneDriver.java | 54 ++++++++++++++ .../armature/weights/BoneWeight.java | 24 ++++++ .../ArmatureAnimationController.java | 36 +++++++++ .../controller/ArmatureController.java | 29 ++++++++ pom.xml | 1 + 14 files changed, 521 insertions(+) create mode 100644 Armature/pom.xml create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/Armature.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/weights/BoneWeight.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java diff --git a/Armature/pom.xml b/Armature/pom.xml new file mode 100644 index 0000000..df1dd86 --- /dev/null +++ b/Armature/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + fr.radi3nt + JavaUtil + 1.0 + + + Armature + + + 8 + 8 + UTF-8 + + + + fr.radi3nt + MathsHelper + 1.0 + compile + + + fr.radi3nt + Animations + 1.0 + compile + + + + \ No newline at end of file diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/Armature.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/Armature.java new file mode 100644 index 0000000..70366df --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/Armature.java @@ -0,0 +1,15 @@ +package fr.radi3nt.armatures.armature; + +import fr.radi3nt.armatures.armature.bone.Bone; + +import java.nio.ByteBuffer; +import java.util.Collection; + +public interface Armature { + + void encode(ByteBuffer byteBuffer); + + Collection getRoots(); + int getBoneCount(); + +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java new file mode 100644 index 0000000..bc709f6 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java @@ -0,0 +1,56 @@ +package fr.radi3nt.armatures.armature; + +import fr.radi3nt.armatures.armature.bone.Bone; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; + +public class ListArmature implements Armature { + + private final Collection rootBones = new ArrayList<>(); + private final Matrix4x4 armatureTransform; + private final Bone[] bonesIds; + + public ListArmature(Matrix4x4 armatureTransform, Bone[] bonesIds, Collection roots) { + this.armatureTransform = armatureTransform; + this.bonesIds = bonesIds; + this.rootBones.addAll(roots); + } + + @Override + public void encode(ByteBuffer byteBuffer) { + for (Bone bonesId : bonesIds) { + writeMatrix(byteBuffer, bonesId.getJointTransform()); + } + } + + private void writeMatrix(ByteBuffer byteBuffer, Matrix4x4 worldSpaceTransform) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + byteBuffer.putFloat(worldSpaceTransform.get(i, j)); + } + } + } + + public void update() { + for (Bone rootBone : rootBones) { + rootBone.update(armatureTransform); + } + } + + public Matrix4x4 getArmatureTransform() { + return armatureTransform; + } + + @Override + public Collection getRoots() { + return rootBones; + } + + @Override + public int getBoneCount() { + return bonesIds.length; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java new file mode 100644 index 0000000..4bc3d4e --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java @@ -0,0 +1,20 @@ +package fr.radi3nt.armatures.armature.bone; + +import fr.radi3nt.armatures.armature.driver.BoneDriver; +import fr.radi3nt.armatures.armature.driver.BoneRestData; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public interface Bone { + + void update(Matrix4x4 parentModelSpace); + + void setBoneDriver(BoneDriver boneDriver); + + BoneRestData getBoneRestData(); + + BoneDriver getBoneDriver(); + + Matrix4x4 getWorldTransform(); + Matrix4x4 getJointTransform(); + +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java new file mode 100644 index 0000000..9617b03 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java @@ -0,0 +1,74 @@ +package fr.radi3nt.armatures.armature.bone; + +import fr.radi3nt.armatures.armature.driver.BoneDriver; +import fr.radi3nt.armatures.armature.driver.BoneRestData; +import fr.radi3nt.armatures.armature.driver.ParentedBoneDriver; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +import java.util.ArrayList; +import java.util.Collection; + +public class ParentBone implements Bone { + + private final Matrix4x4 jointSpaceTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 modelSpaceTransform = ArrayMatrix4x4.newIdentity(); + + private final Matrix4x4 worldInverseBindTransform; + private final BoneRestData boneRestData; + + private BoneDriver boneDriver; + + public final Collection children = new ArrayList<>(); + + public ParentBone(Matrix4x4 worldInverseBindTransform, BoneRestData boneRestData, Collection children) { + this.worldInverseBindTransform = worldInverseBindTransform; + this.boneRestData = boneRestData; + + this.children.addAll(children); + + boneDriver = new ParentedBoneDriver(boneRestData); + } + + @Override + public void update(Matrix4x4 parentModelSpace) { + modelSpaceTransform.copy(boneDriver.getModelSpaceTransform(parentModelSpace)); + + for (Bone child : children) { + child.update(modelSpaceTransform); + } + + jointSpaceTransform.copy(modelSpaceTransform); + jointSpaceTransform.multiply(worldInverseBindTransform); + } + + @Override + public void setBoneDriver(BoneDriver boneDriver) { + this.boneDriver = boneDriver; + } + + public Collection getChildren() { + return children; + } + + @Override + public BoneRestData getBoneRestData() { + return boneRestData; + } + + @Override + public BoneDriver getBoneDriver() { + return boneDriver; + } + + @Override + public Matrix4x4 getWorldTransform() { + return modelSpaceTransform; + } + + @Override + public Matrix4x4 getJointTransform() { + return jointSpaceTransform; + } + +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java new file mode 100644 index 0000000..1c5cb41 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java @@ -0,0 +1,16 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface BoneDriver { + + void set(Vector3f position); + void set(Quaternion quaternion); + void set(Vector3f translation, Quaternion rotation); + void set(Vector3f translate, Quaternion rotate, Vector3f scale); + + Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace); + +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java new file mode 100644 index 0000000..1b8b820 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java @@ -0,0 +1,39 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class BoneRestData { + + private final Vector3f position; + private final Quaternion rotation; + private final Vector3f scale; + + public BoneRestData(Vector3f position, Quaternion rotation, Vector3f scale) { + this.position = position; + this.rotation = rotation; + this.scale = scale; + } + + public Matrix4x4 toMatrix() { + Matrix4x4 result = ArrayMatrix4x4.newIdentity(); + result.quaternionRotation(rotation); + result.translation(position); + result.scalar(scale); + return result; + } + + public Vector3f getPosition() { + return position; + } + + public Quaternion getRotation() { + return rotation; + } + + public Vector3f getScale() { + return scale; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java new file mode 100644 index 0000000..65b7cc7 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java @@ -0,0 +1,63 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ParentedBoneDriver implements BoneDriver { + + //If you choose to export with "Transform" category checked, set that to true + private static final boolean TRANSFORM_MODE = false; + + private final Matrix4x4 resultTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 localTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 localRestTransform = ArrayMatrix4x4.newIdentity(); + + private final Vector3f translation = new SimpleVector3f(); + private final Quaternion rotation = ComponentsQuaternion.zero(); + + public ParentedBoneDriver(BoneRestData restData) { + if (TRANSFORM_MODE) { + this.translation.copy(restData.getPosition()); + this.rotation.copy(restData.getRotation()); + } else { + this.localRestTransform.copy(restData.toMatrix()); + } + } + + @Override + public void set(Vector3f position) { + this.translation.copy(position); + } + + @Override + public void set(Quaternion quaternion) { + this.rotation.copy(quaternion); + } + + @Override + public void set(Vector3f translation, Quaternion rotation) { + set(translation); + set(rotation); + } + + @Override + public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { + set(translate, rotate); //todo unsupported scale + } + + @Override + public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { + localTransform.quaternionRotation(rotation); + localTransform.translation(translation); + + resultTransform.copy(parentModelSpace); + resultTransform.multiply(localRestTransform); + resultTransform.multiply(localTransform); + + return resultTransform; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java new file mode 100644 index 0000000..84154d8 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java @@ -0,0 +1,60 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class WorldIndependentBoneDriver implements BoneDriver { + + private final Matrix4x4 resultTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 localTransform = ArrayMatrix4x4.newIdentity(); + + private final Vector3f translation = new SimpleVector3f(); + private final Quaternion rotation = ComponentsQuaternion.zero(); + + public WorldIndependentBoneDriver() { + + } + + @Override + public void set(Vector3f position) { + this.translation.copy(position); + } + + @Override + public void set(Quaternion quaternion) { + this.rotation.copy(quaternion); + } + + @Override + public void set(Vector3f translation, Quaternion rotation) { + set(translation); + set(rotation); + } + + @Override + public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { + set(translate, rotate); + } + + public Quaternion getRotation() { + return rotation; + } + + public Vector3f getTranslation() { + return translation; + } + + @Override + public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { + localTransform.quaternionRotation(getRotation()); + localTransform.translation(getTranslation()); + + resultTransform.copy(localTransform); + + return resultTransform; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java new file mode 100644 index 0000000..506a8f6 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java @@ -0,0 +1,54 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class WorldRestedBoneDriver implements BoneDriver { + + private final Matrix4x4 resultTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 localTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 localRestTransform = ArrayMatrix4x4.newIdentity(); + + private final Vector3f translation = new SimpleVector3f(); + private final Quaternion rotation = ComponentsQuaternion.zero(); + + public WorldRestedBoneDriver(BoneRestData restData) { + this.localRestTransform.copy(restData.toMatrix()); + } + + @Override + public void set(Vector3f position) { + this.translation.copy(position); + } + + @Override + public void set(Quaternion quaternion) { + this.rotation.copy(quaternion); + } + + @Override + public void set(Vector3f translation, Quaternion rotation) { + set(translation); + set(rotation); + } + + @Override + public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { + set(translate, rotate); + } + + @Override + public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { + localTransform.quaternionRotation(rotation); + localTransform.translation(translation); + + resultTransform.copy(localRestTransform); + resultTransform.multiply(localTransform); + + return resultTransform; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/weights/BoneWeight.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/weights/BoneWeight.java new file mode 100644 index 0000000..b9bd38f --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/weights/BoneWeight.java @@ -0,0 +1,24 @@ +package fr.radi3nt.armatures.armature.weights; + +public class BoneWeight { + + private final int bone; + private float weight; + + public BoneWeight(int bone, float weight) { + this.bone = bone; + this.weight = weight; + } + + public int getBoneIndex() { + return bone; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java new file mode 100644 index 0000000..1386246 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java @@ -0,0 +1,36 @@ +package fr.radi3nt.armatures.controller; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.armatures.armature.driver.BoneDriver; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public class ArmatureAnimationController { + + private final AnimationTimeline animationTimeline; + private final ArmatureController controller; + + public ArmatureAnimationController(AnimationTimeline animationTimeline, ArmatureController controller) { + this.animationTimeline = animationTimeline; + this.controller = controller; + } + + public void update() { + for (String availableObject : animationTimeline.getAvailableObjects()) { + BoneDriver driver = controller.getDriver(availableObject); + if (driver==null) { + System.err.println("Unable to find object '" + availableObject + "' referenced in the animation clip, ignoring"); + continue; + } + Quaternion rotate = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.rotation(availableObject), null); + Vector3f translate = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.translation(availableObject), null); + Vector3f scale = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.scale(availableObject), null); + + if (rotate!=null) + driver.set(rotate); + if (translate!=null) + driver.set(translate); + } + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java new file mode 100644 index 0000000..9e5221c --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java @@ -0,0 +1,29 @@ +package fr.radi3nt.armatures.controller; + +import fr.radi3nt.armatures.armature.bone.Bone; +import fr.radi3nt.armatures.armature.driver.BoneDriver; + +import java.util.HashMap; +import java.util.Map; + +public class ArmatureController { + + private final Map driverMap; + + public ArmatureController(Map driverMap) { + this.driverMap = driverMap; + } + + public static ArmatureController from(Map bones) { + Map driverMap = new HashMap<>(); + for (Map.Entry entry : bones.entrySet()) { + driverMap.put(entry.getKey(), entry.getValue().getBoneDriver()); + } + return new ArmatureController(driverMap); + } + + public BoneDriver getDriver(String boneName) { + return driverMap.get(boneName); + } + +} diff --git a/pom.xml b/pom.xml index 1d6fb8c..3f1464c 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ AnimationsImport Animations glTF + Armature From 74c1d869a212ffe3af10eabe76cf33211d3091bb Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 12 Sep 2024 23:18:04 +0200 Subject: [PATCH 089/125] Added setCurrentAll() in FloatSmoothDynamics --- .../fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java index e7e0f56..7e994ee 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java @@ -65,4 +65,11 @@ public void setCurrent(float currentLocalPos) { public void setCurrentBypass(float currentLocalPos) { response = currentLocalPos; } + + public void setCurrentAll(float currentLocalPos, float responseDerivative) { + response = currentLocalPos; + inputCurrent = currentLocalPos; + inputPrevious = currentLocalPos; + this.responseDerivative = responseDerivative; + } } From e9b20ec6a5d7dc8dc9ca8aac8a7759d0e4ece962 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 22 Sep 2024 18:47:31 +0200 Subject: [PATCH 090/125] Removed sun import --- .../radi3nt/gltf/data/buffer/GlTFBuffer.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java index 3dcdade..0ed7d6c 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java @@ -1,7 +1,6 @@ package fr.radi3nt.gltf.data.buffer; import fr.radi3nt.file.files.ReadableFile; -import sun.misc.IOUtils; import java.io.IOException; import java.io.InputStream; @@ -32,7 +31,7 @@ private ByteBuffer tryReading(long offset, int length) throws IOException { while (totalSkipped < offset) { totalSkipped+=inputStream.skip(offset -totalSkipped); } - byte[] bytes = IOUtils.readNBytes(inputStream, length); + byte[] bytes = readNBytes(inputStream, length); inputStream.close(); ByteBuffer wrap = ByteBuffer.wrap(bytes); @@ -55,9 +54,24 @@ private void tryReading(long offset, int length, ByteBuffer result) throws IOExc while (totalSkipped < offset) { totalSkipped+=inputStream.skip(offset -totalSkipped); } - byte[] bytes = IOUtils.readNBytes(inputStream, length); + byte[] bytes = readNBytes(inputStream, length); inputStream.close(); result.put(bytes); } + + + private byte[] readNBytes(InputStream stream, int length) { + byte[] bytes = new byte[length]; + + int readBytes = 0; + while (readBytes < length) { + try { + readBytes+=stream.read(bytes, readBytes, length-readBytes); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return bytes; + } } From 03b51d2d9d55aebdd141d178ef773fab1802b03d Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 22 Sep 2024 18:48:11 +0200 Subject: [PATCH 091/125] Fixed typo in JavaMathAngle --- .../maths/components/advanced/matrix/angle/JavaMathAngle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java index 211e4b5..6fb89aa 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/angle/JavaMathAngle.java @@ -3,7 +3,7 @@ public class JavaMathAngle implements Angle { public static final Angle POSITIVE_RIGHT_ANGLE = JavaMathAngle.fromDegree(90); - public static final Angle NEAGTIVE_RIGHT_ANGLE = JavaMathAngle.fromDegree(-90); + public static final Angle NEGATIVE_RIGHT_ANGLE = JavaMathAngle.fromDegree(-90); private double angleValueInRadiant; From 8de79adce8fc107760b935bc197d79a13ee3bba1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 22 Sep 2024 18:49:02 +0200 Subject: [PATCH 092/125] Added getTranslation() and getRotation() to WorldRestedBoneDriver --- .../armature/driver/WorldRestedBoneDriver.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java index 506a8f6..8ec4866 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java @@ -41,10 +41,18 @@ public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { set(translate, rotate); } + public Vector3f getTranslation() { + return translation; + } + + public Quaternion getRotation() { + return rotation; + } + @Override public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { - localTransform.quaternionRotation(rotation); - localTransform.translation(translation); + localTransform.quaternionRotation(getRotation()); + localTransform.translation(getTranslation()); resultTransform.copy(localRestTransform); resultTransform.multiply(localTransform); From 458ef0fc70c8615f2c56cc1bd5613bbd0ec0c148 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Sun, 22 Sep 2024 18:49:34 +0200 Subject: [PATCH 093/125] Made it easier to calculate relative local transforms --- .../armatures/armature/driver/BoneRestData.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java index 1b8b820..16fba82 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java @@ -17,6 +17,10 @@ public BoneRestData(Vector3f position, Quaternion rotation, Vector3f scale) { this.scale = scale; } + public static BoneRestData fromMatrix(Matrix4x4 matrix) { + return new BoneRestData(matrix.getTranslation(), matrix.getRotation(), matrix.getScale()); + } + public Matrix4x4 toMatrix() { Matrix4x4 result = ArrayMatrix4x4.newIdentity(); result.quaternionRotation(rotation); @@ -36,4 +40,10 @@ public Quaternion getRotation() { public Vector3f getScale() { return scale; } + + public BoneRestData child(BoneRestData child) { + Matrix4x4 matrix4x4 = toMatrix(); + matrix4x4.multiply(child.toMatrix()); + return BoneRestData.fromMatrix(matrix4x4); + } } From 235171309cad45b1c76686727b5fd1914eb7bd75 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 1 Jan 2025 13:13:40 +0100 Subject: [PATCH 094/125] Fixed ambiguity in FileHelper --- .../java/fr/radi3nt/file/util/RecursiveResourceVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java b/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java index 46ae6f5..36d58df 100644 --- a/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java +++ b/FileHelper/src/main/java/fr/radi3nt/file/util/RecursiveResourceVisitor.java @@ -12,7 +12,7 @@ public static void consume(VisitorSupplier consumer, Class cls, String root) if (location.getProtocol().equals("file")) { Path path = Paths.get(location.toURI()); if (location.getPath().endsWith(".jar")) { - try (FileSystem fs = FileSystems.newFileSystem(path, null)) { + try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) { walkTree(consumer, fs.getPath("/" + root)); } } else { From 83928cd082bf39b48d9b921acc8586e06c56b40c Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:30:33 +0200 Subject: [PATCH 095/125] Now allowing custom gltf attributes --- .../java/fr/radi3nt/gltf/GltfAllImporter.java | 14 ++++++++++---- .../data/attributes/EnumGLTFAttribute.java | 18 ++++++++++++++++++ .../gltf/data/attributes/GlTFAttribute.java | 7 ++----- .../data/attributes/StringGLTFAttribute.java | 15 +++++++++++++++ .../data/buffer/accessor/BufferAccessor.java | 8 ++++++++ .../fr/radi3nt/gltf/data/mesh/Primitive.java | 18 +++++++++++++++--- .../gltf/importer/MaterialsImporter.java | 2 ++ .../radi3nt/gltf/importer/MeshesImporter.java | 6 +++--- 8 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java create mode 100644 glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java diff --git a/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java index 47ab73e..cb19733 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java @@ -13,8 +13,14 @@ public class GltfAllImporter { + public GlTFResult importFile(String fullPath) throws IOException { + int last = fullPath.lastIndexOf("/"); + String path = fullPath.substring(0, last); + String name = fullPath.substring(last+1); + return importFile(path, name); + } - public GlTFResult importFile(String filePath, String fileName) throws IOException { + public GlTFResult importFile(String parent, String fileName) throws IOException { GlTFResult result = new GlTFResult(); @@ -28,10 +34,10 @@ public GlTFResult importFile(String filePath, String fileName) throws IOExceptio importers.add(new SkinsImporter()); importers.add(new ViewImporter()); } - importers.add(new BuffersImporter(filePath)); + importers.add(new BuffersImporter(parent)); - JsonValue parsed = Json.parse(new InputStreamReader(new ResourceFile(filePath + "/" + fileName).getInputStream())); - importers.parallelStream().forEach(importer -> {importer.parse(parsed.asObject(), result);}); + JsonValue parsed = Json.parse(new InputStreamReader(new ResourceFile(parent + "/" + fileName).getInputStream())); + importers.parallelStream().forEach(importer -> importer.parse(parsed.asObject(), result)); return result; } diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java new file mode 100644 index 0000000..cde325b --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java @@ -0,0 +1,18 @@ +package fr.radi3nt.gltf.data.attributes; + +public enum EnumGLTFAttribute implements GlTFAttribute { + + POSITION, + NORMAL, + JOINTS_0, + JOINTS_1, + WEIGHTS_0, + WEIGHTS_1 + + ; + + @Override + public String getId() { + return name(); + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java index 0cc5a95..10699b5 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java @@ -1,10 +1,7 @@ package fr.radi3nt.gltf.data.attributes; -public enum GlTFAttribute { +public interface GlTFAttribute { - POSITION, - NORMAL, - JOINTS_0, - WEIGHTS_0 + String getId(); } diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java new file mode 100644 index 0000000..9776953 --- /dev/null +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java @@ -0,0 +1,15 @@ +package fr.radi3nt.gltf.data.attributes; + +public class StringGLTFAttribute implements GlTFAttribute { + + private final String id; + + public StringGLTFAttribute(String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } +} diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java index c878c20..37269fd 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java @@ -41,6 +41,14 @@ public int getByteSize() { return count*type.amount()*componentType.bytes(); } + public int getComponentBytes() { + return componentType.bytes(); + } + + public int getComponentCount() { + return type.amount(); + } + public int getCount() { return count; } diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java index c2609a9..1d3b41f 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java @@ -10,11 +10,11 @@ public class Primitive { - private final Map attributesToAccessors; + private final Map attributesToAccessors; private final int indicesAccessor; private final int materialSlot; - public Primitive(Map attributesToAccessors, int indicesAccessor, int materialSlot) { + public Primitive(Map attributesToAccessors, int indicesAccessor, int materialSlot) { this.attributesToAccessors = attributesToAccessors; this.indicesAccessor = indicesAccessor; this.materialSlot = materialSlot; @@ -34,13 +34,23 @@ public int getByteSize(GlTFAttribute attribute, GlTFResult result) { return bufferAccessor.getByteSize(); } + public int getComponentByte(GlTFAttribute attribute, GlTFResult result) { + BufferAccessor bufferAccessor = getAccessor(attribute, result); + return bufferAccessor.getComponentBytes(); + } + + public int getComponentCount(GlTFAttribute attribute, GlTFResult result) { + BufferAccessor bufferAccessor = getAccessor(attribute, result); + return bufferAccessor.getComponentCount(); + } + public int getCount(GlTFAttribute attribute, GlTFResult result) { BufferAccessor bufferAccessor = getAccessor(attribute, result); return bufferAccessor.getCount(); } private BufferAccessor getAccessor(GlTFAttribute attribute, GlTFResult result) { - int accessor = attributesToAccessors.get(attribute); + int accessor = attributesToAccessors.get(attribute.getId()); return result.bufferAccessors[accessor]; } @@ -53,6 +63,8 @@ public int getCount(GlTFResult result) { } public GlTFMaterial getMaterial(GlTFResult result) { + if (materialSlot==-1) + return null; return result.materials[materialSlot]; } diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java index 923965c..0cf7d41 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java @@ -8,6 +8,8 @@ public class MaterialsImporter implements GlTFImporter { public void parse(JsonObject file, GlTFResult result) { + if (file.get("materials")==null) + return; JsonArray materialsJson = file.get("materials").asArray(); GlTFMaterial[] materials = new GlTFMaterial[materialsJson.size()]; diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java index 9041c8a..48c94d7 100644 --- a/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java +++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java @@ -2,6 +2,7 @@ import fr.radi3nt.gltf.data.GlTFResult; import fr.radi3nt.gltf.data.attributes.GlTFAttribute; +import fr.radi3nt.gltf.data.attributes.StringGLTFAttribute; import fr.radi3nt.gltf.data.mesh.GlTFMesh; import fr.radi3nt.gltf.data.mesh.Primitive; import fr.radi3nt.json.JsonArray; @@ -24,11 +25,10 @@ public void parse(JsonObject file, GlTFResult result) { for (int j = 0; j < primitivesJson.size(); j++) { JsonObject primitiveJson = primitivesJson.get(j).asObject(); JsonObject attributes = primitiveJson.get("attributes").asObject(); - Map attributesMap = new HashMap<>(); + Map attributesMap = new HashMap<>(); for (JsonObject.Member attribute : attributes) { - GlTFAttribute glTFAttribute = GlTFAttribute.valueOf(attribute.getName()); int accessorIndex = attribute.getValue().asInt(); - attributesMap.put(glTFAttribute, accessorIndex); + attributesMap.put(attribute.getName(), accessorIndex); } int indicesIndex = primitiveJson.getInt("indices", -1); From 0d734e8b433e7f08c80514864f14639ad78959b1 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:32:49 +0200 Subject: [PATCH 096/125] Moved InterpolationData and SplineReader to SplineHelper module --- .../KeyframeSplitEulerXYZRotationChannel.java | 2 +- ...KeyframeSplitInterpolationDataChannel.java | 2 +- .../types/KeyframeSplitVectorChannel.java | 2 +- .../types/KeyframeTranslateChannel.java | 2 +- .../anim/AnimFormatAnimationImporter.java | 10 +-- .../FailureSafeAnimationBodyBuilder.java | 17 +++-- .../anim/animation/data/AnimData.java | 2 +- .../animation/spline/KeyedSplineBuilder.java | 12 ---- .../radi3nt/spline/imports/SplineReader.java | 69 +++++++++++++++++++ .../spline/imports}/key/CurveHandleData.java | 2 +- .../imports}/key/InterpolationType.java | 2 +- .../radi3nt/spline/imports}/key/KeyData.java | 24 +++---- .../spline/imports}/key/KeyframesData.java | 2 +- .../spline/BezierKeyedSplineBuilder.java | 58 +++++++++------- .../spline/CurveHandleDataBuilder.java | 6 +- .../imports/spline/KeyedSplineBuilder.java | 12 ++++ .../spline/handle/AutoHandleDataBuilder.java | 2 +- .../spline/handle/FixedHandleDataBuilder.java | 8 +-- .../handle/GeneratedHandleDataBuilder.java | 24 +++---- .../EasingInterpolationData.java | 2 +- .../interpolation/InterpolationData.java | 2 +- .../interpolation/PlotInterpolationData.java | 16 ++--- 22 files changed, 180 insertions(+), 98 deletions(-) delete mode 100644 AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/key/CurveHandleData.java (90%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/key/InterpolationType.java (61%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/key/KeyData.java (66%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/key/KeyframesData.java (91%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/spline/BezierKeyedSplineBuilder.java (62%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/spline/CurveHandleDataBuilder.java (55%) create mode 100644 SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/spline/handle/AutoHandleDataBuilder.java (77%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/spline/handle/FixedHandleDataBuilder.java (60%) rename {AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation => SplineHelper/src/main/java/fr/radi3nt/spline/imports}/spline/handle/GeneratedHandleDataBuilder.java (61%) rename {Animations/src/main/java/fr/radi3nt/animations/channels => SplineHelper/src/main/java/fr/radi3nt/spline}/interpolation/EasingInterpolationData.java (85%) rename {Animations/src/main/java/fr/radi3nt/animations/channels => SplineHelper/src/main/java/fr/radi3nt/spline}/interpolation/InterpolationData.java (57%) rename {Animations/src/main/java/fr/radi3nt/animations/channels => SplineHelper/src/main/java/fr/radi3nt/spline}/interpolation/PlotInterpolationData.java (85%) diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java index 29732cf..516640c 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitEulerXYZRotationChannel.java @@ -1,6 +1,6 @@ package fr.radi3nt.animations.channels.types; -import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.spline.interpolation.InterpolationData; import fr.radi3nt.maths.components.advanced.matrix.angle.JavaMathAngle; import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java index 2b8c24d..ad4697a 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitInterpolationDataChannel.java @@ -1,7 +1,7 @@ package fr.radi3nt.animations.channels.types; import fr.radi3nt.animations.channels.KeyframeChannel; -import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.spline.interpolation.InterpolationData; public abstract class KeyframeSplitInterpolationDataChannel implements KeyframeChannel { diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java index c06b008..0459c4a 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeSplitVectorChannel.java @@ -1,6 +1,6 @@ package fr.radi3nt.animations.channels.types; -import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.spline.interpolation.InterpolationData; import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; diff --git a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java index b3ae5fa..b1cdbe6 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java +++ b/Animations/src/main/java/fr/radi3nt/animations/channels/types/KeyframeTranslateChannel.java @@ -1,7 +1,7 @@ package fr.radi3nt.animations.channels.types; import fr.radi3nt.animations.channels.KeyframeChannel; -import fr.radi3nt.animations.channels.interpolation.InterpolationData; +import fr.radi3nt.spline.interpolation.InterpolationData; import fr.radi3nt.maths.components.vectors.Vector3f; public class KeyframeTranslateChannel implements KeyframeChannel { diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java index c7405ac..14841e6 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/AnimFormatAnimationImporter.java @@ -2,8 +2,8 @@ import fr.radi3nt.animations.AnimationClip; import fr.radi3nt.animations.channels.ChannelIdentifier; -import fr.radi3nt.animations.channels.interpolation.InterpolationData; -import fr.radi3nt.animations.channels.interpolation.PlotInterpolationData; +import fr.radi3nt.spline.interpolation.InterpolationData; +import fr.radi3nt.spline.interpolation.PlotInterpolationData; import fr.radi3nt.animations.channels.types.KeyframeSplitEulerXYZRotationChannel; import fr.radi3nt.animations.channels.types.KeyframeSplitInterpolationDataChannel; import fr.radi3nt.animations.channels.types.KeyframeSplitVectorChannel; @@ -57,16 +57,16 @@ public AnimationClip toClip() { for (Map.Entry channelInfoAnimDataEntry : animationBody.getAnimData().entrySet()) { AnimData value = channelInfoAnimDataEntry.getValue(); ChannelInfo key = channelInfoAnimDataEntry.getKey(); - Supplier> channelSupplier = createChanneSupplier(key); + Supplier> channelSupplier = createChannelSupplier(key); KeyframeSplitInterpolationDataChannel keyframeChannel = channels.computeIfAbsent(new ChannelIdentifier(key.getObjectName(), key.getMainChannelType()), (c) -> channelSupplier.get()); Spline2D spline = value.getKeyframesData().getDataSpline(); - keyframeChannel.getInterpolationData()[key.getAttributeInt()] = PlotInterpolationData.create(spline, duration, spline.getSegmentCount(), 0, (int) Math.nextUp(duration*POINTS_PER_SECONDS)); + keyframeChannel.getInterpolationData()[key.getAttributeInt()] = PlotInterpolationData.create(spline, duration, spline.getSegmentCount(), 0, (int) Math.ceil(duration*POINTS_PER_SECONDS), 50); } return new AnimationClip(duration, channels); } - private static Supplier> createChanneSupplier(ChannelInfo key) { + private static Supplier> createChannelSupplier(ChannelInfo key) { Supplier> channelSupplier = null; switch (key.getMainChannelType()) { case "rotate": diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java index ff3c17d..bdd3c66 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/FailureSafeAnimationBodyBuilder.java @@ -2,11 +2,11 @@ import fr.radi3nt.animations.importing.anim.animation.data.AnimData; import fr.radi3nt.animations.importing.anim.animation.data.ChannelInfo; -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyframesData; -import fr.radi3nt.animations.importing.anim.animation.spline.KeyedSplineBuilder; +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.InterpolationType; +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.imports.key.KeyframesData; +import fr.radi3nt.spline.imports.spline.KeyedSplineBuilder; import fr.radi3nt.animations.importing.anim.content.AnimFileContent; import fr.radi3nt.animations.importing.anim.header.AnimHeader; import fr.radi3nt.animations.importing.anim.units.UnitType; @@ -77,6 +77,11 @@ private static void fillAnimProperties(AnimFileContent content, Map keyData = getKeyData(content); + return new KeyframesData(keyData, splineBuilder.build(keyData, 1f/header.getTimeUnit().getFrameEquivalent())); + } + + private List getKeyData(AnimFileContent content) { List keyData = new ArrayList<>(); while (content.hasLine()) { String line = content.readLine(); @@ -102,7 +107,7 @@ private KeyframesData buildKeysData(AnimFileContent content, AnimHeader header) keyData.add(new KeyData(frameIndex, correspondingValue, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData)); } content.nextLine(); - return new KeyframesData(keyData, splineBuilder.build(keyData, header.getTimeUnit().getFrameEquivalent())); + return keyData; } private boolean stringToBool(String str) { diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java index 464a328..df2c86e 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java +++ b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/AnimData.java @@ -1,6 +1,6 @@ package fr.radi3nt.animations.importing.anim.animation.data; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyframesData; +import fr.radi3nt.spline.imports.key.KeyframesData; import fr.radi3nt.animations.importing.anim.header.AnimHeader; import fr.radi3nt.animations.importing.anim.units.AnimUnit; import fr.radi3nt.animations.importing.anim.units.UnitType; diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java b/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java deleted file mode 100644 index 1219c01..0000000 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/KeyedSplineBuilder.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.radi3nt.animations.importing.anim.animation.spline; - -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.spline.splines.dimensions.Spline2D; - -import java.util.List; - -public interface KeyedSplineBuilder { - - Spline2D build(List keys, float framesPerSeconds); - -} diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java new file mode 100644 index 0000000..9b42944 --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java @@ -0,0 +1,69 @@ +package fr.radi3nt.spline.imports; + +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.InterpolationType; +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.imports.spline.KeyedSplineBuilder; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class SplineReader { + + private final KeyedSplineBuilder splineBuilder; + + public SplineReader(KeyedSplineBuilder splineBuilder) { + this.splineBuilder = splineBuilder; + } + + public Spline2D build(BufferedReader content, float scaleX) throws IOException { + return splineBuilder.build(getKeyData(content), scaleX); + } + + private List getKeyData(BufferedReader content) throws IOException { + List keyData = new ArrayList<>(); + String line; + while ((line = content.readLine())!=null) { + line = formatLine(line); + if (line.isEmpty()) + continue; + if (line.startsWith("}")) + break; + String[] splitLine = line.split(" "); + float frameIndex = Float.parseFloat(splitLine[0]); + float correspondingValue = Float.parseFloat(splitLine[1]); + InterpolationType inInterpolation = InterpolationType.valueOf(splitLine[2].toUpperCase()); + InterpolationType outInterpolation = InterpolationType.valueOf(splitLine[3].toUpperCase()); + boolean tanLocked = stringToBool(splitLine[4]); + boolean weightLocked = stringToBool(splitLine[5]); + + int additionalDataAmount = splitLine.length-7; + int curveHandleDataAmount = Math.floorDiv(additionalDataAmount, 2); + CurveHandleData[] curveHandleData = new CurveHandleData[curveHandleDataAmount]; + for (int i = 0; i < curveHandleDataAmount; i++) { + String tanAngle = splitLine[7+i*2]; + String tanWeight = splitLine[8+i*2]; + curveHandleData[i] = new CurveHandleData(Float.parseFloat(tanAngle), Float.parseFloat(tanWeight)); + } + + keyData.add(new KeyData(frameIndex, correspondingValue, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData)); + } + return keyData; + } + + private String formatLine(String s) { + String formatted = s.trim(); + int index = formatted.lastIndexOf(";"); + if (index!=-1) + formatted = formatted.substring(0, index); + return formatted; + } + + private boolean stringToBool(String str) { + return str.equals("1"); + } + +} diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java similarity index 90% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java index 539ac72..ab5d73c 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/CurveHandleData.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java @@ -1,4 +1,4 @@ -package fr.radi3nt.animations.importing.anim.animation.data.key; +package fr.radi3nt.spline.imports.key; public class CurveHandleData { diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java similarity index 61% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java index c341957..664199b 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/InterpolationType.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java @@ -1,4 +1,4 @@ -package fr.radi3nt.animations.importing.anim.animation.data.key; +package fr.radi3nt.spline.imports.key; public enum InterpolationType { diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java similarity index 66% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java index cf047e6..8fb80f6 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyData.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java @@ -1,11 +1,11 @@ -package fr.radi3nt.animations.importing.anim.animation.data.key; +package fr.radi3nt.spline.imports.key; import java.util.Arrays; public class KeyData { - private final float frameIndex; - private final float correspondingData; + private final float x; + private final float y; private final InterpolationType inInterpolation; private final InterpolationType outInterpolation; @@ -16,9 +16,9 @@ public class KeyData { private final CurveHandleData[] curveHandleData; - public KeyData(float frameIndex, float correspondingData, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) { - this.frameIndex = frameIndex; - this.correspondingData = correspondingData; + public KeyData(float x, float y, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) { + this.x = x; + this.y = y; this.inInterpolation = inInterpolation; this.outInterpolation = outInterpolation; this.tangentLocked = tangentLocked; @@ -26,12 +26,12 @@ public KeyData(float frameIndex, float correspondingData, InterpolationType inIn this.curveHandleData = curveHandleData; } - public float getFrameIndex() { - return frameIndex; + public float getX() { + return x; } - public float getCorrespondingData() { - return correspondingData; + public float getY() { + return y; } public InterpolationType getInInterpolation() { @@ -57,8 +57,8 @@ public CurveHandleData[] getCurveHandleData() { @Override public String toString() { return "KeyData{" + - "frameIndex=" + frameIndex + - ", correspondingData=" + correspondingData + + "x=" + x + + ", y=" + y + ", inInterpolation=" + inInterpolation + ", outInterpolation=" + outInterpolation + ", tangentLocked=" + tangentLocked + diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java similarity index 91% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java index ab983e2..edab524 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/data/key/KeyframesData.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java @@ -1,4 +1,4 @@ -package fr.radi3nt.animations.importing.anim.animation.data.key; +package fr.radi3nt.spline.imports.key; import fr.radi3nt.spline.splines.dimensions.Spline2D; diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java similarity index 62% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java index ce4d270..fca7823 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/BezierKeyedSplineBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java @@ -1,11 +1,11 @@ -package fr.radi3nt.animations.importing.anim.animation.spline; - -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.InterpolationType; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.animations.importing.anim.animation.spline.handle.AutoHandleDataBuilder; -import fr.radi3nt.animations.importing.anim.animation.spline.handle.FixedHandleDataBuilder; -import fr.radi3nt.animations.importing.anim.animation.spline.handle.GeneratedHandleDataBuilder; +package fr.radi3nt.spline.imports.spline; + +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.InterpolationType; +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.imports.spline.handle.AutoHandleDataBuilder; +import fr.radi3nt.spline.imports.spline.handle.FixedHandleDataBuilder; +import fr.radi3nt.spline.imports.spline.handle.GeneratedHandleDataBuilder; import fr.radi3nt.spline.curve.Curve; import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve; import fr.radi3nt.spline.splines.CollectionSpline; @@ -30,21 +30,29 @@ public class BezierKeyedSplineBuilder implements KeyedSplineBuilder { private final Map curveHandleDataBuilderMap; + private final float offsetX; + private final float offsetY; private final float scaleX; private final float scaleY; - public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap, float scaleX, float scaleY) { + public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap, float offsetX, float offsetY, float scaleX, float scaleY) { this.curveHandleDataBuilderMap = curveHandleDataBuilderMap; + this.offsetX = offsetX; + this.offsetY = offsetY; this.scaleX = scaleX; this.scaleY = scaleY; } public static KeyedSplineBuilder newDefault(float scaleX, float scaleY) { - return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, scaleX, scaleY); + return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, 0, 0, scaleX, scaleY); + } + + public static KeyedSplineBuilder newDefault(float offsetX, float offsetY, float scaleX, float scaleY) { + return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, offsetX, offsetY, scaleX, scaleY); } @Override - public Spline2D build(List keyData, float animFrameRate) { + public Spline2D build(List keyData, float scaleX) { List xCurves = new ArrayList<>(); List yCurves = new ArrayList<>(); Spline xSpline = new CollectionSpline(xCurves); @@ -59,25 +67,25 @@ public Spline2D build(List keyData, float animFrameRate) { CurveHandleData startCurveData = curveHandleDataBuilderMap.get(startSplineType).buildStartHandleData(keyData, i, start, end); CurveHandleData endCurveData = curveHandleDataBuilderMap.get(endSplineType).buildEndHandleData(keyData, i, start, end); - float cappedStartLength = capTangentLength(end.getFrameIndex()-start.getFrameIndex(), startCurveData); - float cappedEndLength = capTangentLength(end.getFrameIndex()-start.getFrameIndex(), endCurveData); + float cappedStartLength = capTangentLength(end.getX()-start.getX(), startCurveData); + float cappedEndLength = capTangentLength(end.getX()-start.getX(), endCurveData); - float startXPointControl =(start.getFrameIndex()+calcPosX(startCurveData, cappedStartLength)); - float endXPointControl = (end.getFrameIndex()-calcPosX(endCurveData, cappedEndLength)); + float startXPointControl =(start.getX()+calcPosX(startCurveData, cappedStartLength)); + float endXPointControl = (end.getX()-calcPosX(endCurveData, cappedEndLength)); - float startYPointControl = (start.getCorrespondingData()+calcPosY(startCurveData, cappedStartLength)); - float endYPointControl = (end.getCorrespondingData()-calcPosY(endCurveData, cappedEndLength)); + float startYPointControl = (start.getY()+calcPosY(startCurveData, cappedStartLength)); + float endYPointControl = (end.getY()-calcPosY(endCurveData, cappedEndLength)); CubicBezierCurve curveX = new CubicBezierCurve(new DirectCubicBezierCurveController( - start.getFrameIndex()*scaleX/animFrameRate, - end.getFrameIndex()*scaleX/animFrameRate, - startXPointControl*scaleX/animFrameRate, - endXPointControl*scaleX/animFrameRate)); + start.getX()* this.scaleX *scaleX+offsetX, + end.getX()* this.scaleX *scaleX+offsetX, + startXPointControl* this.scaleX *scaleX+offsetX, + endXPointControl* this.scaleX *scaleX+offsetX)); CubicBezierCurve curveY = new CubicBezierCurve(new DirectCubicBezierCurveController( - start.getCorrespondingData()*scaleY, - end.getCorrespondingData()*scaleY, - startYPointControl*scaleY, - endYPointControl*scaleY)); + start.getY()*scaleY+offsetY, + end.getY()*scaleY+offsetY, + startYPointControl*scaleY+offsetY, + endYPointControl*scaleY+offsetY)); xCurves.add(curveX); yCurves.add(curveY); diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java similarity index 55% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java index bb5a544..ba1a332 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/CurveHandleDataBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java @@ -1,7 +1,7 @@ -package fr.radi3nt.animations.importing.anim.animation.spline; +package fr.radi3nt.spline.imports.spline; -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.KeyData; import java.util.List; diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java new file mode 100644 index 0000000..a967baa --- /dev/null +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java @@ -0,0 +1,12 @@ +package fr.radi3nt.spline.imports.spline; + +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.splines.dimensions.Spline2D; + +import java.util.List; + +public interface KeyedSplineBuilder { + + Spline2D build(List keys, float intervalDuration); + +} diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java similarity index 77% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java index 0083d64..10ef47d 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/AutoHandleDataBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java @@ -1,4 +1,4 @@ -package fr.radi3nt.animations.importing.anim.animation.spline.handle; +package fr.radi3nt.spline.imports.spline.handle; import fr.radi3nt.maths.components.vectors.Vector2f; diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java similarity index 60% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java index db0ea1c..c568eec 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/FixedHandleDataBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java @@ -1,8 +1,8 @@ -package fr.radi3nt.animations.importing.anim.animation.spline.handle; +package fr.radi3nt.spline.imports.spline.handle; -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.animations.importing.anim.animation.spline.CurveHandleDataBuilder; +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.imports.spline.CurveHandleDataBuilder; import java.util.List; diff --git a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java similarity index 61% rename from AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java rename to SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java index 4651cd9..96d251e 100644 --- a/AnimationsImport/src/main/java/fr/radi3nt/animations/importing/anim/animation/spline/handle/GeneratedHandleDataBuilder.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java @@ -1,8 +1,8 @@ -package fr.radi3nt.animations.importing.anim.animation.spline.handle; +package fr.radi3nt.spline.imports.spline.handle; -import fr.radi3nt.animations.importing.anim.animation.data.key.CurveHandleData; -import fr.radi3nt.animations.importing.anim.animation.data.key.KeyData; -import fr.radi3nt.animations.importing.anim.animation.spline.CurveHandleDataBuilder; +import fr.radi3nt.spline.imports.key.CurveHandleData; +import fr.radi3nt.spline.imports.key.KeyData; +import fr.radi3nt.spline.imports.spline.CurveHandleDataBuilder; import fr.radi3nt.maths.components.vectors.Vector2f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector2f; @@ -11,16 +11,16 @@ public class GeneratedHandleDataBuilder implements CurveHandleDataBuilder { @Override public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) { - Vector2f endPos = new SimpleVector2f(end.getFrameIndex(), end.getCorrespondingData()); - Vector2f beforeOnePos = new SimpleVector2f(start.getFrameIndex(), end.getCorrespondingData()); + Vector2f endPos = new SimpleVector2f(end.getX(), end.getY()); + Vector2f beforeOnePos = new SimpleVector2f(start.getX(), end.getY()); float closeness = 0.5f; float lengthMultiplier = 2; if (i!=0) { lengthMultiplier = 1f; KeyData startBefore = keyData.get(i-1); - beforeOnePos = new SimpleVector2f(startBefore.getFrameIndex(), startBefore.getCorrespondingData()); - closeness = (start.getFrameIndex()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX()); + beforeOnePos = new SimpleVector2f(startBefore.getX(), startBefore.getY()); + closeness = (start.getX()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX()); } Vector2f direction = endPos.clone().sub(beforeOnePos.clone()); @@ -32,8 +32,8 @@ public CurveHandleData buildStartHandleData(List keyData, int i, KeyDat @Override public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) { - Vector2f startPos = new SimpleVector2f(start.getFrameIndex(), start.getCorrespondingData()); - Vector2f afterEndPos = new SimpleVector2f(end.getFrameIndex(), end.getCorrespondingData()); + Vector2f startPos = new SimpleVector2f(start.getX(), start.getY()); + Vector2f afterEndPos = new SimpleVector2f(end.getX(), end.getY()); float closeness = 0.5f; float lengthMultiplier = 2; @@ -41,8 +41,8 @@ public CurveHandleData buildEndHandleData(List keyData, int i, KeyData if (i=splineSegments) currentGuess = splineSegments; if (currentGuess<0) @@ -41,8 +41,8 @@ private static float newtonRaphsonMethod(float expectedX, float startT, Spline2D break; } float vel = spline.velocityX(currentGuess); - if (vel==0) - vel = EPSILON; //preventing catastrophic failure + if (Math.abs(vel)<=EPSILON) + vel = EPSILON*Math.copySign(1, vel); //preventing catastrophic failure currentGuess = currentGuess - (value-expectedX)/(vel); } @@ -73,7 +73,7 @@ public float interpolate(float t) { float startValue = plotted[index]; float endValue = plotted[indexPlusOne]; - float relativeTime = (t-index*plotInterval)/plotInterval; + float relativeTime = t/plotInterval - index; return relativeTime*endValue+(1-relativeTime)*startValue; } From 8c1cd8c09c92bf25a8d144162b983e371096075b Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:33:30 +0200 Subject: [PATCH 097/125] Refactored animation layering --- .../animations/AnimatedPropertyProvider.java | 14 +++++ .../animations/ProcessedAnimation.java | 38 ++++++++++++- .../timeline/AnimationTimeline.java | 5 +- .../timeline/LayeredAnimationTimeline.java | 49 +++++++++++++++++ .../timeline/ReplacingAnimationTimeline.java | 49 ----------------- .../timeline/SetAnimationTimeline.java | 54 +++++++++++++++++++ .../timeline/blending/BlendingRepository.java | 33 ++++++++++++ .../timeline/blending/ObjectBlending.java | 9 ++++ .../timeline/blending/QuaternionBlending.java | 37 +++++++++++++ .../layers/AdditiveLayerBlending.java | 24 +++++++++ .../timeline/layers/AnimationLayer.java | 23 +++++--- .../timeline/layers/LayerBlending.java | 11 ++++ .../animations/timeline/layers/LayerMode.java | 9 ---- .../layers/ReplacingLayerBlending.java | 12 +++++ .../layers/WeightedLayerBlending.java | 24 +++++++++ 15 files changed, 321 insertions(+), 70 deletions(-) create mode 100644 Animations/src/main/java/fr/radi3nt/animations/AnimatedPropertyProvider.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/LayeredAnimationTimeline.java delete mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/SetAnimationTimeline.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/blending/BlendingRepository.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/blending/ObjectBlending.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/blending/QuaternionBlending.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AdditiveLayerBlending.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerBlending.java delete mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/ReplacingLayerBlending.java create mode 100644 Animations/src/main/java/fr/radi3nt/animations/timeline/layers/WeightedLayerBlending.java diff --git a/Animations/src/main/java/fr/radi3nt/animations/AnimatedPropertyProvider.java b/Animations/src/main/java/fr/radi3nt/animations/AnimatedPropertyProvider.java new file mode 100644 index 0000000..4702fe1 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/AnimatedPropertyProvider.java @@ -0,0 +1,14 @@ +package fr.radi3nt.animations; + +import fr.radi3nt.animations.channels.ChannelIdentifier; + +import java.util.Set; +import java.util.function.Supplier; + +public interface AnimatedPropertyProvider { + + void incrementTime(float delta); + Supplier get(ChannelIdentifier identifier); + + void addConcernedObjects(Set objects); +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java b/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java index 40d45fe..cfc8ba7 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java +++ b/Animations/src/main/java/fr/radi3nt/animations/ProcessedAnimation.java @@ -1,6 +1,12 @@ package fr.radi3nt.animations; -public class ProcessedAnimation { +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.channels.KeyframeChannel; + +import java.util.Set; +import java.util.function.Supplier; + +public class ProcessedAnimation implements AnimatedPropertyProvider { public final AnimationClip animationClip; private final boolean looping; @@ -11,14 +17,42 @@ public ProcessedAnimation(AnimationClip animationClip, boolean looping) { this.looping = looping; } + public ProcessedAnimation(AnimationClip animationClip, boolean looping, float relativeTime) { + this.animationClip = animationClip; + this.looping = looping; + this.relativeTime = relativeTime; + } + public float getRelativeTime() { return relativeTime; } + public boolean isDone() { + return relativeTime>animationClip.duration; + } + + @Override public void incrementTime(float delta) { relativeTime+=delta; - if (relativeTime>animationClip.duration && looping) + if (isDone() && looping) relativeTime-=animationClip.duration; } + @Override + public Supplier get(ChannelIdentifier identifier) { + return () -> { + KeyframeChannel keyframeChannel = animationClip.channels.get(identifier); + if (keyframeChannel==null) + return null; + return (A) keyframeChannel.transform(relativeTime); + }; + } + + @Override + public void addConcernedObjects(Set objects) { + for (ChannelIdentifier channelIdentifier : animationClip.channels.keySet()) { + objects.add(channelIdentifier.objectName); + } + } + } diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java index 0269e91..77bfad8 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/AnimationTimeline.java @@ -7,8 +7,7 @@ public interface AnimationTimeline { void update(float delta); - - T getAnimatedPropertyOrDefault(ChannelIdentifier channelIdentifier, T defaultResult); - + T get(ChannelIdentifier channelIdentifier, T defaultResult); Collection getAvailableObjects(); + } diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/LayeredAnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/LayeredAnimationTimeline.java new file mode 100644 index 0000000..abf6883 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/LayeredAnimationTimeline.java @@ -0,0 +1,49 @@ +package fr.radi3nt.animations.timeline; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.blending.BlendingRepository; +import fr.radi3nt.animations.timeline.layers.AnimationLayer; + +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class LayeredAnimationTimeline implements AnimationTimeline { + + private final Queue animationLayers = new ConcurrentLinkedQueue<>(); + private final BlendingRepository blending; + + public LayeredAnimationTimeline(BlendingRepository blending) { + this.blending = blending; + } + + public Queue getAnimationLayers() { + return animationLayers; + } + + @Override + public void update(float delta) { + for (AnimationLayer animationLayer : animationLayers) { + animationLayer.getTimeline().update(delta); + } + } + + @Override + public T get(ChannelIdentifier channelIdentifier, T defaultResult) { + T result = defaultResult; + for (AnimationLayer animationLayer : animationLayers) { + result = animationLayer.getLayerMode().blend(blending, animationLayer.getTimeline(), channelIdentifier, result); + } + return result; + } + + @Override + public Collection getAvailableObjects() { + Set result = new HashSet<>(); + for (AnimationLayer animationLayer : animationLayers) { + result.addAll(animationLayer.getTimeline().getAvailableObjects()); + } + + return result; + } + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java deleted file mode 100644 index 9678f09..0000000 --- a/Animations/src/main/java/fr/radi3nt/animations/timeline/ReplacingAnimationTimeline.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.radi3nt.animations.timeline; - -import fr.radi3nt.animations.AnimationClip; -import fr.radi3nt.animations.ProcessedAnimation; -import fr.radi3nt.animations.channels.ChannelIdentifier; -import fr.radi3nt.animations.channels.KeyframeChannel; - -import java.util.*; - -public class ReplacingAnimationTimeline implements AnimationTimeline { - - private final List processedAnimations = new ArrayList<>(); - - public void addAnimation(AnimationClip animationClip, boolean looping) { - processedAnimations.add(new ProcessedAnimation(animationClip, looping)); - } - - @Override - public void update(float delta) { - for (ProcessedAnimation processedAnimation : processedAnimations) { - processedAnimation.incrementTime(delta); - } - } - - @Override - public T getAnimatedPropertyOrDefault(ChannelIdentifier identifier, T defaultResult) { - KeyframeChannel lastChannel = null; - float t = 0; - - for (ProcessedAnimation processedAnimation : processedAnimations) { - lastChannel = processedAnimation.animationClip.channels.get(identifier); - t = processedAnimation.getRelativeTime(); - } - - return lastChannel==null ? defaultResult : (T) lastChannel.transform(t); - } - - @Override - public Collection getAvailableObjects() { - Set objects = new HashSet<>(); - for (ProcessedAnimation processedAnimation : processedAnimations) { - for (ChannelIdentifier channelIdentifier : processedAnimation.animationClip.channels.keySet()) { - objects.add(channelIdentifier.objectName); - } - } - - return objects; - } -} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/SetAnimationTimeline.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/SetAnimationTimeline.java new file mode 100644 index 0000000..ee2f25f --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/SetAnimationTimeline.java @@ -0,0 +1,54 @@ +package fr.radi3nt.animations.timeline; + +import fr.radi3nt.animations.AnimationClip; +import fr.radi3nt.animations.AnimatedPropertyProvider; +import fr.radi3nt.animations.ProcessedAnimation; +import fr.radi3nt.animations.channels.ChannelIdentifier; + +import java.util.*; +import java.util.function.Supplier; + +public class SetAnimationTimeline implements AnimationTimeline { + + private final List processedAnimations = new ArrayList<>(); + + public void addAnimation(AnimationClip animationClip, boolean looping) { + processedAnimations.add(new ProcessedAnimation(animationClip, looping)); + } + + public void addAnimation(AnimatedPropertyProvider provider) { + processedAnimations.add(provider); + } + + public void removeAnimation(AnimatedPropertyProvider provider) { + processedAnimations.remove(provider); + } + + @Override + public void update(float delta) { + for (AnimatedPropertyProvider processedAnimation : processedAnimations) { + processedAnimation.incrementTime(delta); + } + } + + @Override + public T get(ChannelIdentifier identifier, T defaultResult) { + Supplier lastChannel = null; + + for (AnimatedPropertyProvider processedAnimation : processedAnimations) { + lastChannel = processedAnimation.get(identifier); + } + + return lastChannel==null ? defaultResult : (T) lastChannel.get(); + } + + @Override + public Collection getAvailableObjects() { + Set objects = new HashSet<>(); + for (AnimatedPropertyProvider processedAnimation : processedAnimations) { + processedAnimation.addConcernedObjects(objects); + } + + return objects; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/BlendingRepository.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/BlendingRepository.java new file mode 100644 index 0000000..39a050a --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/BlendingRepository.java @@ -0,0 +1,33 @@ +package fr.radi3nt.animations.timeline.blending; + +import java.util.HashMap; +import java.util.Map; + +public class BlendingRepository { + + public static final BlendingRepository DEFAULT = new BlendingRepository(new QuaternionBlending()); + private final Map, ObjectBlending> blendingMap = new HashMap<>(); + + + public BlendingRepository(ObjectBlending... blendings) { + for (ObjectBlending blending : blendings) { + for (Class aClass : blending.supported()) { + blendingMap.put(aClass, blending); + } + } + } + + public void add(ObjectBlending blending) { + blendingMap.put(blending.getClass(), blending); + } + + public T blend(T first, T second, float weight) { + ObjectBlending objectBlending = (ObjectBlending) blendingMap.get(second.getClass()); + return objectBlending.blend(first, second, weight); + } + + public T additive(T first, T second, float weight) { + ObjectBlending objectBlending = (ObjectBlending) blendingMap.get(second.getClass()); + return objectBlending.add(first, second, weight); + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/ObjectBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/ObjectBlending.java new file mode 100644 index 0000000..f44d315 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/ObjectBlending.java @@ -0,0 +1,9 @@ +package fr.radi3nt.animations.timeline.blending; + +public interface ObjectBlending { + + T blend(T first, T second, float secondWeight); + T add(T first, T second, float weight); + + Class[] supported(); +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/QuaternionBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/QuaternionBlending.java new file mode 100644 index 0000000..f7e82b4 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/blending/QuaternionBlending.java @@ -0,0 +1,37 @@ +package fr.radi3nt.animations.timeline.blending; + +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; + +public class QuaternionBlending implements ObjectBlending { + @Override + public Quaternion blend(Quaternion first, Quaternion second, float secondWeight) { + if (first==null) + first = ComponentsQuaternion.zero(); + Quaternion result = ComponentsQuaternion.zero(); + result.copy(first); + result.interpolate(second, secondWeight); + + return result; + } + + @Override + public Quaternion add(Quaternion first, Quaternion second, float weight) { + if (first==null) + first = ComponentsQuaternion.zero(); + + Quaternion interpolation = ComponentsQuaternion.zero(); + interpolation.interpolate(second, weight); + + Quaternion result = ComponentsQuaternion.zero(); + result.copy(first); + result.multiply(interpolation); + + return result; + } + + @Override + public Class[] supported() { + return new Class[] {Quaternion.class, ComponentsQuaternion.class}; + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AdditiveLayerBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AdditiveLayerBlending.java new file mode 100644 index 0000000..342cf35 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AdditiveLayerBlending.java @@ -0,0 +1,24 @@ +package fr.radi3nt.animations.timeline.layers; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.animations.timeline.blending.BlendingRepository; + +public class AdditiveLayerBlending implements LayerBlending { + + private final float weight; + + public AdditiveLayerBlending(float weight) { + this.weight = weight; + } + + @Override + public T blend(BlendingRepository repository, AnimationTimeline timeline, ChannelIdentifier identifier, T defaultResult) { + if (weight==0) + return defaultResult; + T second = timeline.get(identifier, null); + if (second==null) + return defaultResult; + return repository.additive(defaultResult, second, weight); + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java index fdfbaaf..52cdef5 100644 --- a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/AnimationLayer.java @@ -1,18 +1,27 @@ package fr.radi3nt.animations.timeline.layers; -import fr.radi3nt.animations.ProcessedAnimation; - -import java.util.ArrayList; -import java.util.List; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.animations.timeline.SetAnimationTimeline; public class AnimationLayer { - private final List animations = new ArrayList<>(); - private final LayerMode layerMode; + private final AnimationTimeline timeline; + private final LayerBlending layerMode; - public AnimationLayer(LayerMode layerMode) { + public AnimationLayer(AnimationTimeline timeline, LayerBlending layerMode) { + this.timeline = timeline; this.layerMode = layerMode; } + public AnimationLayer(LayerBlending layerMode) { + this(new SetAnimationTimeline(), layerMode); + } + public LayerBlending getLayerMode() { + return layerMode; + } + + public AnimationTimeline getTimeline() { + return timeline; + } } diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerBlending.java new file mode 100644 index 0000000..01994d9 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerBlending.java @@ -0,0 +1,11 @@ +package fr.radi3nt.animations.timeline.layers; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.animations.timeline.blending.BlendingRepository; + +public interface LayerBlending { + + T blend(BlendingRepository repository, AnimationTimeline timeline, ChannelIdentifier identifier, T defaultResult); + +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java deleted file mode 100644 index ef81e4b..0000000 --- a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/LayerMode.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.radi3nt.animations.timeline.layers; - -public enum LayerMode { - - REPLACE, - ADD, - MULTIPLY - -} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/ReplacingLayerBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/ReplacingLayerBlending.java new file mode 100644 index 0000000..de98807 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/ReplacingLayerBlending.java @@ -0,0 +1,12 @@ +package fr.radi3nt.animations.timeline.layers; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.animations.timeline.blending.BlendingRepository; + +public class ReplacingLayerBlending implements LayerBlending { + @Override + public T blend(BlendingRepository repository, AnimationTimeline timeline, ChannelIdentifier identifier, T previousResult) { + return timeline.get(identifier, previousResult); + } +} diff --git a/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/WeightedLayerBlending.java b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/WeightedLayerBlending.java new file mode 100644 index 0000000..5083dc9 --- /dev/null +++ b/Animations/src/main/java/fr/radi3nt/animations/timeline/layers/WeightedLayerBlending.java @@ -0,0 +1,24 @@ +package fr.radi3nt.animations.timeline.layers; + +import fr.radi3nt.animations.channels.ChannelIdentifier; +import fr.radi3nt.animations.timeline.AnimationTimeline; +import fr.radi3nt.animations.timeline.blending.BlendingRepository; + +public class WeightedLayerBlending implements LayerBlending { + + private final float weight; + + public WeightedLayerBlending(float weight) { + this.weight = weight; + } + + @Override + public T blend(BlendingRepository repository, AnimationTimeline timeline, ChannelIdentifier identifier, T defaultResult) { + if (weight==0) + return defaultResult; + T second = timeline.get(identifier, null); + if (second==null) + return defaultResult; + return repository.blend(defaultResult, second, weight); + } +} From e8c5d3b3a096f58594e5d9ea07e11a9b448cda22 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:36:03 +0200 Subject: [PATCH 098/125] Changed BoneDriver behavior to support scaling (bone independent) --- .../armatures/armature/ListArmature.java | 6 +- .../radi3nt/armatures/armature/bone/Bone.java | 3 +- .../armatures/armature/bone/ParentBone.java | 8 +- .../armatures/armature/driver/BoneDriver.java | 15 ++- .../armature/driver/BoneRestData.java | 7 +- .../armature/driver/DriverResult.java | 11 ++ .../driver/EncapsulatingDriverResult.java | 24 ++++ .../armature/driver/ParentedBoneDriver.java | 103 ++++++++++++++++-- .../armature/driver/ScaleDriverResult.java | 27 +++++ .../armature/driver/SetDriverResult.java | 22 ++++ .../driver/WorldIndependentBoneDriver.java | 54 ++++++--- .../driver/WorldRestedBoneDriver.java | 63 ++++++++--- .../ArmatureAnimationController.java | 13 ++- .../controller/ArmatureController.java | 16 +-- 14 files changed, 306 insertions(+), 66 deletions(-) create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/DriverResult.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/EncapsulatingDriverResult.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ScaleDriverResult.java create mode 100644 Armature/src/main/java/fr/radi3nt/armatures/armature/driver/SetDriverResult.java diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java index bc709f6..0fe9ad0 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/ListArmature.java @@ -1,7 +1,11 @@ package fr.radi3nt.armatures.armature; import fr.radi3nt.armatures.armature.bone.Bone; +import fr.radi3nt.armatures.armature.driver.DriverResult; +import fr.radi3nt.armatures.armature.driver.SetDriverResult; +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.vectors.Vector3f; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -36,7 +40,7 @@ private void writeMatrix(ByteBuffer byteBuffer, Matrix4x4 worldSpaceTransform) { public void update() { for (Bone rootBone : rootBones) { - rootBone.update(armatureTransform); + rootBone.update(new SetDriverResult(armatureTransform)); } } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java index 4bc3d4e..33e33f7 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/Bone.java @@ -2,11 +2,12 @@ import fr.radi3nt.armatures.armature.driver.BoneDriver; import fr.radi3nt.armatures.armature.driver.BoneRestData; +import fr.radi3nt.armatures.armature.driver.DriverResult; import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; public interface Bone { - void update(Matrix4x4 parentModelSpace); + void update(DriverResult parentModelSpace); void setBoneDriver(BoneDriver boneDriver); diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java index 9617b03..da19680 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/bone/ParentBone.java @@ -2,6 +2,7 @@ import fr.radi3nt.armatures.armature.driver.BoneDriver; import fr.radi3nt.armatures.armature.driver.BoneRestData; +import fr.radi3nt.armatures.armature.driver.DriverResult; import fr.radi3nt.armatures.armature.driver.ParentedBoneDriver; import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; @@ -31,13 +32,14 @@ public ParentBone(Matrix4x4 worldInverseBindTransform, BoneRestData boneRestData } @Override - public void update(Matrix4x4 parentModelSpace) { - modelSpaceTransform.copy(boneDriver.getModelSpaceTransform(parentModelSpace)); + public void update(DriverResult parentModelSpace) { + DriverResult result = boneDriver.getModelSpaceForParentTransform(parentModelSpace); for (Bone child : children) { - child.update(modelSpaceTransform); + child.update(result); } + modelSpaceTransform.copy(result.getCurrent()); jointSpaceTransform.copy(modelSpaceTransform); jointSpaceTransform.multiply(worldInverseBindTransform); } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java index 1c5cb41..97aa860 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneDriver.java @@ -6,11 +6,16 @@ public interface BoneDriver { - void set(Vector3f position); - void set(Quaternion quaternion); - void set(Vector3f translation, Quaternion rotation); - void set(Vector3f translate, Quaternion rotate, Vector3f scale); + void setPosition(Vector3f position); + void setScale(Vector3f scale); + void setRotation(Quaternion quaternion); + void addRotation(Quaternion quaternion); + void setPositionAndRotation(Vector3f translation, Quaternion rotation); + void setAll(Vector3f translate, Quaternion rotate, Vector3f scale); - Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace); + DriverResult getModelSpaceForParentTransform(DriverResult parent); + Quaternion getLocalRotation(); + Vector3f getLocalTranslation(); + Vector3f getLocalSize(); } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java index 16fba82..226fcec 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/BoneRestData.java @@ -1,9 +1,11 @@ package fr.radi3nt.armatures.armature.driver; import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix; import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; public class BoneRestData { @@ -22,10 +24,7 @@ public static BoneRestData fromMatrix(Matrix4x4 matrix) { } public Matrix4x4 toMatrix() { - Matrix4x4 result = ArrayMatrix4x4.newIdentity(); - result.quaternionRotation(rotation); - result.translation(position); - result.scalar(scale); + Matrix4x4 result = ArrayMatrix4x4.transform(position, rotation, scale); return result; } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/DriverResult.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/DriverResult.java new file mode 100644 index 0000000..54e7da8 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/DriverResult.java @@ -0,0 +1,11 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface DriverResult { + + Matrix4x4 getCurrent(); + void cancelScale(Matrix4x4 current); + +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/EncapsulatingDriverResult.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/EncapsulatingDriverResult.java new file mode 100644 index 0000000..cc400ca --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/EncapsulatingDriverResult.java @@ -0,0 +1,24 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public class EncapsulatingDriverResult implements DriverResult { + + private final Matrix4x4 current; + private final DriverResult cancelScale; + + public EncapsulatingDriverResult(Matrix4x4 current, DriverResult cancelScale) { + this.current = current; + this.cancelScale = cancelScale; + } + + @Override + public Matrix4x4 getCurrent() { + return current; + } + + @Override + public void cancelScale(Matrix4x4 current) { + cancelScale.cancelScale(current); + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java index 65b7cc7..0df02d5 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ParentedBoneDriver.java @@ -5,7 +5,9 @@ import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.Vector4f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; public class ParentedBoneDriver implements BoneDriver { @@ -13,13 +15,18 @@ public class ParentedBoneDriver implements BoneDriver { private static final boolean TRANSFORM_MODE = false; private final Matrix4x4 resultTransform = ArrayMatrix4x4.newIdentity(); + private final Matrix4x4 resultParentTransform = ArrayMatrix4x4.newIdentity(); private final Matrix4x4 localTransform = ArrayMatrix4x4.newIdentity(); private final Matrix4x4 localRestTransform = ArrayMatrix4x4.newIdentity(); private final Vector3f translation = new SimpleVector3f(); + private final Vector3f scale = new SimpleVector3f(1f, 1f, 1f); private final Quaternion rotation = ComponentsQuaternion.zero(); + private final BoneRestData restData; + public ParentedBoneDriver(BoneRestData restData) { + this.restData = restData; if (TRANSFORM_MODE) { this.translation.copy(restData.getPosition()); this.rotation.copy(restData.getRotation()); @@ -28,36 +35,110 @@ public ParentedBoneDriver(BoneRestData restData) { } } + public BoneRestData getRestData() { + return restData; + } + + public void updateLocalRestTransform() { + this.localRestTransform.copy(restData.toMatrix()); + } + @Override - public void set(Vector3f position) { + public void setPosition(Vector3f position) { this.translation.copy(position); } @Override - public void set(Quaternion quaternion) { + public void setScale(Vector3f scale) { + this.scale.copy(scale); + } + + @Override + public void setRotation(Quaternion quaternion) { this.rotation.copy(quaternion); } @Override - public void set(Vector3f translation, Quaternion rotation) { - set(translation); - set(rotation); + public void addRotation(Quaternion quaternion) { + rotation.multiply(quaternion); } @Override - public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { - set(translate, rotate); //todo unsupported scale + public void setPositionAndRotation(Vector3f translation, Quaternion rotation) { + setPosition(translation); + setRotation(rotation); } @Override - public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { + public void setAll(Vector3f translate, Quaternion rotate, Vector3f scale) { + setPositionAndRotation(translate, rotate); + setScale(scale); + } + + @Override + public DriverResult getModelSpaceForParentTransform(DriverResult parent) { + Matrix4x4 parentTransform = parent.getCurrent(); + Vector3f applyingScale = scale.duplicate(); + localTransform.quaternionRotation(rotation); localTransform.translation(translation); + localTransform.scalar(applyingScale); + + resultTransform.copy(parentTransform); + resultTransform.multiply(ArrayMatrix4x4.transform(restData.getPosition())); + parent.cancelScale(resultTransform); + resultTransform.multiply(ArrayMatrix4x4.fromRotation(restData.getRotation())); + resultTransform.multiply(ArrayMatrix4x4.fromScale(restData.getScale())); - resultTransform.copy(parentModelSpace); - resultTransform.multiply(localRestTransform); resultTransform.multiply(localTransform); + return new ParentDriverResult(applyingScale); + } + + @Override + public Quaternion getLocalRotation() { + return rotation; + } - return resultTransform; + @Override + public Vector3f getLocalTranslation() { + return translation; + } + + @Override + public Vector3f getLocalSize() { + return scale; + } + + public Quaternion getModelRotation(Quaternion parent) { + Quaternion result = ComponentsQuaternion.zero(); + result.multiply(parent); + result.multiply(restData.getRotation()); + result.multiply(getLocalRotation()); + return result; + } + + public float getBoneLength() { + Vector4f bone = new SimpleVector4f(0, 0, 0, 1); + localRestTransform.transform(bone); + return bone.length(); + } + + public class ParentDriverResult implements DriverResult { + + private final Vector3f applyingScale; + + public ParentDriverResult(Vector3f applyingScale) { + this.applyingScale = applyingScale; + } + + @Override + public Matrix4x4 getCurrent() { + return resultTransform; + } + + @Override + public void cancelScale(Matrix4x4 current) { + current.multiply(ArrayMatrix4x4.fromScale(new SimpleVector3f(1f, 1f, 1f).div(applyingScale))); + } } } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ScaleDriverResult.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ScaleDriverResult.java new file mode 100644 index 0000000..8791f60 --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/ScaleDriverResult.java @@ -0,0 +1,27 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4; +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ScaleDriverResult implements DriverResult { + + private final Matrix4x4 result; + private final Vector3f scale; + + public ScaleDriverResult(Matrix4x4 result, Vector3f scale) { + this.result = result; + this.scale = scale; + } + + @Override + public Matrix4x4 getCurrent() { + return result; + } + + @Override + public void cancelScale(Matrix4x4 current) { + current.multiply(ArrayMatrix4x4.fromScale(new SimpleVector3f(1f, 1f, 1f).div(scale))); + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/SetDriverResult.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/SetDriverResult.java new file mode 100644 index 0000000..7e594ba --- /dev/null +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/SetDriverResult.java @@ -0,0 +1,22 @@ +package fr.radi3nt.armatures.armature.driver; + +import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4; + +public class SetDriverResult implements DriverResult { + + private final Matrix4x4 result; + + public SetDriverResult(Matrix4x4 result) { + this.result = result; + } + + @Override + public Matrix4x4 getCurrent() { + return result; + } + + @Override + public void cancelScale(Matrix4x4 current) { + + } +} diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java index 84154d8..0a042aa 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldIndependentBoneDriver.java @@ -13,6 +13,7 @@ public class WorldIndependentBoneDriver implements BoneDriver { private final Matrix4x4 localTransform = ArrayMatrix4x4.newIdentity(); private final Vector3f translation = new SimpleVector3f(); + private final Vector3f scale = new SimpleVector3f(1f, 1f, 1f); private final Quaternion rotation = ComponentsQuaternion.zero(); public WorldIndependentBoneDriver() { @@ -20,41 +21,66 @@ public WorldIndependentBoneDriver() { } @Override - public void set(Vector3f position) { + public void setPosition(Vector3f position) { this.translation.copy(position); } @Override - public void set(Quaternion quaternion) { + public void setScale(Vector3f scale) { + this.scale.copy(scale); + } + + @Override + public void setRotation(Quaternion quaternion) { this.rotation.copy(quaternion); } @Override - public void set(Vector3f translation, Quaternion rotation) { - set(translation); - set(rotation); + public void addRotation(Quaternion quaternion) { + rotation.multiply(quaternion); + } + + @Override + public void setPositionAndRotation(Vector3f translation, Quaternion rotation) { + setPosition(translation); + setRotation(rotation); } @Override - public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { - set(translate, rotate); + public void setAll(Vector3f translate, Quaternion rotate, Vector3f scale) { + setPositionAndRotation(translate, rotate); + setScale(scale); + } + + @Override + public DriverResult getModelSpaceForParentTransform(DriverResult parent) { + localTransform.quaternionRotation(getLocalRotation()); + localTransform.translation(getTranslation()); + localTransform.scalar(getScale()); + + resultTransform.copy(localTransform); + return new SetDriverResult(resultTransform); } - public Quaternion getRotation() { + public Quaternion getLocalRotation() { return rotation; } - public Vector3f getTranslation() { + @Override + public Vector3f getLocalTranslation() { return translation; } @Override - public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { - localTransform.quaternionRotation(getRotation()); - localTransform.translation(getTranslation()); + public Vector3f getLocalSize() { + return scale; + } - resultTransform.copy(localTransform); + public Vector3f getTranslation() { + return translation; + } - return resultTransform; + public Vector3f getScale() { + return scale; } } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java index 8ec4866..0bb99bb 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/armature/driver/WorldRestedBoneDriver.java @@ -14,49 +14,84 @@ public class WorldRestedBoneDriver implements BoneDriver { private final Matrix4x4 localRestTransform = ArrayMatrix4x4.newIdentity(); private final Vector3f translation = new SimpleVector3f(); + private final Vector3f scale = new SimpleVector3f(1f, 1f, 1f); private final Quaternion rotation = ComponentsQuaternion.zero(); + private final BoneRestData restData; + public WorldRestedBoneDriver(BoneRestData restData) { + this.restData = restData; this.localRestTransform.copy(restData.toMatrix()); } @Override - public void set(Vector3f position) { + public void setPosition(Vector3f position) { this.translation.copy(position); } @Override - public void set(Quaternion quaternion) { + public void setScale(Vector3f scale) { + this.scale.copy(scale); + } + + @Override + public void setRotation(Quaternion quaternion) { this.rotation.copy(quaternion); } @Override - public void set(Vector3f translation, Quaternion rotation) { - set(translation); - set(rotation); + public void addRotation(Quaternion quaternion) { + rotation.multiply(quaternion); + } + + @Override + public void setPositionAndRotation(Vector3f translation, Quaternion rotation) { + setPosition(translation); + setRotation(rotation); } @Override - public void set(Vector3f translate, Quaternion rotate, Vector3f scale) { - set(translate, rotate); + public void setAll(Vector3f translate, Quaternion rotate, Vector3f scale) { + setPositionAndRotation(translate, rotate); + setScale(scale); + } + + @Override + public DriverResult getModelSpaceForParentTransform(DriverResult parent) { + localTransform.quaternionRotation(getLocalRotation()); + localTransform.translation(getTranslation()); + localTransform.scale(getScale()); + + resultTransform.copy(localRestTransform); + resultTransform.multiply(localTransform); + return new SetDriverResult(resultTransform); } public Vector3f getTranslation() { return translation; } - public Quaternion getRotation() { + public Quaternion getLocalRotation() { return rotation; } @Override - public Matrix4x4 getModelSpaceTransform(Matrix4x4 parentModelSpace) { - localTransform.quaternionRotation(getRotation()); - localTransform.translation(getTranslation()); + public Vector3f getLocalTranslation() { + return translation; + } - resultTransform.copy(localRestTransform); - resultTransform.multiply(localTransform); + @Override + public Vector3f getLocalSize() { + return scale; + } + + public Quaternion getModelRotation(Quaternion parent) { + Quaternion duplicate = restData.getRotation().duplicate(); + duplicate.multiply(getLocalRotation()); + return duplicate; + } - return resultTransform; + public Vector3f getScale() { + return scale; } } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java index 1386246..a140636 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureAnimationController.java @@ -23,14 +23,17 @@ public void update() { System.err.println("Unable to find object '" + availableObject + "' referenced in the animation clip, ignoring"); continue; } - Quaternion rotate = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.rotation(availableObject), null); - Vector3f translate = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.translation(availableObject), null); - Vector3f scale = animationTimeline.getAnimatedPropertyOrDefault(ChannelIdentifier.scale(availableObject), null); + + Quaternion rotate = animationTimeline.get(ChannelIdentifier.rotation(availableObject), null); + Vector3f translate = animationTimeline.get(ChannelIdentifier.translation(availableObject), null); + Vector3f scale = animationTimeline.get(ChannelIdentifier.scale(availableObject), null); if (rotate!=null) - driver.set(rotate); + driver.setRotation(rotate); if (translate!=null) - driver.set(translate); + driver.setPosition(translate); + if (scale!=null) + driver.setScale(scale); } } } diff --git a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java index 9e5221c..6cb09c1 100644 --- a/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java +++ b/Armature/src/main/java/fr/radi3nt/armatures/controller/ArmatureController.java @@ -8,22 +8,22 @@ public class ArmatureController { - private final Map driverMap; + private final Map driverMap; - public ArmatureController(Map driverMap) { + public ArmatureController(Map driverMap) { this.driverMap = driverMap; } public static ArmatureController from(Map bones) { - Map driverMap = new HashMap<>(); - for (Map.Entry entry : bones.entrySet()) { - driverMap.put(entry.getKey(), entry.getValue().getBoneDriver()); - } - return new ArmatureController(driverMap); + return new ArmatureController(bones); } public BoneDriver getDriver(String boneName) { - return driverMap.get(boneName); + return driverMap.get(boneName).getBoneDriver(); + } + + public void setDriver(String boneName, BoneDriver driver) { + driverMap.get(boneName).setBoneDriver(driver); } } From 4812a86bba385e32b836e88255b683a687c2c063 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:41:24 +0200 Subject: [PATCH 099/125] Refactored to use Quaternion in JointConstraint --- .../radi3nt/ik/solvers/IkIterativeSolver.java | 19 +++++++++---------- .../radi3nt/ik/solvers/ccdik/CCDIKSolver.java | 11 ++++++++--- .../fr/radi3nt/ik/solvers/ccdik/CCDJoint.java | 10 +++++++++- .../constraint/HingeJointConstraint.java | 6 +++--- .../ccdik/constraint/JointConstraint.java | 4 ++-- .../ccdik/constraint/NoJointConstraint.java | 6 +++--- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java index 60187cc..6339e1e 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/IkIterativeSolver.java @@ -5,8 +5,6 @@ public abstract class IkIterativeSolver implements IkSolver { private final int maxIterations; protected final float allowedMarginOfError; - private boolean solved; - public IkIterativeSolver(int maxIterations, float allowedMarginOfError) { this.maxIterations = maxIterations; this.allowedMarginOfError = allowedMarginOfError; @@ -15,20 +13,21 @@ public IkIterativeSolver(int maxIterations, float allowedMarginOfError) { @Override public void solve() { - if (isInAllowedMarginOfError()) { - solved = false; - return; - } for (int i = 0; i < maxIterations; i++) { - iteration(); + prepareSolve(); if (isInAllowedMarginOfError()) break; + iteration(); } - solved = true; + endSolve(); } - public boolean iterationWasSolved() { - return solved; + protected void endSolve() { + + } + + protected void prepareSolve() { + } protected abstract boolean isInAllowedMarginOfError(); diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java index 8c8bc2d..60483b7 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDIKSolver.java @@ -56,9 +56,11 @@ private Quaternion getRotationBetweenEndEffectorAndGoalUsingWorldSpace(int joinI invLinkRot.inverse(); Vector3f localEi = convertToBoneLocalSpace(ei, bonePos, invLinkRot); - localEi.normalize(); + localEi.normalizeSafely(); Vector3f localEt = convertToBoneLocalSpace(et, bonePos, invLinkRot); - localEt.normalize(); + localEt.normalizeSafely(); + if (localEt.lengthSquared()==0 || localEi.lengthSquared()==0) + return ComponentsQuaternion.zero(); return ComponentsQuaternion.fromTwoVectors(localEi, localEt); } @@ -77,6 +79,7 @@ private Vector3f getBonePos(int index) { Quaternion rotation = joint.rotation; float length = joint.getLength(); + //rotation.multiply(joint.baseRot); cumulatedRotation.multiply(rotation); Vector3f localTranslation = upAxis.duplicate(); cumulatedRotation.transform(localTranslation); @@ -93,7 +96,9 @@ public void setGoal(Vector3f goal) { private Quaternion getAllPreviousRotation(int index) { Quaternion localSpaceRotation = ComponentsQuaternion.zero(); for (int i = 0; i < index; i++) { - Quaternion linkInverseRot = joints[i].rotation; + Quaternion linkInverseRot = joints[i].rotation.duplicate(); + Quaternion baseRotInv = joints[i].baseRot; + //linkInverseRot.multiply(baseRotInv); localSpaceRotation.multiply(linkInverseRot); } return localSpaceRotation; diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java index a4805ff..a94780e 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/CCDJoint.java @@ -8,6 +8,7 @@ public class CCDJoint { private final float length; + public Quaternion baseRot = ComponentsQuaternion.zero(); public Quaternion rotation = ComponentsQuaternion.zero(); private final JointConstraint jointConstraint; @@ -19,8 +20,15 @@ public CCDJoint(float length, JointConstraint jointConstraint, JointLimit jointL this.jointLimit = jointLimit; } + public CCDJoint(float length, JointConstraint jointConstraint, JointLimit jointLimit, Quaternion baseRot) { + this.length = length; + this.jointConstraint = jointConstraint; + this.jointLimit = jointLimit; + this.baseRot = baseRot.duplicate(); + } + public void constrain() { - jointConstraint.constrain(this); + jointConstraint.constrain(this.rotation); } public void limit() { diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java index e0633d7..0b951a6 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/HingeJointConstraint.java @@ -14,15 +14,15 @@ public HingeJointConstraint(Vector3f constrainedAxis) { } @Override - public void constrain(CCDJoint ccdJoint) { - Quaternion invRot = ccdJoint.rotation.duplicate(); + public void constrain(Quaternion rotation) { + Quaternion invRot = rotation.duplicate(); invRot.inverse(); Vector3f parentAxis = constrainedAxis.duplicate(); invRot.transform(parentAxis); Quaternion quaternion = ComponentsQuaternion.fromTwoVectors(constrainedAxis, parentAxis); - ccdJoint.rotation.multiply(quaternion); + rotation.multiply(quaternion); } public Vector3f getConstrainedAxis() { diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java index 06708da..630e114 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/JointConstraint.java @@ -1,7 +1,7 @@ package fr.radi3nt.ik.solvers.ccdik.constraint; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; public interface JointConstraint { - void constrain(CCDJoint ccdJoint); + void constrain(Quaternion rotation); } diff --git a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java index 4841324..fe3ede3 100644 --- a/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java +++ b/InverseKinematics/src/main/java/fr/radi3nt/ik/solvers/ccdik/constraint/NoJointConstraint.java @@ -1,17 +1,17 @@ package fr.radi3nt.ik.solvers.ccdik.constraint; -import fr.radi3nt.ik.solvers.ccdik.CCDJoint; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; public class NoJointConstraint implements JointConstraint { - public static NoJointConstraint INSTANCE = new NoJointConstraint(); + public static final NoJointConstraint INSTANCE = new NoJointConstraint(); private NoJointConstraint() { } @Override - public void constrain(CCDJoint ccdJoint) { + public void constrain(Quaternion rotation) { } } From dc8ec5743802feb75751ac3b7cb38d0ee0279014 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:44:36 +0200 Subject: [PATCH 100/125] Added fastAbs(), inRange(), max(a, b, c), min(a, b, c) --- .../src/main/java/fr/radi3nt/maths/Maths.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java index fb67974..e2004be 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/Maths.java @@ -27,8 +27,8 @@ public static double clamp(double value, double min, double max) { return Math.max(Math.min(value, max), min); } - public static double exactDistance(Vector3f vec1, Vector3f vec2) { - return Math.abs(Math.sqrt(Math.pow(vec1.getX()-vec2.getX(), 2) + Math.pow(vec1.getY() - vec2.getY(), 2) + Math.pow(vec1.getZ() - vec2.getZ(), 2))); + public static float fastAbs(float v) { + return Float.intBitsToFloat(0x7fffffff & Float.floatToRawIntBits(v)); } public static byte[] floatToByteArray(float[] value) { @@ -132,4 +132,30 @@ public static double[][] nCopies(int amount, double[] values) { Arrays.fill(array, values); return array; } + + public static boolean inRange(float v1, float v2, float c) { + return fastAbs(v1-v2) <= c; + } + + public static double max(double a, double b, double c) { + double maximum = a; + + if (maximum < b) + maximum = b; + + if (maximum < c) + maximum = c; + return maximum; + } + + public static double min(double a, double b, double c) { + double minimum = a; + + if (minimum > b) + minimum = b; + + if (minimum > c) + minimum = c; + return minimum; + } } From 23d316a5c22823e724980cc14d41016bafb30fdd Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:45:02 +0200 Subject: [PATCH 101/125] Added toVector() --- .../java/fr/radi3nt/maths/colour/colors/BasicColour.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java index 8945b8a..08d5067 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/BasicColour.java @@ -1,6 +1,7 @@ package fr.radi3nt.maths.colour.colors; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; import java.util.Objects; @@ -39,6 +40,10 @@ public BasicColour(int red, int green, int blue) { this.blue = blue/255f; } + public BasicColour(Colour color, float intensity) { + this(color.getRed(), color.getGreen(), color.getBlue(), intensity); + } + @Override public float getRed() { return red; @@ -80,4 +85,8 @@ public int hashCode() { public Colour duplicate() { return new BasicColour(getRed(), getGreen(), getBlue()); } + + public Vector3f toVector() { + return new SimpleVector3f(red, green, blue); + } } From a5b3ec881ebb25e3dacfe247dd15acbc7e3cf570 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:45:15 +0200 Subject: [PATCH 102/125] Added toString() to ColorData --- .../java/fr/radi3nt/maths/colour/colors/ColorData.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java index 42eb182..a5d2d5f 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/colour/colors/ColorData.java @@ -21,4 +21,12 @@ public Colour getColour() { public float getAlpha() { return alpha; } + + @Override + public String toString() { + return "ColorData{" + + "colour=" + colour + + ", alpha=" + alpha + + '}'; + } } From c38b11ea1ecb76a709c87a1d89ebd19da89041f9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:45:44 +0200 Subject: [PATCH 103/125] Added constructor taking in a Matrix4x4 --- .../maths/components/advanced/matrix/ArrayMatrix3x3.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java index dde9822..f38dd3e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -29,6 +29,15 @@ public ArrayMatrix3x3(float[][] m) { this.m = m; } + public ArrayMatrix3x3(Matrix4x4 copy) { + m = new float[3][3]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + set(i, j, copy.get(i, j)); + } + } + } + public static ArrayMatrix3x3 newIdentity() { ArrayMatrix3x3 arrayMatrix4x4 = new ArrayMatrix3x3(); arrayMatrix4x4.identity(); From c22c95bde3994aa07daf8b924a6f44c0529a38a0 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:45:58 +0200 Subject: [PATCH 104/125] Added isZero() --- .../components/advanced/matrix/ArrayMatrix3x3.java | 11 +++++++++++ .../maths/components/advanced/matrix/Matrix3x3.java | 2 ++ 2 files changed, 13 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java index f38dd3e..7bac5b4 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix3x3.java @@ -143,6 +143,17 @@ public void subtract(Matrix3x3 skewRJ) { } } + @Override + public boolean isZero() { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (get(i, j)!=0) + return false; + } + } + return true; + } + @Override public Quaternion getRotation() { return getCopySignRotation(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java index 46a3114..c6f8896 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix3x3.java @@ -33,4 +33,6 @@ public interface Matrix3x3 extends Matrix { Matrix3x3 duplicate(); void subtract(Matrix3x3 skewRJ); + + boolean isZero(); } From 9aa1969cb5421b00007a29abe1bffbff0e14f4d8 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:46:42 +0200 Subject: [PATCH 105/125] Added utility methods for transformations --- .../advanced/matrix/ArrayMatrix4x4.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 1524525..cc0c332 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -46,6 +46,69 @@ public static ArrayMatrix4x4 newIdentity() { return arrayMatrix4x4; } + public static Matrix4x4 transform(Vector3f translation) { + ArrayMatrix4x4 arrayMatrix4x4 = newIdentity(); + arrayMatrix4x4.translation(translation); + return arrayMatrix4x4; + } + + public static Matrix4x4 transform(Vector3f translation, Quaternion rotation) { + ArrayMatrix4x4 arrayMatrix4x4 = new ArrayMatrix4x4(); + arrayMatrix4x4.quaternionRotation(rotation); + arrayMatrix4x4.translation(translation); + return arrayMatrix4x4; + } + + public static Matrix4x4 transform(Vector3f translation, Quaternion rotation, Vector3f scale) { + ArrayMatrix4x4 result = new ArrayMatrix4x4(); + transform(result, translation, rotation, scale); + return result; + } + + + public static void transform(Matrix4x4 result, Vector3f translation, Quaternion rotation, Vector3f scale) { + result.quaternionRotation(rotation); + result.translation(translation); + + Matrix4x4 scaling = ArrayMatrix4x4.newIdentity(); + scaling.scale(scale); + result.multiply(scaling); + + } + + public static Matrix4x4 transform(Vector3f translation, Vector3f scale) { + ArrayMatrix4x4 result = ArrayMatrix4x4.newIdentity(); + + Matrix4x4 scaling = ArrayMatrix4x4.newIdentity(); + scaling.scale(scale); + result.multiply(scaling); + result.translation(translation); + + + return result; + } + + public static Matrix4x4 fromScale(Vector3f scale) { + ArrayMatrix4x4 arrayMatrix4x4 = new ArrayMatrix4x4(); + arrayMatrix4x4.m[3][3] = 1f; + arrayMatrix4x4.scale(scale); + return arrayMatrix4x4; + } + + public static Matrix4x4 mul(Matrix4x4... matrices) { + Matrix4x4 result = ArrayMatrix4x4.newIdentity(); + for (Matrix4x4 matrix : matrices) { + result.multiply(matrix); + } + return result; + } + + public static Matrix4x4 fromRotation(Quaternion rotation) { + Matrix4x4 result = ArrayMatrix4x4.newIdentity(); + result.quaternionRotation(rotation); + return result; + } + @Override public void identity() { for (int i = 0; i < 4; i++) { From d3ca3d782285249897342b19852fe3ee8314b906 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:47:08 +0200 Subject: [PATCH 106/125] Added scalar(x, y, z) --- .../advanced/matrix/ArrayMatrix4x4.java | 15 +++++++++++++++ .../components/advanced/matrix/Matrix4x4.java | 3 +++ 2 files changed, 18 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index cc0c332..445b518 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -241,6 +241,21 @@ public void scalar(Vector3f size) { m[2][2]*=size.getZ(); } + @Override + public void scalar(float x, float y, float z) { + m[0][0]*=x; + m[0][1]*=x; + m[0][2]*=x; + + m[1][0]*=y; + m[1][1]*=y; + m[1][2]*=y; + + m[2][0]*=z; + m[2][1]*=z; + m[2][2]*=z; + } + @Override public Quaternion getRotation() { return getOtherRotation(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index ef201eb..4a9df5b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -43,4 +43,7 @@ public interface Matrix4x4 extends Matrix { Matrix4x4 duplicate(); void scalar(Vector3f size); + + void scalar(float x, float y, float z); + } From 855f179e5b5b922ea01e442257c6e3fd1eae3405 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:47:23 +0200 Subject: [PATCH 107/125] Added translation(x, y, z) --- .../maths/components/advanced/matrix/ArrayMatrix4x4.java | 7 +++++++ .../maths/components/advanced/matrix/Matrix4x4.java | 2 ++ 2 files changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 445b518..049e6d3 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -318,6 +318,13 @@ public void translation(Vector3f translation) { m[3][2] = translation.getZ(); } + @Override + public void translation(float x, float y, float z) { + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + } + @Override public void add(Matrix4x4 rotation) { for (int i = 0; i < 4; i++) { diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index 4a9df5b..db2bf6a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -15,6 +15,8 @@ public interface Matrix4x4 extends Matrix { void translation(Vector3f translation); + void translation(float x, float y, float z); + void add(Matrix4x4 rotation); void scale(Vector3f scale); From 6d0f15ecccfe14a7a9ca8fce5ae59405fa143ea9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:47:40 +0200 Subject: [PATCH 108/125] Added scale(x, y, z) --- .../maths/components/advanced/matrix/ArrayMatrix4x4.java | 7 +++++++ .../maths/components/advanced/matrix/Matrix4x4.java | 2 ++ 2 files changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 049e6d3..06ab075 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -341,6 +341,13 @@ public void scale(Vector3f scale) { m[2][2] = scale.getZ(); } + @Override + public void scale(float x, float y, float z) { + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + } + @Override public void rotationX(Angle angle) { m[1][1] = angle.cos(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index db2bf6a..a169003 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -21,6 +21,8 @@ public interface Matrix4x4 extends Matrix { void scale(Vector3f scale); + void scale(float x, float y, float z); + void rotationX(Angle angle); void rotationY(Angle angle); From 2e09fc3eabf55f1db8de388a5c1f6bf2402de4b9 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:48:26 +0200 Subject: [PATCH 109/125] Added link explaining how perspective matrix is computed --- .../radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java | 1 + 1 file changed, 1 insertion(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 06ab075..8ce852e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -485,6 +485,7 @@ public void orthographic(float right, float left, float top, float bottom, float @Override public void perspective(float fov, float aspect, float near, float far) { + //https://www.songho.ca/opengl/gl_projectionmatrix.html under "Perspective projection with horizontal FOV" identity(); float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f)))); From e8e7223f1b50a45f00cd72a06cf9cc493b205b06 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:49:13 +0200 Subject: [PATCH 110/125] Added transform(vec4, w) --- .../components/advanced/matrix/ArrayMatrix4x4.java | 10 ++++++++++ .../maths/components/advanced/matrix/Matrix4x4.java | 1 + 2 files changed, 11 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index 8ce852e..b65cf4b 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -511,6 +511,16 @@ public void transform(Vector4f toTransform) { toTransform.setW(w); } + @Override + public void transform(Vector3f toTransform, float w) { + float x = m[0][0] * toTransform.getX() + m[1][0] * toTransform.getY() + m[2][0] * toTransform.getZ() + m[3][0] * w; + float y = m[0][1] * toTransform.getX() + m[1][1] * toTransform.getY() + m[2][1] * toTransform.getZ() + m[3][1] * w; + float z = m[0][2] * toTransform.getX() + m[1][2] * toTransform.getY() + m[2][2] * toTransform.getZ() + m[3][2] * w; + toTransform.setX(x); + toTransform.setY(y); + toTransform.setZ(z); + } + @Override public void multiply(Matrix matrix) { Matrix result = new ArrayMatrix4x4(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java index a169003..f4e69a7 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/Matrix4x4.java @@ -39,6 +39,7 @@ public interface Matrix4x4 extends Matrix { void perspective(float fov, float aspect, float near, float far); void transform(Vector4f toTransform); + void transform(Vector3f toTransform, float w); void multiply(Matrix matrix); From fb323bf2410263b1d0344d8506ff90190d7f20d2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:50:44 +0200 Subject: [PATCH 111/125] Inlining multiply --- .../advanced/matrix/ArrayMatrix4x4.java | 69 ++++++++++++++++--- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java index b65cf4b..459a56e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/matrix/ArrayMatrix4x4.java @@ -523,17 +523,66 @@ public void transform(Vector3f toTransform, float w) { @Override public void multiply(Matrix matrix) { - Matrix result = new ArrayMatrix4x4(); - for (int x = 0; x < 4; x++) { - for (int y = 0; y < 4; y++) { - result.set(x, y, this.get(0, y) * matrix.get(x, 0) + - this.get(1, y) * matrix.get(x, 1) + - this.get(2, y) * matrix.get(x, 2) + - this.get(3, y) * matrix.get(x, 3)); - } - } - this.copy(result); + float a00 = this.get(0, 0); + float a01 = this.get(0, 1); + float a02 = this.get(0, 2); + float a03 = this.get(0, 3); + + float a10 = this.get(1, 0); + float a11 = this.get(1, 1); + float a12 = this.get(1, 2); + float a13 = this.get(1, 3); + + float a20 = this.get(2, 0); + float a21 = this.get(2, 1); + float a22 = this.get(2, 2); + float a23 = this.get(2, 3); + + float a30 = this.get(3, 0); + float a31 = this.get(3, 1); + float a32 = this.get(3, 2); + float a33 = this.get(3, 3); + + float b00 = matrix.get(0, 0); + float b01 = matrix.get(0, 1); + float b02 = matrix.get(0, 2); + float b03 = matrix.get(0, 3); + + float b10 = matrix.get(1, 0); + float b11 = matrix.get(1, 1); + float b12 = matrix.get(1, 2); + float b13 = matrix.get(1, 3); + + float b20 = matrix.get(2, 0); + float b21 = matrix.get(2, 1); + float b22 = matrix.get(2, 2); + float b23 = matrix.get(2, 3); + + float b30 = matrix.get(3, 0); + float b31 = matrix.get(3, 1); + float b32 = matrix.get(3, 2); + float b33 = matrix.get(3, 3); + + this.set(0, 0, a00*b00+a10*b01+a20*b02+a30*b03); + this.set(1, 0, a00*b10+a10*b11+a20*b12+a30*b13); + this.set(2, 0, a00*b20+a10*b21+a20*b22+a30*b23); + this.set(3, 0, a00*b30+a10*b31+a20*b32+a30*b33); + + this.set(0, 1, a01*b00+a11*b01+a21*b02+a31*b03); + this.set(1, 1, a01*b10+a11*b11+a21*b12+a31*b13); + this.set(2, 1, a01*b20+a11*b21+a21*b22+a31*b23); + this.set(3, 1, a01*b30+a11*b31+a21*b32+a31*b33); + + this.set(0, 2, a02*b00+a12*b01+a22*b02+a32*b03); + this.set(1, 2, a02*b10+a12*b11+a22*b12+a32*b13); + this.set(2, 2, a02*b20+a12*b21+a22*b22+a32*b23); + this.set(3, 2, a02*b30+a12*b31+a22*b32+a32*b33); + + this.set(0, 3, a03*b00+a13*b01+a23*b02+a33*b03); + this.set(1, 3, a03*b10+a13*b11+a23*b12+a33*b13); + this.set(2, 3, a03*b20+a13*b21+a23*b22+a33*b23); + this.set(3, 3, a03*b30+a13*b31+a23*b32+a33*b33); } @Override From 8c967130ee96981f89ba95638ae59f2c7133525b Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:53:29 +0200 Subject: [PATCH 112/125] Added set() --- .../advanced/quaternions/ComponentsQuaternion.java | 8 ++++++++ .../maths/components/advanced/quaternions/Quaternion.java | 2 ++ 2 files changed, 10 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index da253c1..f87d6ea 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -177,6 +177,14 @@ public void setW(float w) { this.w = w; } + @Override + public void set(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + @Override public void inverse() { this.x = -x; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index 2e659de..f31e48d 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -21,6 +21,8 @@ public interface Quaternion { void setW(float w); + void set(float x, float y, float z, float w); + void inverse(); void normalise(); From abada32a1d01f5c3ed183a41daad8868e5fe44ce Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:53:59 +0200 Subject: [PATCH 113/125] Added normaliseSafely() --- .../advanced/quaternions/ComponentsQuaternion.java | 13 ++++++++++++- .../components/advanced/quaternions/Quaternion.java | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index f87d6ea..6c335bf 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -62,7 +62,7 @@ public static Quaternion fromTwoVectors(Vector3f u, Vector3f v) { } Quaternion quaternion = new ComponentsQuaternion(w.getX(), w.getY(), w.getZ(), real_part); - quaternion.normalise(); + quaternion.normaliseSafely(); return quaternion; } @@ -201,6 +201,17 @@ public void normalise() { this.w /= magnitude; } + @Override + public void normaliseSafely() { + float magnitude = getMagnitude(); + if (magnitude==0) + return; + this.x /= magnitude; + this.y /= magnitude; + this.z /= magnitude; + this.w /= magnitude; + } + @Override public void multiply(Quaternion quaternion) { float otherW = quaternion.getW(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index f31e48d..8989a7e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -27,6 +27,8 @@ public interface Quaternion { void normalise(); + void normaliseSafely(); + void add(Quaternion quaternion); void multiply(Quaternion quaternion); From 303526a8b9b7a2755a5772067a009c78262db6d3 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:54:50 +0200 Subject: [PATCH 114/125] Added copy(vec4) --- .../advanced/quaternions/ComponentsQuaternion.java | 8 ++++++++ .../maths/components/advanced/quaternions/Quaternion.java | 3 +++ 2 files changed, 11 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 6c335bf..021f854 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -356,6 +356,14 @@ public JavaMathAngle getAngle() { return JavaMathAngle.fromRadiant(2 * Math.acos(clamp(w, -1, 1))); } + @Override + public void copy(Vector4f rotation) { + this.x = rotation.getX(); + this.y = rotation.getY(); + this.z = rotation.getZ(); + this.w = rotation.getW(); + } + @Override public void add(Quaternion quaternion) { this.x += quaternion.getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index 8989a7e..c8c5c40 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -2,6 +2,7 @@ import fr.radi3nt.maths.components.advanced.matrix.angle.Angle; import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.Vector4f; public interface Quaternion { @@ -66,4 +67,6 @@ Quaternion getRotationComponentAboutAxis( Vector3f getVector(); Angle getAngle(); + + void copy(Vector4f quaternion); } From a50d7ddbcd078bec82b174712accb1bf3d0d747e Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:55:24 +0200 Subject: [PATCH 115/125] Added getAxisAngle(vec3 out) --- .../advanced/quaternions/ComponentsQuaternion.java | 6 ++++++ .../maths/components/advanced/quaternions/Quaternion.java | 2 ++ 2 files changed, 8 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 021f854..8e2c940 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -364,6 +364,12 @@ public void copy(Vector4f rotation) { this.w = rotation.getW(); } + @Override + public Angle getAxisAngle(Vector3f axis) { + axis.copy(getAxisOrDefault(axis)); + return getAngle(); + } + @Override public void add(Quaternion quaternion) { this.x += quaternion.getX(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java index c8c5c40..ca210b2 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/Quaternion.java @@ -69,4 +69,6 @@ Quaternion getRotationComponentAboutAxis( Angle getAngle(); void copy(Vector4f quaternion); + + Angle getAxisAngle(Vector3f axis); } From 3688e6c1a8f2e151489312aeba41621a4268236d Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:57:44 +0200 Subject: [PATCH 116/125] Added fromUpVector() --- .../advanced/quaternions/ComponentsQuaternion.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 8e2c940..7e4c141 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -15,6 +15,7 @@ public class ComponentsQuaternion implements Quaternion { + private static final Vector3f UP = new SimpleVector3f(0, 1, 0); private float x; private float y; private float z; @@ -98,6 +99,10 @@ public static Quaternion fromVec4(Vector4f response) { return new ComponentsQuaternion(response.getX(), response.getY(), response.getZ(), response.getW()); } + public static Quaternion fromUpVector(Vector3f other) { + return fromTwoVectors(UP, other); + } + @Override public Quaternion getRotationComponentAboutAxis( Vector3f direction) { From 35d70db27a7a27acd94a5da7ec68e6bde8a8f7ca Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:58:03 +0200 Subject: [PATCH 117/125] Added distanceSquared() --- .../advanced/quaternions/ComponentsQuaternion.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java index 7e4c141..2f8dde8 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/advanced/quaternions/ComponentsQuaternion.java @@ -103,6 +103,14 @@ public static Quaternion fromUpVector(Vector3f other) { return fromTwoVectors(UP, other); } + public static float distanceSquared(Quaternion orientation, Quaternion targetOrientation) { + float x = (orientation.getX()-targetOrientation.getX()); + float y = (orientation.getY()-targetOrientation.getY()); + float z = (orientation.getZ()-targetOrientation.getZ()); + float w = (orientation.getW()-targetOrientation.getW()); + return x*x + y*y + z*z + w*w; + } + @Override public Quaternion getRotationComponentAboutAxis( Vector3f direction) { From fb30e4bd089c37c923cd49ee7d1572b3c0949d75 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 12:59:35 +0200 Subject: [PATCH 118/125] Added distance methods --- .../vectors/implementations/SimpleVector2f.java | 12 ++++++++++++ .../vectors/implementations/SimpleVector3f.java | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java index e8b12f5..dbb6e8a 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java @@ -28,6 +28,18 @@ public SimpleVector2f(Vector2f vector) { this.copy(vector); } + public static float distanceSquared(Vector2f first, Vector2f second) { + float x = (first.getX()-second.getX()); + float y = (first.getY()-second.getY()); + return x*x + y*y; + } + + public static float distance(float x, float y, float xo, float yo) { + float xd = x-xo; + float yd = y-yo; + return (float) Math.sqrt(xd*xd+yd*yd); + } + @Override public float getX() { return x; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java index 68f063c..bc100f4 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java @@ -43,6 +43,17 @@ public SimpleVector3f(double v, double v1, double v2) { this((float) v, (float) v1, (float) v2); } + public static float distanceSquared(Vector3f first, Vector3f second) { + float x = (first.getX()-second.getX()); + float y = (first.getY()-second.getY()); + float z = (first.getZ()-second.getZ()); + return x*x + y*y + z*z; + } + + public static float distance(Vector3f first, Vector3f second) { + return (float) Math.sqrt(distanceSquared(first, second)); + } + @Override public float getX() { return x; From a0f50697fdb44c522c9fa87b2626b673e068ea26 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:00:22 +0200 Subject: [PATCH 119/125] Added mul and sub operations --- .../maths/components/vectors/Vector4f.java | 1 + .../implementations/SimpleVector4f.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java index 119e657..c392041 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java @@ -20,6 +20,7 @@ public interface Vector4f extends Vector, OperatingVectorNf { void set(Vector3f vector3f, float w); void set(float x, float y, float z, float w); + void mul(Vector4f other); Vector4f duplicate(); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index c180fb6..40acb76 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -101,6 +101,14 @@ public void set(float x, float y, float z, float w) { setW(w); } + @Override + public void mul(Vector4f other) { + this.x *= other.getX(); + this.y *= other.getY(); + this.z *= other.getZ(); + this.w *= other.getW(); + } + @Override public float get(int row) { if (row==0) @@ -163,6 +171,16 @@ public OperatingVectorNf sub(OperatingVectorNf other) { return this; } + public Vector4f sub(Vector4f other) { + if (other.size()!=this.size()) + throw new IllegalArgumentException(); + this.x -= other.getX(); + this.y -= other.getY(); + this.z -= other.getZ(); + this.w -= other.getW(); + return this; + } + @Override public int size() { return 4; From 9acecf0c3946c1949670e95a2d6fa6089f1c1fac Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:00:41 +0200 Subject: [PATCH 120/125] Added constructor from val and w --- .../components/vectors/implementations/SimpleVector4f.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java index 40acb76..48ef9fe 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java @@ -26,6 +26,13 @@ public SimpleVector4f(Vector3f vec, float w) { this.w = w; } + public SimpleVector4f(float vec, float w) { + this.x = vec; + this.y = vec; + this.z = vec; + this.w = w; + } + public SimpleVector4f() { } From 8110180ed55328c2d2f8b5347c6405fbb437b343 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:01:09 +0200 Subject: [PATCH 121/125] Added new kinds of smoothing --- .../maths/dynamics/SmoothTransform.java | 28 ++++ .../advanced/AdvancedSmoothTransform.java | 132 ++++++++++++++++++ .../DirectionRotationSmoothDynamics.java | 6 +- .../{ => advanced}/DynamicsConstants.java | 12 +- .../{ => advanced}/FloatSmoothDynamics.java | 6 +- .../VectorRotationSmoothDynamics.java | 2 +- .../{ => advanced}/VectorSmoothDynamics.java | 13 +- .../dynamics/values/DynamicValueFactory.java | 8 ++ .../dynamics/values/TargetValueDynamic.java | 33 +++++ .../maths/dynamics/values/ValueDynamic.java | 13 ++ .../dynamics/values/ValueDynamicArray.java | 26 ++++ .../values/ValueDynamicSmoothDirection.java | 56 ++++++++ .../values/ValueDynamicSmoothPosition.java | 55 ++++++++ .../values/ValueDynamicSmoothTransform.java | 112 +++++++++++++++ .../automatic/AutomaticDynamicProperties.java | 14 ++ .../AutomaticDynamicValueFactory.java | 33 +++++ .../automatic/AutomaticValueDynamic.java | 18 +++ 17 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java rename MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/{ => advanced}/DirectionRotationSmoothDynamics.java (75%) rename MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/{ => advanced}/DynamicsConstants.java (71%) rename MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/{ => advanced}/FloatSmoothDynamics.java (93%) rename MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/{ => advanced}/VectorRotationSmoothDynamics.java (95%) rename MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/{ => advanced}/VectorSmoothDynamics.java (89%) create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java create mode 100644 MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java new file mode 100644 index 0000000..0c8fd1b --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java @@ -0,0 +1,28 @@ +package fr.radi3nt.maths.dynamics; + +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; + +public interface SmoothTransform

{ + + Vector3f getTargetPosition(); + Quaternion getTargetOrientation(); + + Vector3f getCurrentPosition(); + Quaternion getCurrentOrientation(); + + void setCurrentPosition(Vector3f position); + void setCurrentOrientation(Quaternion orientation); + + void setTargetPosition(Vector3f position); + void setTargetOrientation(Quaternion orientation); + + void setLinearProperties(P linear); + void setAngularProperties(P angular); + default void setAllProperties(P properties) { + setLinearProperties(properties); + setAngularProperties(properties); + } + + void update(float delta); +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java new file mode 100644 index 0000000..8189bd1 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java @@ -0,0 +1,132 @@ +package fr.radi3nt.maths.dynamics.advanced; + +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.Vector4f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; +import fr.radi3nt.maths.dynamics.SmoothTransform; + +public class AdvancedSmoothTransform implements SmoothTransform { + + protected final VectorSmoothDynamics positionDynamics; + protected final VectorRotationSmoothDynamics rotationDynamics; + + public final Vector3f targetPosition = new SimpleVector3f(); + public final Quaternion targetRotation = ComponentsQuaternion.zero(); + + private final Vector3f position = new SimpleVector3f(); + private final Quaternion rotation = ComponentsQuaternion.zero(); + + public AdvancedSmoothTransform(DynamicsConstants constants) { + this.positionDynamics = new VectorSmoothDynamics<>(constants, new SimpleVector3f()); + this.rotationDynamics = new VectorRotationSmoothDynamics(constants, new SimpleVector4f(0, 0, 0, 1), true); + } + + public AdvancedSmoothTransform(DynamicsConstants position, DynamicsConstants rotation) { + this.positionDynamics = new VectorSmoothDynamics<>(position, new SimpleVector3f()); + this.rotationDynamics = new VectorRotationSmoothDynamics(rotation, new SimpleVector4f(0, 0, 0, 1), true); + } + + public AdvancedSmoothTransform(Vector3f position, Quaternion rotation, DynamicsConstants positionConstants, DynamicsConstants rotationConstants) { + targetPosition.copy(position); + targetRotation.copy(rotation); + + this.position.copy(position); + this.rotation.copy(rotation); + + this.positionDynamics = new VectorSmoothDynamics<>(positionConstants, targetPosition); + this.rotationDynamics = new VectorRotationSmoothDynamics(rotationConstants, new SimpleVector4f(targetRotation), true); + } + + public void reset(Vector3f pos, Quaternion rotation) { + this.targetPosition.copy(pos); + this.position.copy(pos); + + this.rotation.copy(rotation); + this.targetRotation.copy(rotation); + + this.positionDynamics.reset(targetPosition); + Vector4f currentRot = new SimpleVector4f(rotation); + this.rotationDynamics.reset(currentRot); + } + + @Override + public Vector3f getTargetPosition() { + return targetPosition; + } + + @Override + public Quaternion getTargetOrientation() { + return targetRotation; + } + + @Override + public Vector3f getCurrentPosition() { + return position; + } + + @Override + public Quaternion getCurrentOrientation() { + return rotation; + } + + @Override + public void setCurrentPosition(Vector3f position) { + this.positionDynamics.setCurrent(position); + } + + @Override + public void setCurrentOrientation(Quaternion orientation) { + this.rotationDynamics.setCurrent(new SimpleVector4f(orientation)); + } + + @Override + public void setTargetPosition(Vector3f position) { + this.targetPosition.copy(position); + } + + @Override + public void setTargetOrientation(Quaternion orientation) { + this.targetRotation.copy(orientation); + } + + @Override + public void setLinearProperties(DynamicsConstants linear) { + positionDynamics.setConstants(linear); + } + + @Override + public void setAngularProperties(DynamicsConstants angular) { + rotationDynamics.setConstants(angular); + } + + public void update(float delta) { + positionDynamics.setInputCurrent(targetPosition); + rotationDynamics.setInputCurrent(new SimpleVector4f(targetRotation)); + + positionDynamics.update(delta); + rotationDynamics.update(delta); + + this.position.copy(positionDynamics.getResponse()); + this.rotation.copy(rotationDynamics.getResponse()); + } + + public Vector3f getLinearVelocity() { + return positionDynamics.getResponseDerivative(); + } + + public Vector3f getPosition() { + return position; + } + + public Quaternion getRotation() { + return rotation; + } + + public void setConstants(DynamicsConstants constants) { + positionDynamics.setConstants(constants); + rotationDynamics.setConstants(constants); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java similarity index 75% rename from MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java index ae9e9f5..9cae97e 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DirectionRotationSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java @@ -1,4 +1,4 @@ -package fr.radi3nt.maths.dynamics; +package fr.radi3nt.maths.dynamics.advanced; import fr.radi3nt.maths.components.vectors.Vector3f; @@ -10,10 +10,6 @@ public DirectionRotationSmoothDynamics(DynamicsConstants constants, Vector3f sta @Override public void update(float step) { - if (inputPrevious.dot(inputCurrent)<0) { - inputCurrent.mul(-1); - } - super.update(step); response.normalizeSafely(); } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java similarity index 71% rename from MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java index d72df5a..9424452 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/DynamicsConstants.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java @@ -1,4 +1,4 @@ -package fr.radi3nt.maths.dynamics; +package fr.radi3nt.maths.dynamics.advanced; import static java.lang.Math.PI; import static java.lang.Math.abs; @@ -22,6 +22,16 @@ public DynamicsConstants(float k1, float k2, float k3, float w, float z, float d this.d = d; } + /** + * @param f frequency, speed at which the system responds to inputs + * @param z damping coefficient, it controls the vibration + * @param r initial response, + *

+ */ public static DynamicsConstants from(float f, float z, float r) { float w = (float) (2f*PI*f); diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java similarity index 93% rename from MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java index 7e994ee..7b31f06 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/FloatSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java @@ -1,4 +1,4 @@ -package fr.radi3nt.maths.dynamics; +package fr.radi3nt.maths.dynamics.advanced; public class FloatSmoothDynamics { @@ -72,4 +72,8 @@ public void setCurrentAll(float currentLocalPos, float responseDerivative) { inputPrevious = currentLocalPos; this.responseDerivative = responseDerivative; } + + public void setResponseDerivative(float derivative) { + this.responseDerivative = derivative; + } } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java similarity index 95% rename from MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java index ddb03b2..6423d16 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorRotationSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java @@ -1,4 +1,4 @@ -package fr.radi3nt.maths.dynamics; +package fr.radi3nt.maths.dynamics.advanced; import fr.radi3nt.maths.components.vectors.Vector4f; import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f; diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java similarity index 89% rename from MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java rename to MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java index 2ce81fe..bc83338 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/VectorSmoothDynamics.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java @@ -1,4 +1,4 @@ -package fr.radi3nt.maths.dynamics; +package fr.radi3nt.maths.dynamics.advanced; import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf; @@ -8,6 +8,7 @@ public class VectorSmoothDynamics { protected T inputPrevious, inputCurrent; protected T response, responseDerivative; + private final T inputVelocity; private final T inputDerivativeCache; private final T responseDerivativeCache; @@ -20,6 +21,7 @@ public VectorSmoothDynamics(DynamicsConstants constants, T start) { this.inputPrevious = (T) start.duplicate(); responseDerivative = (T) start.duplicate().mul(0); inputDerivativeCache = (T) start.duplicate().mul(0); + inputVelocity = (T) start.duplicate().mul(0); responseDerivativeCache = (T) start.duplicate().mul(0); } @@ -28,11 +30,14 @@ public void update(float step) { return; inputDerivativeCache.copy(inputCurrent); inputDerivativeCache.sub(inputPrevious).div(step); + inputDerivativeCache.add(inputVelocity); + inputVelocity.mul(0); + inputPrevious.copy(inputCurrent); float k1Stable, k2Stable; if (systemIsAtHighSpeed(constants, step)) { k1Stable = constants.getK1(); - k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); + k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); //todo use pole matching } else { k1Stable = constants.getK1(); k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); @@ -94,6 +99,10 @@ public T getInputPrevious() { return inputPrevious; } + public T getInputVelocity() { + return inputVelocity; + } + public void setInputPrevious(T inputPrevious) { this.inputPrevious = inputPrevious; } diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java new file mode 100644 index 0000000..69c8362 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java @@ -0,0 +1,8 @@ +package fr.radi3nt.maths.dynamics.values; + +public interface DynamicValueFactory> { + + T createDynamicValue(P param); + ValueDynamicArray createDynamicValue(P param, int amount); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java new file mode 100644 index 0000000..29f9d94 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java @@ -0,0 +1,33 @@ +package fr.radi3nt.maths.dynamics.values; + +public abstract class TargetValueDynamic

implements ValueDynamic

{ + + protected P properties; + + protected float targetValue; + protected float currentValue; + + public TargetValueDynamic(P properties) { + this.properties = properties; + } + + @Override + public void setTargetValue(float value) { + this.targetValue = value; + } + + @Override + public void setCurrentValue(float value) { + this.currentValue = value; + } + + @Override + public float getCurrentValue() { + return currentValue; + } + + @Override + public void setProperties(P properties) { + this.properties = properties; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java new file mode 100644 index 0000000..e4834a9 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java @@ -0,0 +1,13 @@ +package fr.radi3nt.maths.dynamics.values; + +public interface ValueDynamic

{ + + void setTargetValue(float value); + void setCurrentValue(float value); + + float getCurrentValue(); + void update(float delta); + + void setProperties(P properties); + +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java new file mode 100644 index 0000000..71c53a1 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java @@ -0,0 +1,26 @@ +package fr.radi3nt.maths.dynamics.values; + +public class ValueDynamicArray> { + + private final T[] values; + + public ValueDynamicArray(T[] values) { + this.values = values; + } + + public void setProperties(P properties) { + for (T value : values) { + value.setProperties(properties); + } + } + + public void update(float delta) { + for (T value : values) { + value.update(delta); + } + } + + public T get(int index) { + return values[index]; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java new file mode 100644 index 0000000..679dfa0 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java @@ -0,0 +1,56 @@ +package fr.radi3nt.maths.dynamics.values; + +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; + +public class ValueDynamicSmoothDirection> { + + private final Vector3f targetDirection = new SimpleVector3f(); + + private final Vector3f direction = new SimpleVector3f(); + + private final ValueDynamicArray positionDynamic; + + public ValueDynamicSmoothDirection(DynamicValueFactory factory, P linear) { + this.positionDynamic = factory.createDynamicValue(linear, 3); + } + + public Vector3f getTargetDirection() { + return targetDirection; + } + + public Vector3f getCurrentDirection() { + return direction; + } + + public void setCurrentDirection(Vector3f direction) { + this.direction.set(direction); + this.positionDynamic.get(0).setCurrentValue(direction.getX()); + this.positionDynamic.get(1).setCurrentValue(direction.getY()); + this.positionDynamic.get(2).setCurrentValue(direction.getZ()); + } + + public void setTargetDirection(Vector3f direction) { + targetDirection.copy(direction); + this.positionDynamic.get(0).setTargetValue(targetDirection.getX()); + this.positionDynamic.get(1).setTargetValue(targetDirection.getY()); + this.positionDynamic.get(2).setTargetValue(targetDirection.getZ()); + } + + public void setLinearProperties(P linear) { + this.positionDynamic.setProperties(linear); + } + + + public void update(float delta) { + positionDynamic.update(delta); + + this.direction.set(positionDynamic.get(0).getCurrentValue(), + positionDynamic.get(1).getCurrentValue(), + positionDynamic.get(2).getCurrentValue()); + this.direction.normalizeSafely(); + this.positionDynamic.get(0).setCurrentValue(direction.getX()); + this.positionDynamic.get(1).setCurrentValue(direction.getY()); + this.positionDynamic.get(2).setCurrentValue(direction.getZ()); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java new file mode 100644 index 0000000..24fb4da --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java @@ -0,0 +1,55 @@ +package fr.radi3nt.maths.dynamics.values; + +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.maths.dynamics.SmoothTransform; + +public class ValueDynamicSmoothPosition> { + + private final Vector3f targetPosition = new SimpleVector3f(); + + private final Vector3f position = new SimpleVector3f(); + + private final ValueDynamicArray positionDynamic; + + public ValueDynamicSmoothPosition(DynamicValueFactory factory, P linear) { + this.positionDynamic = factory.createDynamicValue(linear, 3); + } + + public Vector3f getTargetPosition() { + return targetPosition; + } + + public Vector3f getCurrentPosition() { + return position; + } + + public void setCurrentPosition(Vector3f position) { + this.position.set(position); + this.positionDynamic.get(0).setCurrentValue(position.getX()); + this.positionDynamic.get(1).setCurrentValue(position.getY()); + this.positionDynamic.get(2).setCurrentValue(position.getZ()); + } + + public void setTargetPosition(Vector3f position) { + targetPosition.copy(position); + this.positionDynamic.get(0).setTargetValue(targetPosition.getX()); + this.positionDynamic.get(1).setTargetValue(targetPosition.getY()); + this.positionDynamic.get(2).setTargetValue(targetPosition.getZ()); + } + + public void setLinearProperties(P linear) { + this.positionDynamic.setProperties(linear); + } + + + public void update(float delta) { + positionDynamic.update(delta); + + this.position.set(positionDynamic.get(0).getCurrentValue(), + positionDynamic.get(1).getCurrentValue(), + positionDynamic.get(2).getCurrentValue()); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java new file mode 100644 index 0000000..783bf6b --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java @@ -0,0 +1,112 @@ +package fr.radi3nt.maths.dynamics.values; + +import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion; +import fr.radi3nt.maths.components.advanced.quaternions.Quaternion; +import fr.radi3nt.maths.components.vectors.Vector3f; +import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f; +import fr.radi3nt.maths.dynamics.SmoothTransform; + +public class ValueDynamicSmoothTransform> implements SmoothTransform

{ + + private final Vector3f targetPosition = new SimpleVector3f(); + private final Quaternion targetOrientation = ComponentsQuaternion.zero(); + + private final Vector3f position = new SimpleVector3f(); + private final Quaternion orientation = ComponentsQuaternion.zero(); + + private final ValueDynamicArray positionDynamic; + private final ValueDynamicArray rotationDynamic; + + public ValueDynamicSmoothTransform(DynamicValueFactory factory, P linear, P angular) { + this.positionDynamic = factory.createDynamicValue(linear, 3); + this.rotationDynamic = factory.createDynamicValue(angular, 4); + } + + @Override + public Vector3f getTargetPosition() { + return targetPosition; + } + + @Override + public Quaternion getTargetOrientation() { + return targetOrientation; + } + + @Override + public Vector3f getCurrentPosition() { + return position; + } + + @Override + public Quaternion getCurrentOrientation() { + return orientation; + } + + @Override + public void setCurrentPosition(Vector3f position) { + this.position.set(position); + this.positionDynamic.get(0).setCurrentValue(position.getX()); + this.positionDynamic.get(1).setCurrentValue(position.getY()); + this.positionDynamic.get(2).setCurrentValue(position.getZ()); + } + + @Override + public void setCurrentOrientation(Quaternion orientation) { + this.orientation.copy(orientation); + } + + @Override + public void setTargetPosition(Vector3f position) { + targetPosition.copy(position); + this.positionDynamic.get(0).setTargetValue(targetPosition.getX()); + this.positionDynamic.get(1).setTargetValue(targetPosition.getY()); + this.positionDynamic.get(2).setTargetValue(targetPosition.getZ()); + } + + @Override + public void setTargetOrientation(Quaternion orientation) { + targetOrientation.copy(orientation); + } + + @Override + public void setLinearProperties(P linear) { + this.positionDynamic.setProperties(linear); + } + + @Override + public void setAngularProperties(P angular) { + this.rotationDynamic.setProperties(angular); + } + + @Override + public void update(float delta) { + Quaternion currentTarget = targetOrientation.duplicate(); + + if (orientation.dot(currentTarget) <= 0) { + orientation.multiply(-1f); + } + this.rotationDynamic.get(0).setCurrentValue(orientation.getX()); + this.rotationDynamic.get(1).setCurrentValue(orientation.getY()); + this.rotationDynamic.get(2).setCurrentValue(orientation.getZ()); + this.rotationDynamic.get(3).setCurrentValue(orientation.getW()); + + this.rotationDynamic.get(0).setTargetValue(currentTarget.getX()); + this.rotationDynamic.get(1).setTargetValue(currentTarget.getY()); + this.rotationDynamic.get(2).setTargetValue(currentTarget.getZ()); + this.rotationDynamic.get(3).setTargetValue(currentTarget.getW()); + + positionDynamic.update(delta); + rotationDynamic.update(delta); + + this.position.set(positionDynamic.get(0).getCurrentValue(), + positionDynamic.get(1).getCurrentValue(), + positionDynamic.get(2).getCurrentValue()); + + this.orientation.set( + rotationDynamic.get(0).getCurrentValue(), + rotationDynamic.get(1).getCurrentValue(), + rotationDynamic.get(2).getCurrentValue(), + rotationDynamic.get(3).getCurrentValue()); + this.orientation.normaliseSafely(); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java new file mode 100644 index 0000000..3d6cf64 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java @@ -0,0 +1,14 @@ +package fr.radi3nt.maths.dynamics.values.automatic; + +public class AutomaticDynamicProperties { + + private final float agility; + + public AutomaticDynamicProperties(float agility) { + this.agility = agility; + } + + public float getAgility() { + return agility; + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java new file mode 100644 index 0000000..2b452be --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java @@ -0,0 +1,33 @@ +package fr.radi3nt.maths.dynamics.values.automatic; + +import fr.radi3nt.maths.dynamics.values.DynamicValueFactory; +import fr.radi3nt.maths.dynamics.values.ValueDynamicArray; + +public class AutomaticDynamicValueFactory implements DynamicValueFactory { + + public static final DynamicValueFactory DEFAULT = new AutomaticDynamicValueFactory(); + + private final float defaultValue; + + public AutomaticDynamicValueFactory(float defaultValue) { + this.defaultValue = defaultValue; + } + + public AutomaticDynamicValueFactory() { + this(0); + } + + @Override + public AutomaticValueDynamic createDynamicValue(AutomaticDynamicProperties param) { + return new AutomaticValueDynamic(param, defaultValue); + } + + @Override + public ValueDynamicArray createDynamicValue(AutomaticDynamicProperties param, int amount) { + AutomaticValueDynamic[] values = new AutomaticValueDynamic[amount]; + for (int i = 0; i < amount; i++) { + values[i] = new AutomaticValueDynamic(param, defaultValue); + } + return new ValueDynamicArray<>(values); + } +} diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java new file mode 100644 index 0000000..90db8c0 --- /dev/null +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java @@ -0,0 +1,18 @@ +package fr.radi3nt.maths.dynamics.values.automatic; + +import fr.radi3nt.maths.dynamics.values.TargetValueDynamic; + +public class AutomaticValueDynamic extends TargetValueDynamic { + + public AutomaticValueDynamic(AutomaticDynamicProperties properties, float currentValue) { + super(properties); + this.currentValue = currentValue; + this.targetValue = currentValue; + } + + public void update(float delta) { + float distance = targetValue - currentValue; + currentValue += distance * Math.min(properties.getAgility() * delta, 1); + } + +} From 9b21ae104333fd28765625e371d7d170e68332e2 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:11:55 +0200 Subject: [PATCH 122/125] Added more noise classes --- .../noise/generator/DoubleNoise3D.java | 8 ++++ .../noise/generator/FastSimplexNoise3D.java | 37 +++++++++++++++++++ .../noise/simplex/SeededSimplexNoise.java | 30 +++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java create mode 100644 NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java create mode 100644 NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java new file mode 100644 index 0000000..17fe6e6 --- /dev/null +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java @@ -0,0 +1,8 @@ +package fr.radi3nt.noise.generator; + +public interface DoubleNoise3D { + + double noise(double x, double y, double z); + double noise(double x, double y, double z, double w); + +} diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java new file mode 100644 index 0000000..0766435 --- /dev/null +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java @@ -0,0 +1,37 @@ +package fr.radi3nt.noise.generator; + +import fr.radi3nt.noise.FastSimplexNoise; + +import java.util.Random; + +public class FastSimplexNoise3D implements DoubleNoise3D { + + private final long seed; + private final double size; + + private final double offsetX; + private final double offsetY; + private final double offsetZ; + private final double offsetW; + + public FastSimplexNoise3D(long seed, double size) { + this.seed = seed; + this.size = size; + + Random random = new Random(seed); + this.offsetX = random.nextDouble()*1024D-512D; + this.offsetY = random.nextDouble()*1024D-512D; + this.offsetZ = random.nextDouble()*1024D-512D; + this.offsetW = random.nextDouble()*1024D-512D; + } + + @Override + public double noise(double x, double y, double z) { + return FastSimplexNoise.noise(x*size + offsetX, y*size+ offsetY, z*size+ offsetZ)*0.5d+0.5d; + } + + @Override + public double noise(double x, double y, double z, double w) { + return FastSimplexNoise.noise(x*size + offsetX, y*size+ offsetY, z*size+ offsetZ, w*size+offsetW)*0.5d+0.5d; + } +} diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java new file mode 100644 index 0000000..fe48e8e --- /dev/null +++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java @@ -0,0 +1,30 @@ +package fr.radi3nt.noise.simplex; + +import java.util.Random; + +public class SeededSimplexNoise { + + private final long seed; + + private final float offsetX; + private final float offsetY; + private final float offsetZ; + + public SeededSimplexNoise(long seed) { + this.seed = seed; + Random random = new Random(seed); + offsetX = (float) (random.nextDouble()*1024); + offsetY = (float) (random.nextDouble()*1024); + offsetZ = (float) (random.nextDouble()*1024); + } + + public float noise(final float x, final float y) { + return SimplexNoise.noise(x+offsetX, y+offsetY); + } + + public float noise(final float x, final float y, final float z) { + return SimplexNoise.noise(x+offsetX, y+offsetY, z+offsetZ); + } + + +} From 1e542186a77d180e6e7edf85d77c7929a51bd7d8 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:12:52 +0200 Subject: [PATCH 123/125] Added new constructors to CubicBezierSplineBuilder3D and BezierPoint3D --- .../builder/bezier/dim3/BezierPoint3D.java | 5 +++++ .../bezier/dim3/CubicBezierSplineBuilder3D.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java index 469b77a..6690a0e 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java @@ -1,5 +1,6 @@ package fr.radi3nt.spline.splines.builder.bezier.dim3; +import fr.radi3nt.maths.components.vectors.Vector3f; import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint; public class BezierPoint3D { @@ -18,6 +19,10 @@ public BezierPoint3D(float pointX, float pointControlBeforeX, float pointControl this(new BezierPoint(pointX, pointControlBeforeX, pointControlAfterX), new BezierPoint(pointY, pointControlBeforeY, pointControlAfterY), new BezierPoint(pointZ, pointControlBeforeZ, pointControlAfterZ)); } + public BezierPoint3D(Vector3f position, Vector3f beforeDirection, Vector3f afterDirection) { + this(new BezierPoint(position.getX(), beforeDirection.getX(), afterDirection.getX()), new BezierPoint(position.getY(), beforeDirection.getY(), afterDirection.getY()), new BezierPoint(position.getZ(), beforeDirection.getZ(), afterDirection.getZ())); + } + public BezierPoint getXAxis() { return xAxis; } diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java index b8feaf9..71bca23 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java @@ -34,6 +34,23 @@ public CubicBezierSplineBuilder3D(BezierPoint3D... positions) { splineBuilders[2] = new CubicBezierSplineBuilder(zPos); } + public CubicBezierSplineBuilder3D(int length) { + BezierPoint[] xPos = new BezierPoint[length]; + BezierPoint[] yPos = new BezierPoint[length]; + BezierPoint[] zPos = new BezierPoint[length]; + + for (int i = 0; i < length; i++) { + BezierPoint3D position = new BezierPoint3D(0, 0, 0, 0, 0, 0, 0, 0, 0); + xPos[i] = position.getXAxis(); + yPos[i] = position.getYAxis(); + zPos[i] = position.getZAxis(); + } + + splineBuilders[0] = new CubicBezierSplineBuilder(xPos); + splineBuilders[1] = new CubicBezierSplineBuilder(yPos); + splineBuilders[2] = new CubicBezierSplineBuilder(zPos); + } + public Spline3D build() { return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build()); } From 234f727f003630aafbb646246026399692c73486 Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Thu, 31 Jul 2025 13:13:17 +0200 Subject: [PATCH 124/125] Added new constructor to BSplineBuilder3D --- .../splines/builder/bspline/dim3/BSplineBuilder3D.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java index 7e16247..eff2f87 100644 --- a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java +++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java @@ -26,6 +26,16 @@ public BSplineBuilder3D(Vector3f... positions) { splineBuilders[2] = new BSplineBuilder(zPos); } + public BSplineBuilder3D(int count) { + float[] xPos = new float[count]; + float[] yPos = new float[count]; + float[] zPos = new float[count]; + + splineBuilders[0] = new BSplineBuilder(xPos); + splineBuilders[1] = new BSplineBuilder(yPos); + splineBuilders[2] = new BSplineBuilder(zPos); + } + public Spline3D build() { return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build()); } From 84d571275c97acebceb3af8b2ecf01884b15d12b Mon Sep 17 00:00:00 2001 From: Radi3nt Date: Wed, 20 Aug 2025 14:30:26 +0200 Subject: [PATCH 125/125] Made it possible to change constants --- .../maths/dynamics/advanced/AdvancedSmoothTransform.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java index 8189bd1..70a65db 100644 --- a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java +++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java @@ -129,4 +129,13 @@ public void setConstants(DynamicsConstants constants) { positionDynamics.setConstants(constants); rotationDynamics.setConstants(constants); } + + public void setPositionConstants(DynamicsConstants constants) { + positionDynamics.setConstants(constants); + } + + public void setRotationConstants(DynamicsConstants constants) { + rotationDynamics.setConstants(constants); + } + }