diff --git a/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDCalculator.java b/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDCalculator.java deleted file mode 100644 index 8ce6b630..00000000 --- a/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDCalculator.java +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.control.angle.feedback; - -import com.stuypulse.stuylib.control.angle.AngleController; -import com.stuypulse.stuylib.math.Angle; -import com.stuypulse.stuylib.math.SLMath; -import com.stuypulse.stuylib.network.SmartNumber; -import com.stuypulse.stuylib.streams.numbers.filters.IFilter; -import com.stuypulse.stuylib.streams.numbers.filters.IFilterGroup; -import com.stuypulse.stuylib.streams.numbers.filters.TimedMovingAverage; -import com.stuypulse.stuylib.util.StopWatch; - -/** - * This is a Bang-Bang controller that while controlling the robot, will be able to calculate the - * values for the PID controller. It does this by taking the results of oscillations, then creating - * a PIDController withe the correct values once the oscillations have been measured. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class AnglePIDCalculator extends AngleController { - - // Maximum amount of time between update commands before the calculator - // resets its measurements - private static final double kMaxTimeBeforeReset = 0.5; - - // The minimum period length that will be accepted as a valid period - private static final double kMinPeriodTime = 0.05; - - // The filter easuring the period and amplitude - private static IFilter getMeasurementFilter() { - // This is a mix between accuracy and speed of updating. - // Takes about 6 periods to get accurate results - return new IFilterGroup(new TimedMovingAverage(30)); - } - - // Internal timer used by PID Calculator - private StopWatch mTimer; - - // The speed that the bang bang controller will run at - private Number mControlSpeed; - private double mCurrentSpeed; - - // The results of the period and amplitude - private double mPeriod; - private double mAmplitude; - - // The filters used to average the period and amplitudes - private IFilter mPeriodFilter; - private IFilter mAmplitudeFilter; - - // Timer that keeps track of the length of a period - private StopWatch mPeriodTimer; - - // The min and max of the wave - private double mLocalMax; - - // Whether or not the system will measure the oscillation - private boolean mRunning; - - /** @param speed motor output for bang bang controller */ - public AnglePIDCalculator(Number speed) { - mTimer = new StopWatch(); - - mControlSpeed = speed; - mCurrentSpeed = mControlSpeed.doubleValue(); - - mPeriod = 0; - mPeriodFilter = getMeasurementFilter(); - - mAmplitude = 0; - mAmplitudeFilter = getMeasurementFilter(); - - mPeriodTimer = new StopWatch(); - mLocalMax = 0; - - mRunning = false; - } - - /** - * @param speed sets speed for motor output of controller - * @return the calculated result from the PIDController - */ - public AnglePIDCalculator setControlSpeed(Number speed) { - mControlSpeed = SmartNumber.setNumber(mControlSpeed, speed); - return this; - } - - protected double calculate(Angle setpoint, Angle measurement) { - // Calculate error & time step - double error = setpoint.sub(measurement).toRadians(); - double dt = mTimer.reset(); - - // If there is a gap in updates, then disable until next period - if (dt > kMaxTimeBeforeReset) { - mRunning = false; - } - - // Check if we crossed 0, ie, time for next update - if (Math.signum(mCurrentSpeed) != Math.signum(error)) { - // Update the controller - mCurrentSpeed = mControlSpeed.doubleValue() * Math.signum(error); - - // Get period and amplitude - double period = mPeriodTimer.reset() * 2.0; - double amplitude = mLocalMax; - - // If we are running and period is valid, record it - if (mRunning && kMinPeriodTime < period) { - mPeriod = mPeriodFilter.get(period); - mAmplitude = mAmplitudeFilter.get(amplitude); - } - - // Reset everything - mLocalMax = 0; - mRunning = true; - } - - // Calculate amplitude by recording maximum - mLocalMax = Math.max(Math.abs(mLocalMax), Math.abs(error)); - - // Return bang bang control - return mCurrentSpeed; - } - - /** - * Adjusted Amplitude of Oscillations - * - * @return Get calculated K value for PID value equation - */ - public double getK() { - return (4.0 * mControlSpeed.doubleValue()) / (Math.PI * mAmplitude); - } - - /** - * Period of Oscillations - * - * @return Get calculated T value for PID value equation - */ - public double getT() { - return mPeriod; - } - - /** - * @param kP p multiplier when calculating values - * @param kI p multiplier when calculating values - * @param kD p multiplier when calculating values - * @return calculated PID controller based off of measurements - */ - private AnglePIDController getPIDController(double kP, double kI, double kD) { - kP = Math.max(kP, 0.0); - kI = Math.max(kI, 0.0); - kD = Math.max(kD, 0.0); - - if (mAmplitude > 0) { - double t = getT(); - double k = getK(); - - return new AnglePIDController(kP * (k), kI * (k / t), kD * (k * t)); - } else { - return new AnglePIDController(-1, -1, -1); - } - } - - /** @return calculated PID controller based off of measurements */ - public AnglePIDController getPIDController() { - return getPIDController(0.6, 1.2, 3.0 / 40.0); - } - - /** @return calculated PI controller based off of measurements */ - public AnglePIDController getPIController() { - return getPIDController(0.45, 0.54, -1); - } - - /** @return calculated PD controller based off of measurements */ - public AnglePIDController getPDController() { - return getPIDController(0.8, -1, 1.0 / 10.0); - } - - /** @return calculated P controller based off of measurements */ - public AnglePIDController getPController() { - return getPIDController(0.5, -1, -1); - } - - /** @return information about this PIDController */ - public String toString() { - return "(K: " - + SLMath.round(getK(), 4) - + ", T: " - + SLMath.round(getT(), 4) - + ") " - + getPIDController().toString(); - } -} diff --git a/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDController.java b/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDController.java index 2bdc4844..ffe6e0b7 100644 --- a/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDController.java +++ b/src/com/stuypulse/stuylib/control/angle/feedback/AnglePIDController.java @@ -190,15 +190,4 @@ public AnglePIDController setDerivativeFilter(IFilter... derivativeFilter) { mDFilter = IFilter.create(derivativeFilter); return this; } - - /** @return information about this PIDController */ - public String toString() { - return "(P: " - + SLMath.round(getP(), 4) - + ", I: " - + SLMath.round(getI(), 4) - + ", D: " - + SLMath.round(getD(), 4) - + ")"; - } } diff --git a/src/com/stuypulse/stuylib/control/feedback/PIDCalculator.java b/src/com/stuypulse/stuylib/control/feedback/PIDCalculator.java deleted file mode 100644 index e6821cad..00000000 --- a/src/com/stuypulse/stuylib/control/feedback/PIDCalculator.java +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.control.feedback; - -import com.stuypulse.stuylib.control.Controller; -import com.stuypulse.stuylib.math.SLMath; -import com.stuypulse.stuylib.network.SmartNumber; -import com.stuypulse.stuylib.streams.numbers.filters.IFilter; -import com.stuypulse.stuylib.streams.numbers.filters.IFilterGroup; -import com.stuypulse.stuylib.streams.numbers.filters.TimedMovingAverage; -import com.stuypulse.stuylib.util.StopWatch; - -/** - * This is a Bang-Bang controller that while controlling the robot, will be able to calculate the - * values for the PID controller. It does this by taking the results of oscillations, then creating - * a PIDController withe the correct values once the oscillations have been measured. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class PIDCalculator extends Controller { - - // Maximum amount of time between update commands before the calculator - // resets its measurements - private static final double kMaxTimeBeforeReset = 0.5; - - // The minimum period length that will be accepted as a valid period - private static final double kMinPeriodTime = 0.05; - - // The filter easuring the period and amplitude - private static IFilter getMeasurementFilter() { - // This is a mix between accuracy and speed of updating. - // Takes about 6 periods to get accurate results - return new IFilterGroup(new TimedMovingAverage(30)); - } - - // Internal timer used by PID Calculator - private StopWatch mTimer; - - // The speed that the bang bang controller will run at - private Number mControlSpeed; - private double mCurrentSpeed; - - // The results of the period and amplitude - private double mPeriod; - private double mAmplitude; - - // The filters used to average the period and amplitudes - private IFilter mPeriodFilter; - private IFilter mAmplitudeFilter; - - // Timer that keeps track of the length of a period - private StopWatch mPeriodTimer; - - // The min and max of the wave - private double mLocalMax; - - // Whether or not the system will measure the oscillation - private boolean mRunning; - - /** @param speed motor output for bang bang controller */ - public PIDCalculator(Number speed) { - mTimer = new StopWatch(); - - mControlSpeed = speed; - mCurrentSpeed = mControlSpeed.doubleValue(); - - mPeriod = 0; - mPeriodFilter = getMeasurementFilter(); - - mAmplitude = 0; - mAmplitudeFilter = getMeasurementFilter(); - - mPeriodTimer = new StopWatch(); - mLocalMax = 0; - - mRunning = false; - } - - /** - * @param speed sets speed for motor output of controller - * @return the calculated result from the PIDController - */ - public PIDCalculator setControlSpeed(Number speed) { - mControlSpeed = SmartNumber.setNumber(mControlSpeed, speed); - return this; - } - - protected double calculate(double setpoint, double measurement) { - // Calculate error & time step - double error = setpoint - measurement; - double dt = mTimer.reset(); - - // If there is a gap in updates, then disable until next period - if (dt > kMaxTimeBeforeReset) { - mRunning = false; - } - - // Check if we crossed 0, ie, time for next update - if (Math.signum(mCurrentSpeed) != Math.signum(error)) { - // Update the controller - mCurrentSpeed = mControlSpeed.doubleValue() * Math.signum(error); - - // Get period and amplitude - double period = mPeriodTimer.reset() * 2.0; - double amplitude = mLocalMax; - - // If we are running and period is valid, record it - if (mRunning && kMinPeriodTime < period) { - mPeriod = mPeriodFilter.get(period); - mAmplitude = mAmplitudeFilter.get(amplitude); - } - - // Reset everything - mLocalMax = 0; - mRunning = true; - } - - // Calculate amplitude by recording maximum - mLocalMax = Math.max(Math.abs(mLocalMax), Math.abs(error)); - - // Return bang bang control - return mCurrentSpeed; - } - - /** - * Adjusted Amplitude of Oscillations - * - * @return Get calculated K value for PID value equation - */ - public double getK() { - return (4.0 * mControlSpeed.doubleValue()) / (Math.PI * mAmplitude); - } - - /** - * Period of Oscillations - * - * @return Get calculated T value for PID value equation - */ - public double getT() { - return mPeriod; - } - - /** - * @param kP p multiplier when calculating values - * @param kI p multiplier when calculating values - * @param kD p multiplier when calculating values - * @return calculated PID controller based off of measurements - */ - private PIDController getPIDController(double kP, double kI, double kD) { - kP = Math.max(kP, 0.0); - kI = Math.max(kI, 0.0); - kD = Math.max(kD, 0.0); - - if (mAmplitude > 0) { - double t = getT(); - double k = getK(); - - return new PIDController(kP * (k), kI * (k / t), kD * (k * t)); - } else { - return new PIDController(-1, -1, -1); - } - } - - /** @return calculated PID controller based off of measurements */ - public PIDController getPIDController() { - return getPIDController(0.6, 1.2, 3.0 / 40.0); - } - - /** @return calculated PI controller based off of measurements */ - public PIDController getPIController() { - return getPIDController(0.45, 0.54, -1); - } - - /** @return calculated PD controller based off of measurements */ - public PIDController getPDController() { - return getPIDController(0.8, -1, 1.0 / 10.0); - } - - /** @return calculated P controller based off of measurements */ - public PIDController getPController() { - return getPIDController(0.5, -1, -1); - } - - /** @return information about this PIDController */ - public String toString() { - return "(K: " - + SLMath.round(getK(), 4) - + ", T: " - + SLMath.round(getT(), 4) - + ") " - + getPIDController().toString(); - } -} diff --git a/src/com/stuypulse/stuylib/control/feedback/PIDController.java b/src/com/stuypulse/stuylib/control/feedback/PIDController.java index e404440e..4ee4a422 100644 --- a/src/com/stuypulse/stuylib/control/feedback/PIDController.java +++ b/src/com/stuypulse/stuylib/control/feedback/PIDController.java @@ -196,15 +196,4 @@ public PIDController setDerivativeFilter(IFilter... derivativeFilter) { mDFilter = IFilter.create(derivativeFilter); return this; } - - /** @return information about this PIDController */ - public String toString() { - return "(P: " - + SLMath.round(getP(), 4) - + ", I: " - + SLMath.round(getI(), 4) - + ", D: " - + SLMath.round(getD(), 4) - + ")"; - } } diff --git a/src/com/stuypulse/stuylib/input/GamepadState.java b/src/com/stuypulse/stuylib/input/GamepadState.java deleted file mode 100644 index d8feafcd..00000000 --- a/src/com/stuypulse/stuylib/input/GamepadState.java +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input; - -/** - * This class stores the state of a {@link Gamepad} as all of the different values for its buttons - * and axis. - * - *

It can be constructed by passing in a {@link Gamepad}, which it will grab all of the current - * values and store them. - * - *

This class implements all of the functions for {@link Gamepad}, making it a valid gamepad that - * something can call. - * - *

TODO: this class is designed to be turned into a JSON string and back, which has yet to be - * implemented. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class GamepadState extends Gamepad { - - /*************************************/ - /*** VARIABLES MAKING UP THE STATE ***/ - /*************************************/ - - public final double stickLeftX; - - public final double stickLeftY; - - public final double stickRightX; - public final double stickRightY; - - public final boolean dpadUp; - public final boolean dpadDown; - public final boolean dpadLeft; - public final boolean dpadRight; - - public final boolean bumperLeft; - public final boolean bumperRight; - - public final double triggerLeft; - public final double triggerRight; - - public final boolean buttonTop; - public final boolean buttonBottom; - public final boolean buttonLeft; - public final boolean buttonRight; - - public final boolean buttonSelect; - public final boolean buttonStart; - - public final boolean buttonStickLeft; - public final boolean buttonStickRight; - - /*******************/ - /*** CONSTRUCTOR ***/ - /*******************/ - - /** @param gamepad Gamepad class to record in the state */ - public GamepadState(Gamepad gamepad) { - this.stickLeftX = gamepad.getLeftX(); - this.stickLeftY = gamepad.getLeftY(); - - this.stickRightX = gamepad.getRightX(); - this.stickRightY = gamepad.getRightY(); - - this.dpadUp = gamepad.getRawDPadUp(); - this.dpadDown = gamepad.getRawDPadDown(); - this.dpadLeft = gamepad.getRawDPadLeft(); - this.dpadRight = gamepad.getRawDPadRight(); - - this.bumperLeft = gamepad.getRawLeftBumper(); - this.bumperRight = gamepad.getRawRightBumper(); - - this.triggerLeft = gamepad.getLeftTrigger(); - this.triggerRight = gamepad.getRightTrigger(); - - this.buttonTop = gamepad.getRawTopButton(); - this.buttonBottom = gamepad.getRawBottomButton(); - this.buttonLeft = gamepad.getRawLeftButton(); - this.buttonRight = gamepad.getRawRightButton(); - - this.buttonSelect = gamepad.getRawSelectButton(); - this.buttonStart = gamepad.getRawStartButton(); - - this.buttonStickLeft = gamepad.getRawLeftStickButton(); - this.buttonStickRight = gamepad.getRawRightStickButton(); - } - - /*******************************/ - /*** GAMEPAD STATE FUNCTIONS ***/ - /*******************************/ - - // TODO: JSON FORMATTING - - /****************************************/ - /*** GAMEPAD IMPLEMENTATION FUNCTIONS ***/ - /****************************************/ - - // Left Stick // - @Override - public double getLeftX() { - return this.stickLeftX; - } - - @Override - public double getLeftY() { - return this.stickLeftY; - } - - // Right Stick // - @Override - public double getRightX() { - return this.stickRightX; - } - - @Override - public double getRightY() { - return this.stickRightY; - } - - // D-Pad // - @Override - public boolean getRawDPadUp() { - return this.dpadUp; - } - - @Override - public boolean getRawDPadDown() { - return this.dpadDown; - } - - @Override - public boolean getRawDPadLeft() { - return this.dpadLeft; - } - - @Override - public boolean getRawDPadRight() { - return this.dpadRight; - } - - // Bumpers // - @Override - public boolean getRawLeftBumper() { - return this.bumperLeft; - } - - @Override - public boolean getRawRightBumper() { - return this.bumperRight; - } - - // Triggers // - @Override - public double getLeftTrigger() { - return this.triggerLeft; - } - - @Override - public double getRightTrigger() { - return this.triggerRight; - } - - // Face Buttons // - @Override - public boolean getRawTopButton() { - return this.buttonTop; - } - - @Override - public boolean getRawBottomButton() { - return this.buttonBottom; - } - - @Override - public boolean getRawLeftButton() { - return this.buttonLeft; - } - - @Override - public boolean getRawRightButton() { - return this.buttonRight; - } - - // Start / Select / Option // - @Override - public boolean getRawSelectButton() { - return this.buttonSelect; - } - - @Override - public boolean getRawStartButton() { - return this.buttonStart; - } - - // Analog Stick Buttons // - @Override - public boolean getRawLeftStickButton() { - return this.buttonStickLeft; - } - - @Override - public boolean getRawRightStickButton() { - return this.buttonStickRight; - } -} diff --git a/src/com/stuypulse/stuylib/input/gamepads/keyboard/KeyGamepad.java b/src/com/stuypulse/stuylib/input/gamepads/keyboard/KeyGamepad.java deleted file mode 100644 index 904a162e..00000000 --- a/src/com/stuypulse/stuylib/input/gamepads/keyboard/KeyGamepad.java +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.gamepads.keyboard; - -import com.stuypulse.stuylib.input.Gamepad; - -/** - * This is a base class for a gamepad controlled via keyboard. This class controls the keymappings. - * All a child controller needs to do is provide a way to check if any keyboard button is - * pressed. - * - *

- * - *
- * - * @see com.stuypulse.stuylib.streams.numbers.filters.IFilter - * @author Myles Pasetsky (selym3) - */ -public class KeyGamepad extends Gamepad { - - public KeyGamepad() {} - - protected boolean getKey(String name) { - return false; - } - - private final int getDirection(String pos, String neg) { - return (getKey(pos) ? 1 : 0) - (getKey(neg) ? 1 : 0); - } - - public double getLeftX() { - return (getDirection("d", "a")); - } - - public double getLeftY() { - return (getDirection("w", "s")); - } - - // Right Stick // - public double getRightX() { - return (getDirection("l", "j")); - } - - public double getRightY() { - return (getDirection("i", "k")); - } - - // D-Pad // - public boolean getRawDPadUp() { - return getKey("numpad-8") || getKey("up"); - } - - public boolean getRawDPadDown() { - return getKey("numpad-2") || getKey("down"); - } - - public boolean getRawDPadLeft() { - return getKey("numpad-4") || getKey("left"); - } - - public boolean getRawDPadRight() { - return getKey("numpad-6") || getKey("right"); - } - - // Bumpers // - public boolean getRawLeftBumper() { - return getKey("e"); - } - - public boolean getRawRightBumper() { - return getKey("u"); - } - - // Triggers // - public double getLeftTrigger() { - return (getKey("q") ? 1 : 0); - } - - public double getRightTrigger() { - return (getKey("o") ? 1 : 0); - } - - // Face Buttons // - public boolean getRawLeftButton() { - return getKey("z"); - } - - public boolean getRawRightButton() { - return getKey("x"); - } - - public boolean getRawTopButton() { - return getKey("c"); - } - - public boolean getRawBottomButton() { - return getKey("v"); - } - - // Start / Select // - public boolean getRawSelectButton() { - return getKey("r"); - } - - public boolean getRawStartButton() { - return getKey("t"); - } - - // Analog Stick Buttons // - public boolean getRawLeftStickButton() { - return getKey("f"); - } - - public boolean getRawRightStickButton() { - return getKey("h"); - } -} diff --git a/src/com/stuypulse/stuylib/input/gamepads/keyboard/NetKeyGamepad.java b/src/com/stuypulse/stuylib/input/gamepads/keyboard/NetKeyGamepad.java deleted file mode 100644 index 3b3bc851..00000000 --- a/src/com/stuypulse/stuylib/input/gamepads/keyboard/NetKeyGamepad.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.gamepads.keyboard; - -import com.stuypulse.stuylib.input.keyboard.NetKeyboard; - -/** - * This class takes data from a {@link NetKeyboard} and puts it into a {@link - * com.stuypulse.stuylib.input.Gamepad} - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class NetKeyGamepad extends KeyGamepad { - - /** Underlying Network Keyboard */ - private NetKeyboard mKeyboard; - - /** - * Opens Network Keyboard Gamepad - * - * @param port virtual port - */ - public NetKeyGamepad(int port) { - mKeyboard = new NetKeyboard(port); - } - - /** - * Get boolean for if key is pressed - * - * @param key key name - * @return if key is pressed - */ - @Override - public boolean getKey(String key) { - return mKeyboard.getKey(key); - } -} diff --git a/src/com/stuypulse/stuylib/input/gamepads/keyboard/SimKeyGamepad.java b/src/com/stuypulse/stuylib/input/gamepads/keyboard/SimKeyGamepad.java deleted file mode 100644 index 500e0eb9..00000000 --- a/src/com/stuypulse/stuylib/input/gamepads/keyboard/SimKeyGamepad.java +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.gamepads.keyboard; - -import com.stuypulse.stuylib.util.plot.KeyTracker; - -import java.awt.Color; -import javax.swing.JFrame; - -/** - * This class opens a window to accept keyboard input that acts as a gamepad. It is meant to be used - * with simulation code, in which the code is running on a computer. It will not work if the robot - * code is being run on the robot (e.g. RoboRIO) - * - * @author Myles Pasetsky (selym3) - */ -public class SimKeyGamepad extends KeyGamepad { - - /** Default size of an input area */ - private static final int DEFAULT_WIDTH = 300, DEFAULT_HEIGHT = 300; - - /** Opens up a screen in which keyboard input is accepted. */ - private JFrame inputArea; - - /** This keytracker is added to the input area to allow us to read key inputs */ - private KeyTracker keyboard; - - /** Creates a sim gamepad and opens an input area with the default width and height */ - public SimKeyGamepad() { - this(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - /** - * Creates a sim gamepad and opens an input area with the given width and height - * - * @param width width of input area - * @param height height of input area - */ - public SimKeyGamepad(int width, int height) { - inputArea = new JFrame("Simulation Gamepad"); - inputArea.setSize(width, height); - inputArea.setResizable(false); - inputArea.setDefaultCloseOperation( - // JFrame.DISPOSE_ON_CLOSE - JFrame.EXIT_ON_CLOSE); - - keyboard = new KeyTracker(); - inputArea.addKeyListener(keyboard); - - inputArea.setLocationRelativeTo(null); - inputArea.setVisible(true); - } - - /** - * Gets if a key is being held - * - * @return whether or not the key is being pressed - */ - @Override - protected boolean getKey(String name) { - return keyboard.hasKey(name); - } - - /** - * Sets the color of the input area based on rumble - * - * @param intensity the magnitude of rumble for the controller - */ - public void setRumble(double intensity) { - Color color = Color.getHSBColor(0.0f, (float) intensity, 1.0f); - inputArea.getContentPane().setBackground(color); - } -} diff --git a/src/com/stuypulse/stuylib/input/keyboard/NetKeyboard.java b/src/com/stuypulse/stuylib/input/keyboard/NetKeyboard.java deleted file mode 100644 index 96980395..00000000 --- a/src/com/stuypulse/stuylib/input/keyboard/NetKeyboard.java +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.keyboard; - -import com.stuypulse.stuylib.network.SLNetworkTable; - -import java.util.Set; - -/** - * This class lets you send and receive keyboard information over network tables - * - *

Every other class will interact with the network keyboards through this class - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class NetKeyboard { - - private interface Constants { - - /** - * Gets name of network table for Network Keyboard and its virtual port number - * - * @param port virtual port number - * @return network table name - */ - public static String getTableName(int port) { - return ("NetworkKeyboard/port/" + Integer.toString(Math.abs(port))); - } - - /** - * Sanitize key names to prevent caps issues - * - * @param key key name - * @return sanitized key name - */ - public static String sanitize(String key) { - return key.toUpperCase().trim(); - } - } - - /** Table where key information is stored */ - private SLNetworkTable mKeyboardTable; - - /** - * Creates NetworkKeyboard on robot - * - * @param port virtual port number (unsure, use 0) - */ - public NetKeyboard(int port) { - mKeyboardTable = SLNetworkTable.open(Constants.getTableName(port)); - } - - /** - * Creates NetworkKeyboard that is connected to the robot from elsewhere - * - * @param team robot team number - * @param port virtual port number (unsure, use 0) - */ - public NetKeyboard(int team, int port) { - mKeyboardTable = SLNetworkTable.open(team, Constants.getTableName(port)); - } - - /** - * Checks if network table is connected - * - * @return if network table is connected - */ - public boolean isConnected() { - return mKeyboardTable.isConnected(); - } - - /** - * Set key value - * - * @param key name of key - * @param val new value for key - */ - public void setKey(String key, boolean val) { - mKeyboardTable.setBoolean(Constants.sanitize(key), val); - } - - /** - * Gets if key is pressed - * - * @param key name of key - * @return if key is pressed - */ - public boolean getKey(String key) { - return mKeyboardTable.getBoolean(Constants.sanitize(key)); - } - - /** - * Returns Set of Strings with the names of every key that is pressed - * - * @return set of strings - */ - public Set getKeysPressed() { - Set keysPressed = mKeyboardTable.getKeys(); - for (String s : keysPressed) { - if (!mKeyboardTable.getBoolean(s)) { - keysPressed.remove(s); - } - } - return keysPressed; - } -} diff --git a/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyListener.java b/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyListener.java deleted file mode 100644 index 72de9748..00000000 --- a/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.keyboard.computer; - -import com.stuypulse.stuylib.input.keyboard.NetKeyboard; - -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; - -/** - * A KeyListener that uploads all of the key strokes to a network table where they can then be - * received and put into the robot - * - *

This would not be used on the robot, but should be used on the users computer - * - *

Make an AWT window to use this listener - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class NetKeyListener extends KeyAdapter { - - /** Network Table for which key presses go */ - private NetKeyboard mNetKeyboard; - - /** - * Initialize Network Keyboard Listener - * - * @param team team number of robot - * @param port virtual keyboard port - */ - public NetKeyListener(int team, int port) { - mNetKeyboard = new NetKeyboard(team, port); - } - - /** - * Returns underlying NetKeyboard class - * - * @return underlying NetKeyboard class - */ - public NetKeyboard getNetKeyboard() { - return mNetKeyboard; - } - - /** - * Checks if network table is connected - * - * @return if network table is connected - */ - public boolean isConnected() { - return mNetKeyboard.isConnected(); - } - - /** - * Adds Key from Key Event to State - * - * @param e Key Event - */ - public void keyPressed(KeyEvent e) { - mNetKeyboard.setKey(KeyEvent.getKeyText(e.getKeyCode()), true); - } - - /** - * Removes Key from Key Event to State - * - * @param e Key Event - */ - public void keyReleased(KeyEvent e) { - mNetKeyboard.setKey(KeyEvent.getKeyText(e.getKeyCode()), false); - } -} diff --git a/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyWindow.java b/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyWindow.java deleted file mode 100644 index 5fcb2a42..00000000 --- a/src/com/stuypulse/stuylib/input/keyboard/computer/NetKeyWindow.java +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.input.keyboard.computer; - -import java.awt.Color; -import java.awt.GridBagLayout; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.border.LineBorder; - -/** - * This is a simple class that opens a Java AWT window, which has a KeyListener that uploads - * keyboard information to a network table - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class NetKeyWindow extends JFrame { - - private static final long serialVersionUID = 1L; - - /** NetKeyListener for window */ - private NetKeyListener mListener; - - /** Opens Network Keyboard Input Window */ - public NetKeyWindow() { - // Set Title and Open Network Table - super("Network Keyboard Input"); - - // Get team number from user - int team; - do { - try { - String teamNum = JOptionPane.showInputDialog("Enter Team Number:"); - team = Integer.parseInt(teamNum); - } catch (Exception e) { - team = -1; - } - } while (team < 0); - - // Get keyboard port from user - int port = 0; - try { - String keyboardPort = - JOptionPane.showInputDialog("Enter Virtual Keyboard Port (Default=0):"); - port = Integer.parseInt(keyboardPort); - } catch (Exception e) { - port = 0; - } - - // Connect NetKeyListener - mListener = new NetKeyListener(team, port); - addKeyListener(mListener); - - // Set Title - setTitle("Network Keyboard Input [Team: " + team + ", Port: " + port + "]"); - - // Message - JLabel message = - new JLabel("Sending Keyboard Input to [Team: " + team + ", Port: " + port + "]"); - message.setBorder(new LineBorder(Color.BLACK, 4)); - - // Message Panel - final JPanel messagePanel = new JPanel(new GridBagLayout()); - messagePanel.add(message); - getContentPane().add(messagePanel); - - // Pack and Set Size - pack(); - - // Set Visible - setVisible(true); - } -} diff --git a/src/com/stuypulse/stuylib/input/keyboard/readme.md b/src/com/stuypulse/stuylib/input/keyboard/readme.md deleted file mode 100644 index 73d6c9b9..00000000 --- a/src/com/stuypulse/stuylib/input/keyboard/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# StuyLib Network Keyboard - -WIP... \ No newline at end of file diff --git a/src/com/stuypulse/stuylib/math/Angle.java b/src/com/stuypulse/stuylib/math/Angle.java index 5d05c9a6..a451c3be 100644 --- a/src/com/stuypulse/stuylib/math/Angle.java +++ b/src/com/stuypulse/stuylib/math/Angle.java @@ -15,10 +15,6 @@ */ public final class Angle { - // Configuration for toString() function - private static final boolean STRING_RADIANS = false; - private static final int STRING_SIGFIGS = 5; - /******************************************************/ /*** CONSTANT ANGLE VALUES, SET AT BENCHMARK VALUES ***/ /******************************************************/ @@ -494,19 +490,4 @@ public boolean equals(Object other) { public int hashCode() { return Double.hashCode(this.toRadians()); } - - /** @return the string representation of the angle */ - @Override - public String toString() { - StringBuilder out = new StringBuilder(); - out.append("Angle("); - - if (STRING_RADIANS) { - out.append(SLMath.round(this.toRadians(), STRING_SIGFIGS)).append("pi, "); - } - - out.append(SLMath.round(this.toDegrees(), STRING_SIGFIGS)).append("deg)"); - - return out.toString(); - } } diff --git a/src/com/stuypulse/stuylib/math/Polar2D.java b/src/com/stuypulse/stuylib/math/Polar2D.java deleted file mode 100644 index 68fd4c3a..00000000 --- a/src/com/stuypulse/stuylib/math/Polar2D.java +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math; - -import com.stuypulse.stuylib.util.HashBuilder; - -/** - * A class that is used to store polar coordinates. It's heavily dependant on the vector and angle - * class. - * - * @author Sam Belliveau (sam.belliveau@gmail.com) - */ -public class Polar2D { - - // Configuration for toString() function - private static final int STRING_SIGFIGS = 5; - - // Internal Variables - public final double magnitude; - public final Angle angle; - - /** - * Create a Polar2D with a magnitude and an angle - * - * @param mag magnitude - * @param ang angle - */ - public Polar2D(double mag, Angle ang) { - // Make sure the magnitude is always positive - if (mag >= 0) { - magnitude = mag; - angle = ang; - } else { - magnitude = -mag; - angle = ang.opposite(); - } - } - - /** - * Convert a Vector2D into Polar Coordinates - * - * @param vec Vector2D to turn into polar coordinates - */ - public Polar2D(Vector2D vec) { - this(vec.magnitude(), vec.getAngle()); - } - - /** - * Get the distance between two Polar2Ds - * - * @param other other Polar2D - * @return the distance between the two Polar2Ds - */ - public double distance(Polar2D other) { - final double a = this.magnitude; - final double b = other.magnitude; - final Angle t = this.angle.sub(other.angle); - return Math.sqrt(a * a + b * b - 2.0 * a * b * t.cos()); - } - - /** @return distance from 0, 0 */ - public double distance() { - return this.magnitude; - } - - /** @return magnitude */ - public double magnitude() { - return magnitude; - } - - /** @return angle */ - public Angle getAngle() { - return angle; - } - - /** @return Polar Coordinates as a Vector2D */ - public Vector2D getVector() { - return new Vector2D(angle.cos() * magnitude, angle.sin() * magnitude); - } - - /** - * @param m scalar to multiply by - * @return result of multiplication - */ - public Polar2D mul(double m) { - return new Polar2D(magnitude * m, angle); - } - - /** - * @param d scalar to divide by - * @return result of division - */ - public Polar2D div(double d) { - return new Polar2D(magnitude / d, angle); - } - - /** - * @param a angle to rotate by - * @return result of rotation - */ - public Polar2D rotate(Angle a) { - return new Polar2D(magnitude, angle.add(a)); - } - - /** @return Polar2D object with a negated magnitude */ - public Polar2D negative() { - return new Polar2D(-magnitude, angle); - } - - /** @return normalized polar coordinates */ - public Polar2D normalize() { - return new Polar2D(1, angle); - } - - /** - * @param other object to compare to - * @return both objects are Polar2Ds and they equal eachother - */ - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other instanceof Polar2D) { - Polar2D o = (Polar2D) other; - return this.magnitude == o.magnitude && this.angle.equals(o.angle); - } - - return false; - } - - /** - * @see com.stuypulse.stuylib.util.HashBuilder#combineHash(int, int) - * @return hashCode generated by combining the hashes of the magnitude and the angle - */ - @Override - public int hashCode() { - return HashBuilder.combineHash(Double.hashCode(magnitude), angle); - } - - /** @return String representation of the Polar2D class */ - @Override - public String toString() { - StringBuilder out = new StringBuilder(); - out.append("Polar2D("); - out.append(SLMath.round(magnitude, STRING_SIGFIGS)); - out.append(", "); - out.append(angle); - out.append(")"); - return out.toString(); - } -} diff --git a/src/com/stuypulse/stuylib/math/SLMath.java b/src/com/stuypulse/stuylib/math/SLMath.java index 2ec69453..19dbe340 100644 --- a/src/com/stuypulse/stuylib/math/SLMath.java +++ b/src/com/stuypulse/stuylib/math/SLMath.java @@ -16,37 +16,6 @@ public final class SLMath { // Prevent the class from being extended at all private SLMath() {} - /*********************/ - /*** INTERPOLATION ***/ - /*********************/ - - /** - * Linear Interpolation from start to end using value t [0...1] - * - * @param start value of linear interpolation when t = 0 - * @param end value of linear interpolation when t = 1 - * @param t time value for linear interpolation [0...1] - * @return interpolated value - */ - public static double lerp(double start, double end, double t) { - return start + (end - start) * clamp(t, 0.0, 1.0); - } - - /** - * Maps an input in one range to an output in another range - * - * @param input value to map - * @param minInput minimum value of input - * @param maxInput maximum value of input - * @param minOutput minimum value of output - * @param maxOutput maximum value of output - * @return the mapped value - */ - public static double map( - double input, double minInput, double maxInput, double minOutput, double maxOutput) { - return lerp(minOutput, maxOutput, (input - minInput) / (maxInput - minInput)); - } - /**************/ /*** LIMITS ***/ /**************/ @@ -116,26 +85,6 @@ public static double deadband(double x, double window) { /*** RAISE TO POWER WHILE KEEPING SIGN ***/ /*****************************************/ - /** - * [WARNING! THIS WILL KEEP THE SIGN OF THE INPUT NUMBER] Square number and keep sign - * - * @param x input - * @return squared input with the same sign - */ - public static double square(double x) { - return clamp(x * x * Math.signum(x)); - } - - /** - * Cube a number - * - * @param x input - * @return cubed input that - */ - public static double cube(double x) { - return x * x * x; - } - /** * spow (signless pow), raises a number to a power without affecting the sign of the number * @@ -146,85 +95,4 @@ public static double cube(double x) { public static double spow(double x, double power) { return Math.pow(Math.abs(x), power) * Math.signum(x); } - - /*****************/ - /*** MISC MATH ***/ - /*****************/ - - /** - * fpow (fast pow), is a pow function that takes in an integer for the exponent. This allows it - * to be much faster on repeated calls due to the fact that it does not need to deal with - * fractional exponents. - * - * @param base base of the power - * @param exp integer exponent of power - * @return result of calculation - */ - public static double fpow(double base, int exp) { - // Output of the fpow function - double out = 1.0; - - // If the exponent is negative, divide instead of multiply - if (exp < 0) { - // Flip exponent to make calculations easier - exp = -exp; - - // Fast integer power algorithm - while (exp > 0) { - if ((exp & 1) == 1) { - out /= base; - } - base *= base; - exp >>= 1; - } - } else { - // Fast integer power algorithm - while (exp > 0) { - if ((exp & 1) == 1) { - out *= base; - } - base *= base; - exp >>= 1; - } - } - - // Return - return out; - } - - /** - * Round a double by a certain amount of sigfigs in base 10 - * - * @param n number to round - * @param sigfigs amount of sigfigs to round it to - * @return rounded number - */ - public static double round(double n, int sigfigs) { - // The value 0 returns nan if not accounted for - if (n == 0.0) { - return 0.0; - } - - // Digit place that number starts at - int digits = (int) Math.floor(Math.log10(Math.abs(n))); - - // Amount to multiply before multiplying based on - // the sigfigs and digits in the number - double mul = fpow(10.0, sigfigs - digits); - - // Round number by the multiplier calculated - return Math.round(n * mul) / mul; - } - - private static final double FLT_ELIPSON = fpow(0.5, 32); - - /** - * Compare a double to zero using a Elipson - * - * @param num number to compare to zero - * @return if the number equals a number close to zero - */ - public static boolean isZero(double num) { - return Math.abs(num) < FLT_ELIPSON; - } } diff --git a/src/com/stuypulse/stuylib/math/Swizzler.java b/src/com/stuypulse/stuylib/math/Swizzler.java deleted file mode 100644 index bd69372e..00000000 --- a/src/com/stuypulse/stuylib/math/Swizzler.java +++ /dev/null @@ -1,1102 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math; - -/** - * A utility class that allows you to "Swizzle" vectors / scalars using standard notation commonly - * found in graphics programming languages. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public final class Swizzler { - - private Swizzler() { - /** This is a utility class */ - } - - /************************/ - /*** Swizzled doubles ***/ - /************************/ - - /** - * @param v double to swizzle with - * @return swizzled double with component v - */ - public static double x(double v) { - return v; - } - - /** - * @param v double to swizzle with - * @return swizzled Vector2D with components v, v - */ - public static Vector2D xx(double v) { - return new Vector2D(v, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components v, v, v - */ - public static Vector3D xxx(double v) { - return new Vector3D(v, v, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components v, v, 0 - */ - public static Vector3D xx_(double v) { - return new Vector3D(v, v, 0.0); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector2D with components v, 0 - */ - public static Vector2D x_(double v) { - return new Vector2D(v, 0.0); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components v, 0, v - */ - public static Vector3D x_x(double v) { - return new Vector3D(v, 0.0, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components v, 0, 0 - */ - public static Vector3D x__(double v) { - return new Vector3D(v, 0.0, 0.0); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector2D with components 0, v - */ - public static Vector2D _x(double v) { - return new Vector2D(0.0, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components 0, v, v - */ - public static Vector3D _xx(double v) { - return new Vector3D(0.0, v, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components 0, v, 0 - */ - public static Vector3D _x_(double v) { - return new Vector3D(0.0, v, 0.0); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector2D with components 0, 0 - */ - public static Vector2D __(double v) { - return new Vector2D(0.0, 0.0); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components 0, 0, v - */ - public static Vector3D __x(double v) { - return new Vector3D(0.0, 0.0, v); - } - - /** - * @param v double to swizzle with - * @return swizzled Vector3D with components 0, 0, 0 - */ - public static Vector3D ___(double v) { - return new Vector3D(0.0, 0.0, 0.0); - } - - /**************************/ - /*** Swizzled Vector2Ds ***/ - /**************************/ - - /** - * @param v vector to swizzle with - * @return swizzled double with component x - */ - public static double x(Vector2D v) { - return v.x; - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, x - */ - public static Vector2D xx(Vector2D v) { - return new Vector2D(v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, x - */ - public static Vector3D xxx(Vector2D v) { - return new Vector3D(v.x, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, y - */ - public static Vector3D xxy(Vector2D v) { - return new Vector3D(v.x, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, 0 - */ - public static Vector3D xx_(Vector2D v) { - return new Vector3D(v.x, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, y - */ - public static Vector2D xy(Vector2D v) { - return new Vector2D(v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, x - */ - public static Vector3D xyx(Vector2D v) { - return new Vector3D(v.x, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, y - */ - public static Vector3D xyy(Vector2D v) { - return new Vector3D(v.x, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, 0 - */ - public static Vector3D xy_(Vector2D v) { - return new Vector3D(v.x, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, 0 - */ - public static Vector2D x_(Vector2D v) { - return new Vector2D(v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, x - */ - public static Vector3D x_x(Vector2D v) { - return new Vector3D(v.x, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, y - */ - public static Vector3D x_y(Vector2D v) { - return new Vector3D(v.x, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, 0 - */ - public static Vector3D x__(Vector2D v) { - return new Vector3D(v.x, 0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled double with component y - */ - public static double y(Vector2D v) { - return v.y; - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, x - */ - public static Vector2D yx(Vector2D v) { - return new Vector2D(v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, x - */ - public static Vector3D yxx(Vector2D v) { - return new Vector3D(v.y, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, y - */ - public static Vector3D yxy(Vector2D v) { - return new Vector3D(v.y, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, 0 - */ - public static Vector3D yx_(Vector2D v) { - return new Vector3D(v.y, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, y - */ - public static Vector2D yy(Vector2D v) { - return new Vector2D(v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, x - */ - public static Vector3D yyx(Vector2D v) { - return new Vector3D(v.y, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, y - */ - public static Vector3D yyy(Vector2D v) { - return new Vector3D(v.y, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, 0 - */ - public static Vector3D yy_(Vector2D v) { - return new Vector3D(v.y, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, 0 - */ - public static Vector2D y_(Vector2D v) { - return new Vector2D(v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, x - */ - public static Vector3D y_x(Vector2D v) { - return new Vector3D(v.y, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, y - */ - public static Vector3D y_y(Vector2D v) { - return new Vector3D(v.y, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, 0 - */ - public static Vector3D y__(Vector2D v) { - return new Vector3D(v.y, 0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, x - */ - public static Vector2D _x(Vector2D v) { - return new Vector2D(0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, x - */ - public static Vector3D _xx(Vector2D v) { - return new Vector3D(0.0, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, y - */ - public static Vector3D _xy(Vector2D v) { - return new Vector3D(0.0, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, 0 - */ - public static Vector3D _x_(Vector2D v) { - return new Vector3D(0.0, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, y - */ - public static Vector2D _y(Vector2D v) { - return new Vector2D(0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, x - */ - public static Vector3D _yx(Vector2D v) { - return new Vector3D(0.0, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, y - */ - public static Vector3D _yy(Vector2D v) { - return new Vector3D(0.0, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, 0 - */ - public static Vector3D _y_(Vector2D v) { - return new Vector3D(0.0, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, 0 - */ - public static Vector2D __(Vector2D v) { - return new Vector2D(0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, x - */ - public static Vector3D __x(Vector2D v) { - return new Vector3D(0.0, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, y - */ - public static Vector3D __y(Vector2D v) { - return new Vector3D(0.0, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, 0 - */ - public static Vector3D ___(Vector2D v) { - return new Vector3D(0.0, 0.0, 0.0); - } - - /**************************/ - /*** Swizzled Vector3Ds ***/ - /**************************/ - - /** - * @param v vector to swizzle with - * @return swizzled double with component x - */ - public static double x(Vector3D v) { - return v.x; - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, x - */ - public static Vector2D xx(Vector3D v) { - return new Vector2D(v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, x - */ - public static Vector3D xxx(Vector3D v) { - return new Vector3D(v.x, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, y - */ - public static Vector3D xxy(Vector3D v) { - return new Vector3D(v.x, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, z - */ - public static Vector3D xxz(Vector3D v) { - return new Vector3D(v.x, v.x, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, x, 0 - */ - public static Vector3D xx_(Vector3D v) { - return new Vector3D(v.x, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, y - */ - public static Vector2D xy(Vector3D v) { - return new Vector2D(v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, x - */ - public static Vector3D xyx(Vector3D v) { - return new Vector3D(v.x, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, y - */ - public static Vector3D xyy(Vector3D v) { - return new Vector3D(v.x, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, z - */ - public static Vector3D xyz(Vector3D v) { - return new Vector3D(v.x, v.y, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, y, 0 - */ - public static Vector3D xy_(Vector3D v) { - return new Vector3D(v.x, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, z - */ - public static Vector2D xz(Vector3D v) { - return new Vector2D(v.x, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, z, x - */ - public static Vector3D xzx(Vector3D v) { - return new Vector3D(v.x, v.z, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, z, y - */ - public static Vector3D xzy(Vector3D v) { - return new Vector3D(v.x, v.z, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, z, z - */ - public static Vector3D xzz(Vector3D v) { - return new Vector3D(v.x, v.z, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, z, 0 - */ - public static Vector3D xz_(Vector3D v) { - return new Vector3D(v.x, v.z, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components x, 0 - */ - public static Vector2D x_(Vector3D v) { - return new Vector2D(v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, x - */ - public static Vector3D x_x(Vector3D v) { - return new Vector3D(v.x, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, y - */ - public static Vector3D x_y(Vector3D v) { - return new Vector3D(v.x, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, z - */ - public static Vector3D x_z(Vector3D v) { - return new Vector3D(v.x, 0.0, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components x, 0, 0 - */ - public static Vector3D x__(Vector3D v) { - return new Vector3D(v.x, 0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled double with component y - */ - public static double y(Vector3D v) { - return v.y; - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, x - */ - public static Vector2D yx(Vector3D v) { - return new Vector2D(v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, x - */ - public static Vector3D yxx(Vector3D v) { - return new Vector3D(v.y, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, y - */ - public static Vector3D yxy(Vector3D v) { - return new Vector3D(v.y, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, z - */ - public static Vector3D yxz(Vector3D v) { - return new Vector3D(v.y, v.x, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, x, 0 - */ - public static Vector3D yx_(Vector3D v) { - return new Vector3D(v.y, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, y - */ - public static Vector2D yy(Vector3D v) { - return new Vector2D(v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, x - */ - public static Vector3D yyx(Vector3D v) { - return new Vector3D(v.y, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, y - */ - public static Vector3D yyy(Vector3D v) { - return new Vector3D(v.y, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, z - */ - public static Vector3D yyz(Vector3D v) { - return new Vector3D(v.y, v.y, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, y, 0 - */ - public static Vector3D yy_(Vector3D v) { - return new Vector3D(v.y, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, z - */ - public static Vector2D yz(Vector3D v) { - return new Vector2D(v.y, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, z, x - */ - public static Vector3D yzx(Vector3D v) { - return new Vector3D(v.y, v.z, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, z, y - */ - public static Vector3D yzy(Vector3D v) { - return new Vector3D(v.y, v.z, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, z, z - */ - public static Vector3D yzz(Vector3D v) { - return new Vector3D(v.y, v.z, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, z, 0 - */ - public static Vector3D yz_(Vector3D v) { - return new Vector3D(v.y, v.z, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components y, 0 - */ - public static Vector2D y_(Vector3D v) { - return new Vector2D(v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, x - */ - public static Vector3D y_x(Vector3D v) { - return new Vector3D(v.y, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, y - */ - public static Vector3D y_y(Vector3D v) { - return new Vector3D(v.y, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, z - */ - public static Vector3D y_z(Vector3D v) { - return new Vector3D(v.y, 0.0, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components y, 0, 0 - */ - public static Vector3D y__(Vector3D v) { - return new Vector3D(v.y, 0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled double with component z - */ - public static double z(Vector3D v) { - return v.z; - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components z, x - */ - public static Vector2D zx(Vector3D v) { - return new Vector2D(v.z, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, x, x - */ - public static Vector3D zxx(Vector3D v) { - return new Vector3D(v.z, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, x, y - */ - public static Vector3D zxy(Vector3D v) { - return new Vector3D(v.z, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, x, z - */ - public static Vector3D zxz(Vector3D v) { - return new Vector3D(v.z, v.x, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, x, 0 - */ - public static Vector3D zx_(Vector3D v) { - return new Vector3D(v.z, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components z, y - */ - public static Vector2D zy(Vector3D v) { - return new Vector2D(v.z, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, y, x - */ - public static Vector3D zyx(Vector3D v) { - return new Vector3D(v.z, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, y, y - */ - public static Vector3D zyy(Vector3D v) { - return new Vector3D(v.z, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, y, z - */ - public static Vector3D zyz(Vector3D v) { - return new Vector3D(v.z, v.y, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, y, 0 - */ - public static Vector3D zy_(Vector3D v) { - return new Vector3D(v.z, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components z, z - */ - public static Vector2D zz(Vector3D v) { - return new Vector2D(v.z, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, z, x - */ - public static Vector3D zzx(Vector3D v) { - return new Vector3D(v.z, v.z, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, z, y - */ - public static Vector3D zzy(Vector3D v) { - return new Vector3D(v.z, v.z, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, z, z - */ - public static Vector3D zzz(Vector3D v) { - return new Vector3D(v.z, v.z, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, z, 0 - */ - public static Vector3D zz_(Vector3D v) { - return new Vector3D(v.z, v.z, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components z, 0 - */ - public static Vector2D z_(Vector3D v) { - return new Vector2D(v.z, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, 0, x - */ - public static Vector3D z_x(Vector3D v) { - return new Vector3D(v.z, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, 0, y - */ - public static Vector3D z_y(Vector3D v) { - return new Vector3D(v.z, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, 0, z - */ - public static Vector3D z_z(Vector3D v) { - return new Vector3D(v.z, 0.0, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components z, 0, 0 - */ - public static Vector3D z__(Vector3D v) { - return new Vector3D(v.z, 0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, x - */ - public static Vector2D _x(Vector3D v) { - return new Vector2D(0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, x - */ - public static Vector3D _xx(Vector3D v) { - return new Vector3D(0.0, v.x, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, y - */ - public static Vector3D _xy(Vector3D v) { - return new Vector3D(0.0, v.x, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, z - */ - public static Vector3D _xz(Vector3D v) { - return new Vector3D(0.0, v.x, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, x, 0 - */ - public static Vector3D _x_(Vector3D v) { - return new Vector3D(0.0, v.x, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, y - */ - public static Vector2D _y(Vector3D v) { - return new Vector2D(0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, x - */ - public static Vector3D _yx(Vector3D v) { - return new Vector3D(0.0, v.y, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, y - */ - public static Vector3D _yy(Vector3D v) { - return new Vector3D(0.0, v.y, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, z - */ - public static Vector3D _yz(Vector3D v) { - return new Vector3D(0.0, v.y, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, y, 0 - */ - public static Vector3D _y_(Vector3D v) { - return new Vector3D(0.0, v.y, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, z - */ - public static Vector2D _z(Vector3D v) { - return new Vector2D(0.0, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, z, x - */ - public static Vector3D _zx(Vector3D v) { - return new Vector3D(0.0, v.z, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, z, y - */ - public static Vector3D _zy(Vector3D v) { - return new Vector3D(0.0, v.z, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, z, z - */ - public static Vector3D _zz(Vector3D v) { - return new Vector3D(0.0, v.z, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, z, 0 - */ - public static Vector3D _z_(Vector3D v) { - return new Vector3D(0.0, v.z, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector2D with components 0, 0 - */ - public static Vector2D __(Vector3D v) { - return new Vector2D(0.0, 0.0); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, x - */ - public static Vector3D __x(Vector3D v) { - return new Vector3D(0.0, 0.0, v.x); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, y - */ - public static Vector3D __y(Vector3D v) { - return new Vector3D(0.0, 0.0, v.y); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, z - */ - public static Vector3D __z(Vector3D v) { - return new Vector3D(0.0, 0.0, v.z); - } - - /** - * @param v vector to swizzle with - * @return swizzled Vector3D with components 0, 0, 0 - */ - public static Vector3D ___(Vector3D v) { - return new Vector3D(0.0, 0.0, 0.0); - } -} diff --git a/src/com/stuypulse/stuylib/math/Vector2D.java b/src/com/stuypulse/stuylib/math/Vector2D.java index c3450c04..38a7256d 100644 --- a/src/com/stuypulse/stuylib/math/Vector2D.java +++ b/src/com/stuypulse/stuylib/math/Vector2D.java @@ -4,8 +4,6 @@ package com.stuypulse.stuylib.math; -import com.stuypulse.stuylib.util.HashBuilder; - import edu.wpi.first.math.geometry.Translation2d; /** @@ -17,9 +15,6 @@ */ public final class Vector2D { - // Configuration for toString() function - private static final int STRING_SIGFIGS = 5; - // Vector Constnants public static final Vector2D kOrigin = new Vector2D(0, 0); public static final Vector2D kI = new Vector2D(1, 0); @@ -103,11 +98,6 @@ public Angle getAngle() { return Angle.fromVector(this); } - /** @return polar coordinates created from this vector */ - public Polar2D getPolar() { - return new Polar2D(this); - } - /** * @param angle angle to rotate by * @param origin point to rotate around @@ -196,7 +186,7 @@ public double cross(Vector2D other) { /** @return result of normalizing the Vector2D so that the magnitude is 1.0 */ public Vector2D normalize() { final double magnitude = this.distance(); - if (SLMath.isZero(magnitude)) { + if (magnitude <= 1e-9) { return Vector2D.kI; } else { return this.div(magnitude); @@ -243,25 +233,4 @@ public boolean equals(Object other) { return false; } - - /** - * @see com.stuypulse.stuylib.util.HashBuilder#combineHash(int, int) - * @return hashCode generated by combining the hashes of the x and y components - */ - @Override - public int hashCode() { - return HashBuilder.combineHash(Double.hashCode(x), Double.hashCode(y)); - } - - /** @return string representation of Vector2D */ - @Override - public String toString() { - StringBuilder out = new StringBuilder(); - out.append("Vector2D("); - out.append(SLMath.round(x, STRING_SIGFIGS)); - out.append(", "); - out.append(SLMath.round(y, STRING_SIGFIGS)); - out.append(")"); - return out.toString(); - } } diff --git a/src/com/stuypulse/stuylib/math/Vector3D.java b/src/com/stuypulse/stuylib/math/Vector3D.java deleted file mode 100644 index 8fb2d42a..00000000 --- a/src/com/stuypulse/stuylib/math/Vector3D.java +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math; - -import com.stuypulse.stuylib.util.HashBuilder; - -/** - * A Vector3D class that stores x, y, and z position data. It is made to work with the StuyLib Angle - * class and be easy to use. It is a standard Vector3D class with all of the functions that you - * would expect. - * - * @author Vincent (vinowang921@gmail.com) - */ -public final class Vector3D { - - // Configuration for toString() function - private static final int STRING_SIGFIGS = 5; - - // Vector Constnants - public static final Vector3D kOrigin = new Vector3D(0, 0, 0); - public static final Vector3D kI = new Vector3D(1, 0, 0); - public static final Vector3D kJ = new Vector3D(0, 1, 0); - public static final Vector3D kK = new Vector3D(0, 0, 1); - - /****************************/ - /*** Class Implementation ***/ - /****************************/ - - /** The x position of the Vector3D */ - public final double x; - - /** The y position of the Vector3D */ - public final double y; - - /** The z position of the Vector3D */ - public final double z; - - /** - * @param x the x axis of the vector - * @param y the y axis of the vector - * @param z the z axis of the vector - */ - public Vector3D(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * @param axis Array of size 3 where the first element will be defined as x, the second will be - * defined as y, and the third will be defined as z. - */ - public Vector3D(double[] axis) { - if (axis.length != 3) { - throw new IllegalArgumentException("axis must be of size 3"); - } - - this.x = axis[0]; - this.y = axis[1]; - this.z = axis[2]; - } - - /** @return double array of size 3 defined as {x, y, z} */ - public double[] getArray() { - return new double[] {x, y, z}; - } - - /** - * @param other other Vector3D - * @return the distance between the two Vector3Ds - */ - public double distance(Vector3D other) { - double dx = this.x - other.x; - double dy = this.y - other.y; - double dz = this.z - other.z; - - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - /** @return distance from 0, 0, 0 */ - public double distance() { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - } - - /** @return magnitude of the vector (same as distance from 0, 0, 0) */ - public double magnitude() { - return this.distance(); - } - - /** - * @param angle angle to rotate by - * @return result of rotation - */ - public Vector3D rotateX(Angle angle) { - return new Vector3D( - +this.x, - +this.y * angle.cos() + +this.x * angle.sin(), - -this.x * angle.sin() + +this.z * angle.cos()); - } - - /** - * @param angle angle to rotate by - * @return result of rotation - */ - public Vector3D rotateY(Angle angle) { - return new Vector3D( - +this.x * angle.cos() + +this.z * angle.sin(), - +this.y, - -this.x * angle.sin() + +this.z * angle.cos()); - } - - /** - * @param angle angle to rotate by - * @return result of rotation - */ - public Vector3D rotateZ(Angle angle) { - return new Vector3D( - +this.x * angle.cos() + -this.y * angle.sin(), - +this.x * angle.sin() + +this.y * angle.cos(), - +this.z); - } - - /** - * @param other Vector3D to be added by - * @return sum of the two Vector3Ds - */ - public Vector3D add(Vector3D other) { - return new Vector3D(this.x + other.x, this.y + other.y, this.z + other.z); - } - - /** - * @param other Vector3D to be subtracted from - * @return difference between the two Vector3Ds - */ - public Vector3D sub(Vector3D other) { - return new Vector3D(this.x - other.x, this.y - other.y, this.z - other.z); - } - - /** - * @param other Vector3D to be multiplied by - * @return product of the two Vector3Ds - */ - public Vector3D mul(Vector3D other) { - return new Vector3D(this.x * other.x, this.y * other.y, this.z * other.z); - } - - /** - * @param other Vector3D to be divided by - * @return division of the two Vector3Ds - */ - public Vector3D div(Vector3D other) { - return new Vector3D(this.x / other.x, this.y / other.y, this.z / other.z); - } - - /** - * @param multiplier amount to multiply the x and y components by - * @return result of multiplying the x and y components by the multiplier - */ - public Vector3D mul(double multiplier) { - return new Vector3D(this.x * multiplier, this.y * multiplier, this.z * multiplier); - } - - /** - * @param divisor amount to divide the x and y components by - * @return result of dividing the x and y components by the divisor - */ - public Vector3D div(double divisor) { - return new Vector3D(this.x / divisor, this.y / divisor, this.z / divisor); - } - - /** - * @param other Vector3D to perform dot product with - * @return result of performing the dot product with the other Vector3D - */ - public double dot(Vector3D other) { - return this.x * other.x + this.y * other.y + this.z * other.z; - } - - /** - * @param other Vector3D to perform cross product with - * @return result of performing the cross product with the other Vector3D - */ - public Vector3D cross(Vector3D other) { - return new Vector3D( - this.y * other.z - this.z * other.y, - this.z * other.x - this.x * other.z, - this.x * other.y - this.y * other.x); - } - - /** @return result of normalizing the Vector3D so that the magnitude is 1.0 */ - public Vector3D normalize() { - double magnitude = this.distance(); - if (SLMath.isZero(magnitude)) { - return Vector3D.kI; - } else { - return this.div(magnitude); - } - } - - /** @return result of negating the x, y, and z components */ - public Vector3D negative() { - return new Vector3D(-this.x, -this.y, -this.z); - } - - /** - * @param other object to compare to - * @return both objects are Vector3Ds and they equal eachother - */ - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other instanceof Vector3D) { - Vector3D o = (Vector3D) other; - return this.x == o.x && this.y == o.y && this.z == o.z; - } - - return false; - } - - /** - * @see com.stuypulse.stuylib.util.HashBuilder#combineHash(int, int) - * @return hashCode generated by combining the hashes of the x, y, and z components - */ - @Override - public int hashCode() { - return new HashBuilder().append(this.x).append(this.y).append(this.z).toHashCode(); - } - - /** @return string representation of Vector3D */ - @Override - public String toString() { - StringBuilder out = new StringBuilder(); - out.append("Vector3D("); - out.append(SLMath.round(x, STRING_SIGFIGS)); - out.append(", "); - out.append(SLMath.round(y, STRING_SIGFIGS)); - out.append(", "); - out.append(SLMath.round(z, STRING_SIGFIGS)); - out.append(")"); - return out.toString(); - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/CubicInterpolator.java b/src/com/stuypulse/stuylib/math/interpolation/CubicInterpolator.java deleted file mode 100644 index c1030ff1..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/CubicInterpolator.java +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.Vector2D; - -/** - * This class uses Cubic Hermite interpolation (to find the RPM of the shooter). This class gets a - * polynomial that represents the model. We then use the polynomial to interpolate. - * - *

The polynomial can be written as P(t) = h00(t)p0 + h10(t)m0 + h01(t)p1 + h11(t)m1 - * - *

in which P(t) is the polynomial p0 and p1 are the y coordinates of the reference points h00(t) - * = 2(t * t * t) - 3(t * t) + 1 h10(t) = (t* t * t) - 2(t * t) + t h01(t) = -2(t * t * t) + 3(t * - * t) h11(t) = (t * t * t) - (t * t) m0, m1 is the slope (derivative) of the points t = time - * (arbitrary point in interval) - * - *

It can be thought of as interpolating between the derivatives. - * https://www.desmos.com/calculator/wcjns2ayab Note: the two points surrounding a point is - * parrellel to the tangent. To get the slope of a point, we look at the points around it. - * - *

more information can be found here: https://en.wikipedia.org/wiki/Cubic_Hermite_spline - * - * @author Sam (sam.belliveau@gmail.com) - * @author Eric (ericlin071906@gmail.com) - */ -public class CubicInterpolator implements Interpolator { - - /** - * Get the tangents of the two reference points surrounding the point to be interpolated - * - * @param left the left point - * @param right the right point - * @return the slope/tangent (note that the slope and tangents are parallel - */ - private static double getTangent(Vector2D left, Vector2D right) { - return (right.y - left.y) / (right.x - left.x); - } - - private final int size; - private final Vector2D[] points; - private final double[] tangents; - - /** - * This constructor creates a new cubic hermite spline interpolator. It takes in at least 4 - * reference points it gets the tangent of every point by the two points around it and stores it - * in a array - * - * @param points the reference points we interpolate from. - */ - public CubicInterpolator(Vector2D... points) { - if (points.length < 4) { - throw new IllegalArgumentException("CubicInterpolator requires at least 4 points"); - } - - this.size = points.length; - this.points = Interpolator.getSortedPoints(points); - this.tangents = new double[size]; - - // gets the tangent (m0 and m1) - // note that the tangent of the points are parrallel to the slope of the 2 points - // surrounding it - this.tangents[0] = getTangent(this.points[0], this.points[1]); - this.tangents[size - 1] = getTangent(this.points[size - 2], this.points[size - 1]); - - for (int i = 1; i < size - 1; ++i) { - this.tangents[i] = getTangent(this.points[i - 1], this.points[i + 1]); - } - } - - @Override - public double interpolate(double x) { - // Find the nearest reference points to the distance - Vector2D left = Vector2D.kOrigin; // kOrigin is (0,0) - Vector2D right = Vector2D.kOrigin; - - double left_tangent = 0; - double right_tangent = 0; - - // Solve for the tangents of the left and right points that surround the target point - for (int i = 1; i < points.length; i++) { - Vector2D left_temp = points[i - 1]; - Vector2D right_temp = points[i - 0]; - - if (left_temp.x <= x && x <= right_temp.x) { - left = left_temp; - right = right_temp; - - left_tangent = tangents[i - 1]; - right_tangent = tangents[i - 0]; - - break; - } - } - - double gap = (right.x - left.x); - - // Apply the formula - double t = (x - left.x) / gap; - double tt = t * t; - double ttt = tt * t; - - double h00 = 2 * ttt - 3 * tt + 1; - double h10 = ttt - 2 * tt + t; - double h01 = -2 * ttt + 3 * tt; - double h11 = ttt - tt; - - return h00 * left.y + h10 * gap * left_tangent + h01 * right.y + h11 * gap * right_tangent; - } - - // Tests - public static void main(String... args) { - Interpolator test = - new CubicInterpolator( - new Vector2D(1, 1), - new Vector2D(3, 2), - new Vector2D(8, 5), - new Vector2D(10, 2)); - - for (double i = 3; i < 8; i += 0.5) { - System.out.println(new Vector2D(i, test.interpolate(i))); - } - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/Interpolator.java b/src/com/stuypulse/stuylib/math/interpolation/Interpolator.java deleted file mode 100644 index 185b4d05..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/Interpolator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.Vector2D; -import com.stuypulse.stuylib.streams.numbers.filters.IFilter; - -import java.util.Arrays; - -/** - * This class serves as a baseline for all other classes. The Interpolator is a filter that will - * find the values of any point given a few reference points - * - * @author Eric (ericlin071906@gmail.com) - * @author Ivan Wei (ivanw8288@gmail.com) - */ -public interface Interpolator extends IFilter { - - /** - * A behavior that takes in a double and returns a double - * - * @param x point to be intepolated - * @return interpolated value - */ - double interpolate(double x); - - // doesn't NEED to be overrided (hence the default). All filters need a get() method - // when get() is called, interpolated() will be passed through - default double get(double x) { - return interpolate(x); - } - - /** - * Returns the index of the point with the greatest x-coordinate less than or equal to x, or -1 - * if it is lower than every element. Assumes that the array is sorted. - * - * @param x the x-value to compare to - * @param points the points to find the lower bound among - * @return the index of the lower bound, or -1 - */ - public static int indexLowerBound(double x, Vector2D... points) { - for (int i = 0; i < points.length; ++i) { - if (points[i].x > x) { - return i - 1; - } - } - return points.length - 1; - } - - /** - * Performs an in-place sort by the value of x from smallest to greatest - * - * @param points the array for which to sort reference points - * @return the parameter array, for chaining - */ - public static Vector2D[] sortPoints(Vector2D[] points) { - Arrays.sort(points, (lhs, rhs) -> (int) (Math.signum(lhs.x - rhs.x))); - return points; - } - - /** - * Returns a sorted array of reference points by the value of x from smallest to greatest - * - * @param points reference points - * @return an array of sorted reference points - */ - public static Vector2D[] getSortedPoints(Vector2D... points) { - Vector2D[] output = points.clone(); - sortPoints(points); - return output; - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/IntervalInterpolator.java b/src/com/stuypulse/stuylib/math/interpolation/IntervalInterpolator.java deleted file mode 100644 index 2e4f9fec..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/IntervalInterpolator.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.Vector2D; - -/** - * This class uses two reference points to interpolate all points on a line between them - * - * @author Eric (ericlin071906@gmail.com) - */ -public class IntervalInterpolator implements Interpolator { - private final Vector2D point1; - private final Vector2D point2; - - /** - * Store the two reference points - * - * @param point1 first point to interpolate from - * @param point2 second point to interpolate from - */ - public IntervalInterpolator(Vector2D point1, Vector2D point2) { - this.point1 = point1; - this.point2 = point2; - } - - @Override - public double interpolate(double x) { - double range = point2.x - point1.x; - double slope = (point2.y - point1.y) / range; - double yIntercept = point1.y - (slope * point1.x); // y = mx + b - - double interpolatedValue = slope * x + yIntercept; - - return interpolatedValue; - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/LinearInterpolator.java b/src/com/stuypulse/stuylib/math/interpolation/LinearInterpolator.java deleted file mode 100644 index ae96e9eb..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/LinearInterpolator.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.Vector2D; - -/** - * Using this class will allow you to linearly interpolate between two surrounding reference points. - * - * @author Eric Lin (ericlin071906@gmail.com, Github: cire694) - * @author Sam (sam.belliveau@gmail.com) - */ -public class LinearInterpolator implements Interpolator { - - private final Vector2D[] points; - - // Sort the points in ascending order - public LinearInterpolator(Vector2D... points) { - if (points.length < 2) { - throw new IllegalArgumentException("Linear Interpolator needs at least 2 points"); - } - - this.points = Interpolator.getSortedPoints(points); - } - - @Override - /** - * @param x the point of interpolation to get an output - * @return interpolated value - */ - public double interpolate(double x) { - // Find the nearest refernce points to the distance - Vector2D left = Vector2D.kOrigin; // kOrigin is (0,0) - Vector2D right = Vector2D.kOrigin; - - // Searching for the points on the left and right of the target point. - - if (x < points[0].x) { - left = points[0]; - right = points[1]; - } else if (x > points[points.length - 1].x) { - left = points[points.length - 2]; - right = points[points.length - 1]; - } else { - for (int i = 1; i < points.length; i++) { - Vector2D left_temp = points[i - 1]; - Vector2D right_temp = points[i - 0]; - - if (left_temp.x <= x && x <= right_temp.x) { - left = left_temp; - right = right_temp; - - break; - } - } - } - - return new IntervalInterpolator(left, right).interpolate(x); - } - - // Tests - public static void main(String... args) { - Interpolator test = - new LinearInterpolator( - new Vector2D(1, 6), - new Vector2D(6.5, 3), - new Vector2D(12, 6), - new Vector2D(9, 1)); - - for (double i = 1; i < 12; i += 0.5) { - System.out.println(new Vector2D(i, test.interpolate(i))); - } - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/NearestInterpolator.java b/src/com/stuypulse/stuylib/math/interpolation/NearestInterpolator.java deleted file mode 100644 index cec8f3ff..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/NearestInterpolator.java +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.SLMath; -import com.stuypulse.stuylib.math.Vector2D; - -import java.util.function.BiFunction; - -/** - * A nearest interpolator takes the y-value of the reference point closest on the x-axis. - * - *

There are three interpolation "biases": left, center, right. The center "bias" will simply use - * x-axis distance to find the nearest reference point to the x-value being interpolated for. - * However, the left and right "biases" will only use reference points to the left and right, - * respectively. - * - *

Because left and right biases reject points, they may not have reference points for certain - * x-values, in which case extrapolation is done using the y-value of the nearest point. - * - * @author Myles Pasetsky - */ -public class NearestInterpolator implements Interpolator { - - /** A bias describes how the interpolator will accept or reject points. */ - public static enum Bias { - // use points to the left - kLeft((x, point) -> x >= point.x), - - // use any point - kCenter((x, point) -> true), - - // use points to the right - kRight((x, point) -> x <= point.x); - - private BiFunction mAcceptor; - - private Bias(BiFunction acceptor) { - mAcceptor = acceptor; - } - - private boolean accept(double x, Vector2D point) { - return mAcceptor.apply(x, point); - } - } - - /** array of reference points */ - private final Vector2D[] mPoints; - - /** bias mode to use */ - private final Bias mBias; - - /** - * Creates a nearest interpolator given a bias mode and reference points. - * - *

There must be at least one reference point. - * - * @param bias bias mode - * @param points reference points - */ - public NearestInterpolator(Bias bias, Vector2D... points) { - if (points.length < 1) { - throw new IllegalArgumentException("Nearest Interpolator requires 1 point"); - } - - mPoints = Interpolator.getSortedPoints(points); - mBias = bias; - } - - /** - * Given an x-value, returns the y-value of the nearest reference point. - * - *

Due to biasing of reference points, there may be no point to refer to. In this case, - * extrapolation is done. This means if the input x is biased to the left, but there are no - * reference points to its left, it will use the rightmost point. - * - * @param x the input value to interpolate the value of - * @return the interpolated value - */ - @Override - public double interpolate(double x) { - double nearest = Double.MAX_VALUE; - double y = Double.NaN; - - for (Vector2D point : mPoints) { - if (!mBias.accept(x, point)) continue; - - double distance = Math.abs(point.x - x); - if (distance < nearest) { - nearest = distance; - y = point.y; - } - } - - if (Double.isNaN(y)) { - if (x < mPoints[0].x) return mPoints[0].y; - else return mPoints[mPoints.length - 1].y; - } - - return y; - } - - public static void main(String[] args) { - for (Bias bias : new Bias[] {Bias.kLeft, Bias.kCenter, Bias.kRight}) { - System.out.println(bias.name()); - - NearestInterpolator interp = - new NearestInterpolator(bias, new Vector2D(+0.25, +1), new Vector2D(+0.75, -1)); - - for (double i = 0; i <= 1.0; i += 0.05) { - System.out.println(SLMath.round(i, 2) + " -> " + interp.get(i)); - } - System.out.println(); - } - } -} diff --git a/src/com/stuypulse/stuylib/math/interpolation/PolyInterpolator.java b/src/com/stuypulse/stuylib/math/interpolation/PolyInterpolator.java deleted file mode 100644 index 6f781801..00000000 --- a/src/com/stuypulse/stuylib/math/interpolation/PolyInterpolator.java +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.math.interpolation; - -import com.stuypulse.stuylib.math.Vector2D; - -import java.util.ArrayList; - -/** - * This class uses Lagrange polynomial interpolation. It derives an equation for a set of points in - * the form - * - *

P(x) = a(x) + b(x) + c(x) ... - * - *

where a(x), b(x), c(x) .., is a "sub" - polynomial / "partial" - polynomial. - * - *

These partial polynomials are derived from the reference data provided. The partial polynomial - * is derived by a(x-r1)(x-r2)(x-r3)... in where - * - *

r1, r2, r3,... are the x coordinates of the reference points NOT including the current - * reference point a is the y coordinate current reference point divided by (x-r1)(x-r2)(x-r3)..., - * - *

where x is replaced by the current x coordinate of the reference point, and NOT including the - * current reference point. - * - *

We then sum up all the partial polynomials to get the final polynomial. This final polynomial - * is a polynomial that all reference points will pass through. We plug the x value of the y we want - * to find into this polynomial and it will return the y value. - * - * @author Eric Lin (ericlin071906@gmail.com) - * @author Myles Pasetsky (selym3 on github) - */ -public class PolyInterpolator implements Interpolator { - - /** - * This class contains a constructor that creates a polynomial. It has several functions that - * can be called - */ - private static class Polynomial { - private double a; - private ArrayList factors; - - /** - * A constructor that creates a new (partial) polynomial and stores all factors in a new - * arrayList for easy access - */ - public Polynomial() { - a = 0.0; - factors = new ArrayList<>(); - } - - /** - * Set the coefficent of a - * - * @param a - */ - public void setCoefficient(double a) { - this.a = a; - } - - public void addZero(double zero) { - // Add factor to the list of factors - factors.add(zero); - } - - /** - * Evaluates polynomial in the form a * (x - factors[0]) * (x - factors[1]) * ... - * - * @param x target point (point we want to interpolate the y for) - * @return output (y) - */ - public double get(double x) { - double output = a; - for (double factor : factors) { - output *= (x - factor); - } - return output; - } - } - - /** - * This class a partial polynomial that is used to derive the polynomial - * - * @param targetReference the reference point for that partial polynomial - * @param points the reference points (for that partial polynomial) - * @return a partial polynomial - */ - private static Polynomial getPartialPolynomial(Vector2D targetReference, Vector2D[] points) { - - Polynomial polynomial = new Polynomial(); - double a = targetReference.y; - - for (Vector2D point : points) { - if (point != targetReference) { - a /= targetReference.x - point.x; - polynomial.addZero(point.x); - } - } - polynomial.setCoefficient(a); - return polynomial; - } - - private final Polynomial[] partialPolynomials; // storing the partial polynomials - - /** - * Constructor for the class that takes in a set of points and creates a polynomial - * - * @param points are reference points - */ - public PolyInterpolator(Vector2D... points) { - if (points.length <= 1) { - throw new IllegalArgumentException("PolyInterpolator needs at least 2 or more points"); - } - - partialPolynomials = new Polynomial[points.length]; - - // creates a list of partial polynomials - for (int i = 0; i < points.length; i++) { - partialPolynomials[i] = getPartialPolynomial(points[i], points); - } - } - - @Override - /** - * Adds the list of partial polynomials from above, while plugging x into the polynomial - * - * @param x target point - */ - public double interpolate(double x) { - double fullPolynomial = 0; - for (int i = 0; i < partialPolynomials.length; i++) { - fullPolynomial += partialPolynomials[i].get(x); - } - return fullPolynomial; - } -} diff --git a/src/com/stuypulse/stuylib/network/SLNetworkTable.java b/src/com/stuypulse/stuylib/network/SLNetworkTable.java deleted file mode 100644 index f2ca35bb..00000000 --- a/src/com/stuypulse/stuylib/network/SLNetworkTable.java +++ /dev/null @@ -1,276 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.network; - -import edu.wpi.first.networktables.GenericEntry; -import edu.wpi.first.networktables.NetworkTable; -import edu.wpi.first.networktables.NetworkTableInstance; - -import java.util.Set; - -/** - * The SLNetworkTable is a very fast way to easily interface with a network table. - * - *

If a function you want is not implemented, use {@link SLNetworkTable#getTable()}, {@link - * SLNetworkTable#getGenericEntry(String)}, or {@link SLNetworkTable#getInstance()} to call the - * function yourself - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class SLNetworkTable { - - /*********************/ - /***** FACTORIES *****/ - /*********************/ - - /** - * Opens network table on local device. IE a robot opens a network table for other devices to - * connect to - * - * @param table network table name - * @return Configured Network Table Wrapper - */ - public static SLNetworkTable open(String table) { - return open(NetworkTableInstance.getDefault(), table); - } - - /** - * Opens network table that is connected to a robot. IE a program connecting to a robot. - * - * @param team team number - * @param table network table name - * @return Configured Network Table Wrapper - */ - public static SLNetworkTable open(int team, String table) { - NetworkTableInstance instance = NetworkTableInstance.create(); - instance.startClient4("stuylib"); - instance.setServerTeam(team); - return open(instance, table); - } - - /** - * Opens network table with special instance. - * - * @param instance NetworkTableInstance - * @param table network table name - * @return Configured Network Table Wrapper - */ - public static SLNetworkTable open(NetworkTableInstance instance, String table) { - return new SLNetworkTable(instance, table); - } - - /*********************/ - /***** VARIABLES *****/ - /*********************/ - - private NetworkTableInstance mInstance; // Instance contains IP/Related - // information - private NetworkTable mTable; // Current Data Table - private String mTableName = ""; // Name of Data Table - - /************************/ - /***** CONSTRUCTORS *****/ - /************************/ - - /** - * Creates a Network Table Wrapper opened on table "tableName", and with the a special - * NetworkTableInstance (ie. if you are making a client) - * - * @param tableName network table name - * @param instance custom network table instance - */ - private SLNetworkTable(NetworkTableInstance instance, String table) { - mInstance = instance; - mTable = mInstance.getTable(table); - mTableName = table; - } - - /****************************/ - /***** VARIABLE GETTERS *****/ - /****************************/ - - /** - * Gets current network table instance - * - * @return current network table instance - */ - public NetworkTableInstance getInstance() { - return mInstance; - } - - /** - * Gets current network table - * - * @return current network table - */ - public NetworkTable getTable() { - return mTable; - } - - /** - * Gets current network table name - * - * @return current network table name - */ - public String getTableName() { - return mTableName; - } - - /************************/ - /***** MISC GETTERS *****/ - /************************/ - - /** - * Checks if network table is connected - * - * @return if network table is connected - */ - public boolean isConnected() { - return getInstance().isConnected(); - } - - /** - * Gets a set of all key names in network table - * - * @return set of key names in network table - */ - public Set getKeys() { - return mTable.getKeys(); - } - - /** - * Get a Topic for a key - * - * @param key key name - * @return Topic for key - */ - public GenericEntry getGenericEntry(String key) { - return mTable.getTopic(key).getGenericEntry(); - } - - /** - * Checks if key is a valid entry - * - * @param key key name - * @return if key is a valid entry - */ - public boolean isEntryValid(String key) { - return getGenericEntry(key).isValid(); - } - - /** - * Checks to see if network table contains key - * - * @param key key name - * @return if network table contains key - */ - public boolean containsKey(String key) { - return mTable.containsKey(key); - } - - /****************************************/ - /***** GETTING NETWORK TABLE VALUES *****/ - /****************************************/ - - /** Boolean returned if no entry is found */ - public static final boolean DEFAULT_BOOLEAN = false; - - /** - * Get boolean from network table - * - * @param key key name - * @return value - */ - public boolean getBoolean(String key) { - return getGenericEntry(key).getBoolean(DEFAULT_BOOLEAN); - } - - /** Double returned if no entry is found */ - public static final double DEFAULT_DOUBLE = 0.0; - - /** - * Get Double from network table - * - * @param key key name - * @return value - */ - public double getDouble(String key) { - return getGenericEntry(key).getDouble(DEFAULT_DOUBLE); - } - - /** Number returned if no entry is found */ - public static final Number DEFAULT_NUMBER = 0.0; - - /** - * Get Number from network table - * - * @param key key name - * @return value - */ - public Number getNumber(String key) { - return getGenericEntry(key).getDouble((double) DEFAULT_NUMBER); - } - - /** String returned if no entry is found */ - public static final String DEFAULT_STRING = ""; - - /** - * Get String from network table - * - * @param key key name - * @return value - */ - public String getString(String key) { - return getGenericEntry(key).getString(DEFAULT_STRING); - } - - /****************************************/ - /***** SETTING NETWORK TABLE VALUES *****/ - /****************************************/ - - /** - * Set boolean in network table - * - * @param key key name - * @param value desired value - * @return returns false if entry exists with other type - */ - public boolean setBoolean(String key, boolean value) { - return getGenericEntry(key).setBoolean(value); - } - - /** - * Set double in network table - * - * @param key key name - * @param value desired value - * @return returns false if entry exists with other type - */ - public boolean setDouble(String key, double value) { - return getGenericEntry(key).setDouble(value); - } - - /** - * Set Number in network table - * - * @param key key name - * @param value desired value - * @return returns false if entry exists with other type - */ - public boolean setNumber(String key, Number value) { - return getGenericEntry(key).setDouble((double) value); - } - - /** - * Set String in network table - * - * @param key key name - * @param value desired value - * @return returns false if entry exists with other type - */ - public boolean setString(String key, String value) { - return getGenericEntry(key).setString(value); - } -} diff --git a/src/com/stuypulse/stuylib/network/limelight/Limelight.java b/src/com/stuypulse/stuylib/network/limelight/Limelight.java deleted file mode 100644 index 92c43d7e..00000000 --- a/src/com/stuypulse/stuylib/network/limelight/Limelight.java +++ /dev/null @@ -1,513 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.network.limelight; - -import com.stuypulse.stuylib.math.SLMath; -import com.stuypulse.stuylib.math.Vector2D; - -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation3d; - -/** - * This is a class that lets you interface with the limelight network table. - * - * @author Sam (sam.belliveau@gmail.com) - * @author Vincent Wang (vincentw921) - */ -public final class Limelight { - - /*****************/ - /*** Singleton ***/ - /*****************/ - - private static Limelight mDefaultInstance = null; - - /** - * Returns a Limelight Class using the default table name. - * - *

If you only have one limelight, this is most likely the constructor you want to use. - * - * @return instance of limelight - */ - public static Limelight getInstance() { - if (mDefaultInstance == null) mDefaultInstance = new Limelight(); - return mDefaultInstance; - } - - /** - * Returns a Limelight Class using a custom table name. - * - *

If you have multiple limelights, this is most likely the constructor you want to use. - * - * @param tableName the table name of the limelight - * @return instance of limelight - */ - public static Limelight getInstance(String tableName) { - return new Limelight(tableName); - } - - /********************/ - /*** Constructors ***/ - /********************/ - - /** - * Construct a Limelight Class using the default table name. - * - *

If you only have one limelight, this is most likely the constructor you want to use. - */ - private Limelight() { - table = new LimelightTable(); - } - - /** - * Construct a Limelight Class using a custom table name. - * - *

If you have multiple limelights, this is most likely the constructor you want to use. - * - * @param tableName the table name of the limelight - */ - private Limelight(String tableName) { - table = new LimelightTable(tableName); - } - - /****************************/ - /*** Variable Definitions ***/ - /****************************/ - - private final LimelightTable table; - - /************************/ - /*** Connnection Test ***/ - /************************/ - - /** @return name of Limelight NetworkTables */ - public String getTableName() { - return table.tableName; - } - - /** @return time of last network table change from limelight */ - public long getLastUpdate() { - long lastChange = table.latency.getLastChange(); - lastChange = Math.max(lastChange, table.xAngle.getLastChange()); - lastChange = Math.max(lastChange, table.yAngle.getLastChange()); - return lastChange; - } - - /** @return if the limelight has updated its */ - public boolean isConnected() { - final long MAX_UPDATE_TIME = 250_000; - - table.timingEntry.set(!table.timingEntry.get()); - long currentTime = table.timingEntry.getLastChange(); - - return Math.abs(currentTime - getLastUpdate()) < MAX_UPDATE_TIME; - } - - /*****************************************/ - /*** Commonly Used Contour Information ***/ - /*****************************************/ - - /** @return Whether the limelight has any valid targets */ - public boolean getValidTarget() { - return (table.validTarget.get() > 0.5) && (isConnected()); - } - - /** @return Horizontal Offset From Crosshair To Target (-27 degrees to 27 degrees) */ - public double getTargetXAngle() { - return table.xAngle.get(); - } - - /** @return Vertical Offset From Crosshair To Target (-20.5 degrees to 20.5 degrees) */ - public double getTargetYAngle() { - return table.yAngle.get(); - } - - /** @return Percent of the screen the target takes up on a scale of 0 to 1 */ - public double getTargetArea() { - // Lime light returns a double from 0 - 100 - // Divide by 100 to scale number from 0 - 1 - return SLMath.clamp(table.targetArea.get(0) / 100.0, 0, 1); - } - - /** @return Skew or rotation (-90 degrees to 0 degrees) */ - public double getTargetSkew() { - return table.targetSkew.get(); - } - - /** @return Latency of limelight information in milli-seconds */ - public double getLatencyMs() { - // Add Image Capture Latency to get more accurate result - return table.latency.get() + LimelightConstants.IMAGE_CAPTURE_LATENCY; - } - - /********************/ - /*** Side Lengths ***/ - /********************/ - - /** @return Shortest side length of target in pixels */ - public double getShortestSidelength() { - return table.shortestSideLength.get(); - } - - /** @return Sidelength of longest side of the fitted bounding box (0 - 320 pixels) */ - public double getLongestSidelength() { - return table.longestSideLength.get(); - } - - /** @return Horizontal sidelength of the rough bounding box (0 - 320 pixels) */ - public double getHorizontalSidelength() { - return table.horizontalSideLength.get(); - } - - /** @return Vertical sidelength of the rough bounding box (0 - 320 pixels) */ - public double getVerticalSidelength() { - return table.verticalSideLength.get(); - } - - /**********************/ - /*** Target Corners ***/ - /**********************/ - - /** @return Number array of corner x-coordinates */ - public double[] getRawTargetCornersX() { - return table.xCorners.get(); - } - - /** @return Number array of corner y-coordinates */ - public double[] getRawTargetCornersY() { - return table.yCorners.get(); - } - - /** @return Vector2D array of the target corners */ - public Vector2D[] getTargetCorners() { - double[] rawX = getRawTargetCornersX(); - double[] rawY = getRawTargetCornersX(); - - if (rawX.length != 0 && rawY.length != 0 && rawX.length == rawY.length) { - int length = rawX.length; - - Vector2D[] output = new Vector2D[length]; - - for (int i = 0; i < length; ++i) { - output[i] = new Vector2D(rawX[i], rawY[i]); - } - - return output; - } - - return new Vector2D[] {}; - } - - /**************************************************************/ - /*** Advanced Usage with Raw Contours (Not sent by default) ***/ - /**************************************************************/ - - // Raw Contours are formatted as tx0, ty0, tx1, ty1, tx2, ty2 - // So to make this easier, you pass an int and it formats it - - /** - * @param target Target to read X Angle from - * @return X Angle of corresponding target - */ - public double getRawTargetXAngle(int target) { - return table.getGenericEntry("tx" + target).getDouble(0); - } - - /** - * @param target Target to read Y Angle from - * @return Y Angle of corresponding target - */ - public double getRawTargetYAngle(int target) { - return table.getGenericEntry("ty" + target).getDouble(0); - } - - /** - * @param target Target to read Area from - * @return Percent of the screen the corresponding target takes up on a scale of 0 to 1 - */ - public double getRawTargetArea(int target) { - // Lime light returns a double from 0 - 100 - // Divide by 100 to scale number from 0 - 1 - return SLMath.clamp(table.getGenericEntry("ta" + target).getDouble(0) / 100.0, 0, 1); - } - - /** - * @param target Target to read Skew from - * @return Skew of corresponding target - */ - public double getRawTargetSkew(int target) { - return table.getGenericEntry("ts" + target).getDouble(0); - } - - /** - * @param crosshair Crosshair to read coords from - * @return X Coordinate of corresponding crosshair - */ - public double getCustomRawCrosshairX(int crosshair) { - return table.getGenericEntry("cx" + crosshair).getDouble(0); - } - - /** - * @param crosshair Crosshair to read coords from - * @return Y Coordinate of corresponding crosshair - */ - public double getRawCrosshairY(int crosshair) { - return table.getGenericEntry("cy" + crosshair).getDouble(0); - } - - /****************/ - /*** Solve 3D ***/ - /****************/ - - /** - * @param arr Array of doubles to convert to a Pose3d - * @return Pose3d from array - */ - private Pose3d arrayToPose3d(final double[] arr) { - if (arr != null && arr.length == 6) { - return new Pose3d( - arr[0], - arr[1], - arr[2], - new Rotation3d( - Math.toRadians(arr[3]), - Math.toRadians(arr[4]), - Math.toRadians(arr[5]))); - } - - return null; - } - - /** @return The Solve 3D Result */ - public Pose3d getSolve3D() { - return arrayToPose3d(table.solve3D.get(new double[] {})); - } - - /** @return The Pose3d of the robot in the field */ - public Pose3d getRobotPose() { - return arrayToPose3d(table.botpose.get(new double[] {})); - } - - /****************************/ - /*** AprilTag Information ***/ - /****************************/ - - /** @return ID of the primary AprilTag */ - public long getTagID() { - return table.tagID.get(); - } - - /***************************/ - /*** Camera Mode Control ***/ - /***************************/ - - /** @param mode Specified LED Mode to set the limelight to */ - public void setLEDMode(LEDMode mode) { - table.ledMode.set(mode.getCodeValue()); - } - - /** @param mode Specified Cam Mode to set the limelight to */ - public void setCamMode(CamMode mode) { - table.camMode.set(mode.getCodeValue()); - } - - /** @param mode Specified Snapshot Mode to set the limelight to */ - public void setSnapshotMode(SnapshotMode mode) { - table.snapshotMode.set(mode.getCodeValue()); - } - - /** @param stream Specified Camera Stream to set the limelight to */ - public void setCameraStream(CameraStream stream) { - table.cameraStream.set(stream.getCodeValue()); - } - - /** @param pipeline Specified pipeline to set the limelight to */ - public void setPipeline(Pipeline pipeline) { - if (!pipeline.equals(Pipeline.INVALID_PIPELINE)) - table.pipeline.set(pipeline.getCodeValue()); - } - - /** @return The current pipeline the limelight is set to */ - public Pipeline getPipeline() { - double ntValue = table.getPipeline.get(); - int pipelineID = (int) (ntValue + 0.5); - switch (pipelineID) { - case 0: - return Pipeline.SETTING_0; - case 1: - return Pipeline.SETTING_1; - case 2: - return Pipeline.SETTING_2; - case 3: - return Pipeline.SETTING_3; - case 4: - return Pipeline.SETTING_4; - case 5: - return Pipeline.SETTING_5; - case 6: - return Pipeline.SETTING_6; - case 7: - return Pipeline.SETTING_7; - case 8: - return Pipeline.SETTING_8; - case 9: - return Pipeline.SETTING_9; - default: - return Pipeline.INVALID_PIPELINE; - } - } - - /*************************************/ - /*** Camera Modes Enum Definitions ***/ - /*************************************/ - - /** Modes for how the lights on the Limelight should be configured */ - public enum LEDMode { - /* Use LED mode set in pipeline */ - PIPELINE(0), - - /* Force LEDs off */ - FORCE_OFF(1), - - /* Force LEDs to blink */ - FORCE_BLINK(2), - - /* Force LEDs on */ - FORCE_ON(3); - - private final int value; - - LEDMode(int value) { - this.value = value; - } - - public int getCodeValue() { - return value; - } - }; - - /** Modes for how the Camera should be configured */ - public enum CamMode { - /* Use limelight for CV */ - VISION(0), - - /* Use limelight for Driving */ - DRIVER(1); - - private final int value; - - CamMode(int value) { - this.value = value; - } - - public int getCodeValue() { - return value; - } - }; - - /** Mode for how the limelight should take snapshots */ - public enum SnapshotMode { - /* Don't take snapshots */ - STOP(0), - - /* Take two snapshots per second */ - TWO_PER_SECOND(1); - - private final int value; - - SnapshotMode(int value) { - this.value = value; - } - - public int getCodeValue() { - return value; - } - }; - - /** Modes for how the camera stream over the network should be delivered */ - public enum CameraStream { - /* Shows limelight and secondary camera side by side */ - STANDARD(0), - - /** Shows the secondary camera along with and within the limelight camera */ - PIP_MAIN(1), - - /** Shows the limelight along with and within the limelight camera */ - PIP_SECONDARY(2); - - private final int value; - - CameraStream(int value) { - this.value = value; - } - - public int getCodeValue() { - return value; - } - }; - - /** The different Pipelines that the limelight camera can be set to */ - public enum Pipeline { - INVALID_PIPELINE(-1), - SETTING_0(0), - SETTING_1(1), - SETTING_2(2), - SETTING_3(3), - SETTING_4(4), - SETTING_5(5), - SETTING_6(6), - SETTING_7(7), - SETTING_8(8), - SETTING_9(9); - - private final int value; - - Pipeline(int value) { - this.value = value; - } - - public int getCodeValue() { - return value; - } - }; - - /**************************/ - /*** Custom Grip Values ***/ - /**************************/ - - /** - * @param element Name of double provided by GRIP Pipeline - * @return Double provided by GRIP Pipeline - */ - public double getCustomDouble(String element) { - return table.getGenericEntry(element).getDouble(0); - } - - /** - * @param element Name of Number to set on Network Table - * @param value Value to set the Number on the Network Table to - * @return Whether or not the write was successful - */ - public boolean setCustomNumber(String element, Number value) { - return table.getGenericEntry(element).setDouble((double) value); - } - - /** - * @param element Name of String provided by GRIP Pipeline - * @return String provided by GRIP Pipeline - */ - public String getCustomString(String element) { - return table.getGenericEntry(element).getString(""); - } - - /** - * @param element Name of String to set on Network Table - * @param value Value to set the Sting on the Network Table to - * @return Whether or not the write was successful - */ - public boolean setCustomString(String element, String value) { - return table.getGenericEntry(element).setString(value); - } -} diff --git a/src/com/stuypulse/stuylib/network/limelight/LimelightConstants.java b/src/com/stuypulse/stuylib/network/limelight/LimelightConstants.java deleted file mode 100644 index e68484e6..00000000 --- a/src/com/stuypulse/stuylib/network/limelight/LimelightConstants.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.network.limelight; - -/** - * This class defines all of the constants defined in the Limelight Documentation. Usage of these - * numbers is rare, but this is good to have. - * - * @author Sam B (sam.belliveau@gmail.com) - */ -public final class LimelightConstants { - - /** Prevent class from being extended. */ - private LimelightConstants() {} - - /*************************/ - /*** Camera Mode Enums ***/ - /*************************/ - - public static final double IMAGE_CAPTURE_LATENCY = 11; - - public static final double MIN_X_ANGLE = -27; - public static final double MAX_X_ANGLE = 27; - - public static final double MIN_Y_ANGLE = -20.5; - public static final double MAX_Y_ANGLE = 20.5; - - public static final double MIN_TARGET_AREA = 0; - public static final double MAX_TARGET_AREA = 1; - - public static final double MIN_SKEW = -90; - public static final double MAX_SKEW = 0; - - public static final double MIN_SIDE_LENGTH = 0; - public static final double MAX_SIDE_LENGTH = 320; -} diff --git a/src/com/stuypulse/stuylib/network/limelight/LimelightTable.java b/src/com/stuypulse/stuylib/network/limelight/LimelightTable.java deleted file mode 100644 index d20de1f7..00000000 --- a/src/com/stuypulse/stuylib/network/limelight/LimelightTable.java +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.network.limelight; - -import edu.wpi.first.networktables.BooleanEntry; -import edu.wpi.first.networktables.DoubleArrayEntry; -import edu.wpi.first.networktables.DoubleEntry; -import edu.wpi.first.networktables.GenericEntry; -import edu.wpi.first.networktables.IntegerEntry; -import edu.wpi.first.networktables.NetworkTable; -import edu.wpi.first.networktables.NetworkTableInstance; - -/** - * This class provides an extremely low level implementation construction of the limelight network - * table. It defines all of the NetworkTabe entries, and nothing else. This is not made for use in - * robot code, but instead to assist other API's that use the limelight. - * - * @author Sam B (sam.belliveau@gmail.com) - * @author Vincent Wang (vincentw921) - */ -public final class LimelightTable { - - /** Create a LimelightTable with the default table name */ - public LimelightTable() { - this("limelight"); - } - - /** - * Create a LimelightTable with a custom NetworkTable name. This may be used if we need multiple - * limelights. - * - * @param tableName the custom name of the limelight's network table - */ - public LimelightTable(String tableName) { - tableInstance = NetworkTableInstance.getDefault(); - table = tableInstance.getTable(tableName); - - this.tableName = tableName; - - validTarget = table.getIntegerTopic("tv").getEntry(0); - - xAngle = table.getDoubleTopic("tx").getEntry(0); - yAngle = table.getDoubleTopic("ty").getEntry(0); - - targetArea = table.getDoubleTopic("ta").getEntry(0); - targetSkew = table.getDoubleTopic("ts").getEntry(0); - - latency = table.getIntegerTopic("tl").getEntry(0); - - shortestSideLength = table.getDoubleTopic("tshort").getEntry(0); - longestSideLength = table.getDoubleTopic("tlong").getEntry(0); - horizontalSideLength = table.getDoubleTopic("thor").getEntry(0); - verticalSideLength = table.getDoubleTopic("tvert").getEntry(0); - - xCorners = table.getDoubleArrayTopic("tcornx").getEntry(new double[] {}); - yCorners = table.getDoubleArrayTopic("tcorny").getEntry(new double[] {}); - - solve3D = table.getDoubleArrayTopic("campose").getEntry(new double[] {}); - botpose = table.getDoubleArrayTopic("botpose").getEntry(new double[] {}); - - tagID = table.getIntegerTopic("tid").getEntry(-1); - - ledMode = table.getIntegerTopic("ledMode").getEntry(0); - camMode = table.getIntegerTopic("camMode").getEntry(0); - pipeline = table.getIntegerTopic("pipeline").getEntry(0); - getPipeline = table.getIntegerTopic("getpipe").getEntry(0); - cameraStream = table.getIntegerTopic("stream").getEntry(0); - snapshotMode = table.getIntegerTopic("snapshot").getEntry(0); - - timingEntry = table.getBooleanTopic(".timing_data").getEntry(false); - } - - /****************************************************/ - /*** Network Table Info used to contact Limelight ***/ - /****************************************************/ - - public final NetworkTableInstance tableInstance; - - public final NetworkTable table; - - public final String tableName; - - /****************************************************************/ - /*** Network Table Entries used to communicate with Limelight ***/ - /****************************************************************/ - - // Whether the limelight has any valid targets (0 or 1) - public final IntegerEntry validTarget; - - // Horizontal Offset From Crosshair To Target (-27 degrees to 27 degrees) - public final DoubleEntry xAngle; - - // Vertical Offset From Crosshair To Target (-20.5 degrees to 20.5 degrees) - public final DoubleEntry yAngle; - - // Target Area (0% of image to 100% of image) - public final DoubleEntry targetArea; - - // Skew or rotation (-90 degrees to 0 degrees) - public final DoubleEntry targetSkew; - - // The pipeline’s latency contribution (ms) Add at - // least 11ms for image capture latency. - public final IntegerEntry latency; - - // Pixel information returned from these functions - public final DoubleEntry shortestSideLength; - public final DoubleEntry longestSideLength; - public final DoubleEntry horizontalSideLength; - public final DoubleEntry verticalSideLength; - - // Corner DoubleArrayEntry - public final DoubleArrayEntry xCorners; - public final DoubleArrayEntry yCorners; - - // Solve 3D DoubleArrayEntrys - public final DoubleArrayEntry solve3D; - public final DoubleArrayEntry botpose; - - // AprilTag Information - public final IntegerEntry tagID; - - // Camera Control DoubleEntrys - public final IntegerEntry ledMode; - public final IntegerEntry camMode; - public final IntegerEntry pipeline; - public final IntegerEntry getPipeline; - public final IntegerEntry cameraStream; - public final IntegerEntry snapshotMode; - - // Custom Timing DoubleEntrys - public final BooleanEntry timingEntry; - - /************************************************/ - /*** Functions to get Entries not listed here ***/ - /************************************************/ - - /** - * @param key ID of value on the network table - * @return The {@link GenericEntry} of the network table value on the Limelight Table - */ - public GenericEntry getGenericEntry(String key) { - return table.getTopic(key).getGenericEntry(); - } -} diff --git a/src/com/stuypulse/stuylib/network/limelight/Solve3DResult.java b/src/com/stuypulse/stuylib/network/limelight/Solve3DResult.java deleted file mode 100644 index ddc40a81..00000000 --- a/src/com/stuypulse/stuylib/network/limelight/Solve3DResult.java +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.network.limelight; - -import com.stuypulse.stuylib.math.Angle; - -/** - * Class that is used to return solve 3D results from the limelight - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class Solve3DResult { - - // Position Data - private double mX; - private double mY; - private double mZ; - - // Rotation Data - private Angle mPitch; - private Angle mYaw; - private Angle mRoll; - - /** - * Initialize each part of the Solve3DResult - * - * @param x x position - * @param y y position - * @param z z position - * @param pitch pitch - * @param yaw yaw - * @param roll roll - */ - public Solve3DResult(double x, double y, double z, double pitch, double yaw, double roll) { - mX = x; - mY = y; - mZ = z; - - mPitch = Angle.fromDegrees(pitch); - mYaw = Angle.fromDegrees(yaw); - mRoll = Angle.fromDegrees(roll); - } - - /** - * Parse data from array into class - * - * @param data array that the limelight returns - */ - public Solve3DResult(double[] data) { - this(data[0], data[1], data[2], data[3], data[4], data[5]); - } - - /** - * Get x from Solve3D Result - * - * @return x position - */ - public double getX() { - return mX; - } - - /** - * Get y from Solve3D Result - * - * @return y position - */ - public double getY() { - return mY; - } - - /** - * Get z from Solve3D Result - * - * @return z position - */ - public double getZ() { - return mZ; - } - - /** - * Get pitch from Solve3D Result - * - * @return pitch - */ - public Angle getPitch() { - return mPitch; - } - - /** - * Get yaw from Solve3D Result - * - * @return yaw - */ - public Angle getYaw() { - return mYaw; - } - - /** - * Get roll from Solve3D Result - * - * @return roll - */ - public Angle getRoll() { - return mRoll; - } -} diff --git a/src/com/stuypulse/stuylib/network/limelight/readme.md b/src/com/stuypulse/stuylib/network/limelight/readme.md deleted file mode 100644 index 927217fd..00000000 --- a/src/com/stuypulse/stuylib/network/limelight/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# StuyLib Limelight Library - -WIP... \ No newline at end of file diff --git a/src/com/stuypulse/stuylib/streams/angles/AFuser.java b/src/com/stuypulse/stuylib/streams/angles/AFuser.java deleted file mode 100644 index 0a4dbd9a..00000000 --- a/src/com/stuypulse/stuylib/streams/angles/AFuser.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.angles; - -import com.stuypulse.stuylib.math.Angle; -import com.stuypulse.stuylib.streams.angles.filters.AFilter; -import com.stuypulse.stuylib.streams.angles.filters.AHighPassFilter; -import com.stuypulse.stuylib.streams.angles.filters.ALowPassFilter; - -/** - * A class that combines two AStreams, usually in order to combine some slow data source with a - * faster one. The Base Measurement should generally drift less while the Fast Measurement should - * have less delay. The Fast measurement will go through a high pass filter so it is less important - * if that one drifts compared to the Base Measurement. - * - *

Example Usage: BaseMeasurement = Limelight, FastMeasurement = Encoders - * - * @author Myles Pasetsky - */ -public class AFuser implements AStream { - - private final Number mFilterRC; - - private final AStream mBase; - private final AStream mFast; - - private AFilter mBaseFilter; - private AFilter mFastFilter; - - private Angle mFastOffset; - - /** - * Create an AFuser with an RC, Base/Fast Measurement stream - * - * @param rc RC value for the lowpass / highpass filters - * @param baseMeasurement a stream that returns the slow, but accurate measurement values - * @param fastMeasurement a stream that returns faster, less accurate measurement values - */ - public AFuser(Number rc, AStream baseMeasurement, AStream fastMeasurement) { - mBase = baseMeasurement; - mFast = fastMeasurement; - - mFilterRC = rc; - - reset(); - } - - /** Resets the AFuser so that it can ignore any previous data / reset its initial read */ - public void reset() { - mBaseFilter = new ALowPassFilter(mFilterRC); - mFastFilter = new AHighPassFilter(mFilterRC); - - mFastOffset = mBase.get().sub(mFast.get()); - } - - private Angle getBase() { - return mBaseFilter.get(mBase.get()); - } - - private Angle getFast() { - return mFastFilter.get(mFast.get().add(mFastOffset)); - } - - /** Get the result of merging the two datastreams together */ - public Angle get() { - return getBase().add(getFast()); - } -} diff --git a/src/com/stuypulse/stuylib/streams/numbers/filters/Integral.java b/src/com/stuypulse/stuylib/streams/numbers/filters/Integral.java deleted file mode 100644 index 71c457c7..00000000 --- a/src/com/stuypulse/stuylib/streams/numbers/filters/Integral.java +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.numbers.filters; - -import com.stuypulse.stuylib.util.StopWatch; - -/** - * This class takes an IStream and gives you the integral with respect to time. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class Integral implements IFilter { - - private final StopWatch mTimer; - private double mTotal; - - public Integral() { - mTimer = new StopWatch(); - mTotal = 0.0; - } - - public double get(double next) { - return mTotal += next * mTimer.reset(); - } -} diff --git a/src/com/stuypulse/stuylib/streams/numbers/filters/LowPassFilter.java b/src/com/stuypulse/stuylib/streams/numbers/filters/LowPassFilter.java index b3c0809d..9434de4b 100644 --- a/src/com/stuypulse/stuylib/streams/numbers/filters/LowPassFilter.java +++ b/src/com/stuypulse/stuylib/streams/numbers/filters/LowPassFilter.java @@ -4,7 +4,6 @@ package com.stuypulse.stuylib.streams.numbers.filters; -import com.stuypulse.stuylib.math.SLMath; import com.stuypulse.stuylib.util.StopWatch; /** @@ -38,10 +37,10 @@ public double get(double next) { } // Get a constant, which is determined based on dt and the mRC constant - double a = Math.exp(-mTimer.reset() / mRC.doubleValue()); + double a = 1.0 - Math.exp(-mTimer.reset() / mRC.doubleValue()); // Based on the value of a (which is determined by dt), the next value // could either change a lot, or not by much. (smaller dt = smaller change) - return mLastValue = SLMath.lerp(next, mLastValue, a); + return mLastValue += a * (next - mLastValue); } } diff --git a/src/com/stuypulse/stuylib/streams/numbers/filters/MedianFilter.java b/src/com/stuypulse/stuylib/streams/numbers/filters/MedianFilter.java deleted file mode 100644 index cc0eb93c..00000000 --- a/src/com/stuypulse/stuylib/streams/numbers/filters/MedianFilter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.numbers.filters; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -/** - * A median filter implementation using an ordered window and a value queue. - * - * @author Myles Pasetsky (selym3) - */ -public class MedianFilter implements IFilter { - - /** The size of the input window to get the median of. */ - private final int mSize; - - /** This queue stores values in the order they are inputted. */ - private Queue mBuffer; - - /** - * This list is acts as an ordered window. All operations to this list maintain its ascending - * order. - */ - private List mOrdered; - - /** - * Creates a median filter with a fixed size window. - * - * @param size window size - */ - public MedianFilter(int size) { - if (size < 1) - throw new IllegalArgumentException( - "Window size for MedianFilter must be greater than 0"); - - mSize = size; - - mBuffer = new LinkedList<>(); - mOrdered = new ArrayList<>(); - } - - /** - * Uses the binary search algorithm to find the index to insert next so that the ordered window - * stays ordered. - * - * @param next the new input - * @return the index to insert at - */ - private int getSortedIndex(double next) { - int idx = Collections.binarySearch(mOrdered, next); - - if (idx < 0) idx = -1 * (idx + 1); - - return idx; - } - - @Override - public double get(double next) { - // maintain the sorted list - int idx = getSortedIndex(next); - mOrdered.add(idx, next); - - int orderedSize = mOrdered.size(); - - // if the ordered list is greater than the window size - // remove the first element in the buffer from the window - if (orderedSize > mSize) { - mOrdered.remove(mBuffer.remove()); - --orderedSize; - } - - // push the value to the back of the buffer - // because mSize > 0, there will always be - // a value in the buffer ready to remove - mBuffer.add(next); - - // get the median from the ordered window - double mid = mOrdered.get(orderedSize / 2); - if ((orderedSize & 1) == 1) return mid; - else return (mOrdered.get(orderedSize / 2 - 1) + mid) / 2.0; - } -} diff --git a/src/com/stuypulse/stuylib/streams/numbers/filters/MovingAverage.java b/src/com/stuypulse/stuylib/streams/numbers/filters/MovingAverage.java deleted file mode 100644 index 35ff10ea..00000000 --- a/src/com/stuypulse/stuylib/streams/numbers/filters/MovingAverage.java +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.numbers.filters; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * An implementation of an Simple Moving Average - * - *

This is not time dependant, so the values will change if you change the rate that you call - * this filter, the filter will not adapt for that. - * - *

This implementation is O(1) unlike many other implementations of this algorithm. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class MovingAverage implements IFilter { - - private int mSize; - private double mTotal; - private Queue mValues; - - /** - * Make Simple Moving Average with Max Array Size - * - * @param size size of moving average - */ - public MovingAverage(int size) { - if (size <= 0) { - throw new IllegalArgumentException("size must be > 0"); - } - - mSize = size; - mValues = new LinkedList<>(); - mTotal = 0.0; - - for (int i = 0; i < mSize; ++i) { - mValues.add(0.0); - } - } - - public double get(double next) { - // Add new value - mValues.add(next); - mTotal += next; - - // Remove old values - while (mSize < mValues.size()) mTotal -= mValues.remove(); - - // Return average - return mTotal / mValues.size(); - } -} diff --git a/src/com/stuypulse/stuylib/streams/numbers/filters/WeightedMovingAverage.java b/src/com/stuypulse/stuylib/streams/numbers/filters/WeightedMovingAverage.java deleted file mode 100644 index ba085bcf..00000000 --- a/src/com/stuypulse/stuylib/streams/numbers/filters/WeightedMovingAverage.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.numbers.filters; - -/** - * Implementation of Weighted Moving Average. In a Weighted moving average, each value in the - * average buffer is weighted linearly based on their position in the buffer. The most recent item - * is weighted the most, and the last item is weighted the least. - * - *

This implementation is very fast, however, it is also very hard to explain. It does however - * correctly calculate a weighted moving average. - * - *

This implementation is O(1) unlike many other implementations of this algorithm. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class WeightedMovingAverage implements IFilter { - - private int mSize; - private double mTotal; - private double mLastAverage; - private MovingAverage mAverage; - - /** @param size size of weighted moving average */ - public WeightedMovingAverage(int size) { - if (size <= 0) { - throw new IllegalArgumentException("size must be greater than 0!"); - } - - mSize = size; - mAverage = new MovingAverage(size); - mLastAverage = 0.0; - mTotal = 0.0; - } - - public double get(double next) { - mTotal -= mLastAverage; - mLastAverage = mAverage.get(next); - return (mTotal += next) / ((mSize + 1) * 0.5); - } -} diff --git a/src/com/stuypulse/stuylib/streams/readme.md b/src/com/stuypulse/stuylib/streams/readme.md index caab1eec..318e5ce8 100644 --- a/src/com/stuypulse/stuylib/streams/readme.md +++ b/src/com/stuypulse/stuylib/streams/readme.md @@ -1,4 +1,4 @@ -# StuyLib Streams Library +# StuyLib Streams Library ## What is a Stream @@ -23,7 +23,7 @@ An [IStream](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/st ### [Filtered IStream](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/FilteredIStream.java) -A [Filtered ISteam](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/FilteredIStream.java) applies a [Filter](https://github.com/StuyPulse/StuyLib/tree/main/src/com/stuypulse/stuylib/streams/filters) to a stream, and returns that value instead. +A [Filtered ISteam](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/FilteredIStream.java) applies a [Filter](https://github.com/StuyPulse/StuyLib/tree/main/src/com/stuypulse/stuylib/streams/filters) to a stream, and returns that value instead. Continuing from the example above, we could do: @@ -37,7 +37,7 @@ System.out.println(filtered_speed.get()); // Prints the filtered value of the st CSVIStream has two child classes in it, `CSVIStream.Writer` and `CSVIStream.Reader`. -`CSVIStream.Writer` is used to save the values of a stream as you read it, and can be used as so. +`CSVIStream.Writer` is used to save the values of a stream as you read it, and can be used as so. ```java IStream recorded_speed = new CSVIStream.Writer("./speeds.csv", speed); diff --git a/src/com/stuypulse/stuylib/streams/vectors/VFuser.java b/src/com/stuypulse/stuylib/streams/vectors/VFuser.java deleted file mode 100644 index ae4a8196..00000000 --- a/src/com/stuypulse/stuylib/streams/vectors/VFuser.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.vectors; - -import com.stuypulse.stuylib.math.Vector2D; -import com.stuypulse.stuylib.streams.vectors.filters.VFilter; -import com.stuypulse.stuylib.streams.vectors.filters.VHighPassFilter; -import com.stuypulse.stuylib.streams.vectors.filters.VLowPassFilter; - -/** - * A class that combines two VStreams, usually in order to combine some slow data source with a - * faster one. The Base Measurement should generally drift less while the Fast Measurement should - * have less delay. The Fast measurement will go through a high pass filter so it is less important - * if that one drifts compared to the Base Measurement. - * - *

Example Usage: BaseMeasurement = Limelight, FastMeasurement = Encoders - * - * @author Myles Pasetsky - */ -public class VFuser implements VStream { - - private final Number mFilterRC; - - private final VStream mBase; - private final VStream mFast; - - private VFilter mBaseFilter; - private VFilter mFastFilter; - - private Vector2D mFastOffset; - - /** - * Create an VFuser with an RC, Base/Fast Measurement stream - * - * @param rc RC value for the lowpass / highpass filters - * @param baseMeasurement a stream that returns the slow, but accurate measurement values - * @param fastMeasurement a stream that returns faster, less accurate measurement values - */ - public VFuser(Number rc, VStream baseMeasurement, VStream fastMeasurement) { - mBase = baseMeasurement; - mFast = fastMeasurement; - - mFilterRC = rc; - - reset(); - } - - /** Resets the VFuser so that it can ignore any previous data / reset its initial read */ - public void reset() { - mBaseFilter = new VLowPassFilter(mFilterRC); - mFastFilter = new VHighPassFilter(mFilterRC); - - mFastOffset = mBase.get().sub(mFast.get()); - } - - private Vector2D getBase() { - return mBaseFilter.get(mBase.get()); - } - - private Vector2D getFast() { - return mFastFilter.get(mFast.get().add(mFastOffset)); - } - - /** Get the result of merging the two datastreams together */ - public Vector2D get() { - return getBase().add(getFast()); - } -} diff --git a/src/com/stuypulse/stuylib/streams/vectors/filters/VIntegral.java b/src/com/stuypulse/stuylib/streams/vectors/filters/VIntegral.java deleted file mode 100644 index 6cad277c..00000000 --- a/src/com/stuypulse/stuylib/streams/vectors/filters/VIntegral.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.vectors.filters; - -import com.stuypulse.stuylib.streams.numbers.filters.Integral; - -/** - * A filter that integrates a VStream with respect to time. - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class VIntegral extends XYFilter { - - public VIntegral() { - super(new Integral(), new Integral()); - } -} diff --git a/src/com/stuypulse/stuylib/streams/vectors/filters/VMovingAverage.java b/src/com/stuypulse/stuylib/streams/vectors/filters/VMovingAverage.java deleted file mode 100644 index bcf99155..00000000 --- a/src/com/stuypulse/stuylib/streams/vectors/filters/VMovingAverage.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.vectors.filters; - -import com.stuypulse.stuylib.streams.numbers.filters.MovingAverage; - -/** - * A filter that takes a moving average of a VStream - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class VMovingAverage extends XYFilter { - - public VMovingAverage(int size) { - super(new MovingAverage(size), new MovingAverage(size)); - } -} diff --git a/src/com/stuypulse/stuylib/streams/vectors/filters/VWeightedMovingAverage.java b/src/com/stuypulse/stuylib/streams/vectors/filters/VWeightedMovingAverage.java deleted file mode 100644 index b0c362e0..00000000 --- a/src/com/stuypulse/stuylib/streams/vectors/filters/VWeightedMovingAverage.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.streams.vectors.filters; - -import com.stuypulse.stuylib.streams.numbers.filters.WeightedMovingAverage; - -/** - * A filter that takes a weighted moving average of a VStream - * - * @author Sam (sam.belliveau@gmail.com) - */ -public class VWeightedMovingAverage extends XYFilter { - - public VWeightedMovingAverage(int size) { - super(new WeightedMovingAverage(size), new WeightedMovingAverage(size)); - } -} diff --git a/src/com/stuypulse/stuylib/util/HashBuilder.java b/src/com/stuypulse/stuylib/util/HashBuilder.java deleted file mode 100644 index fd91d8b6..00000000 --- a/src/com/stuypulse/stuylib/util/HashBuilder.java +++ /dev/null @@ -1,284 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util; - -/** - * A class used to generate HashCodes by combining multiple different objects / types. The combining - * function is taken from boost, as it is a great hash combiner - * - *

It also has static methods available if creating a new class is undesirable. - * - * @author Sam B. (sam.belliveau@gmail.com) - */ -public final class HashBuilder { - - /*******************************************/ - /*** Static HashBuilder Helper Functions ***/ - /*******************************************/ - - /** Default Value the internal hashpool will have if no value is given */ - public static final int DEFAULT_INITIALER = 0x9e3779b9; - - /** Prime Numbers used in combination process */ - private static final int PRIME_C1 = 0xcc9e2d51; - - private static final int PRIME_C2 = 0x1b873593; - - /** - * Implementation of Hash Combine from the Boost Library - * - * @see Boost - * Implementation - * @param a the first of the two values to combine into a hash - * @param b the second of the two values to combine into a hash - * @return the result of the hash combining function - */ - public static int combineHash(int a, int b) { - b *= PRIME_C1; - b = Integer.rotateLeft(b, 15); - b *= PRIME_C2; - - a ^= b; - a = Integer.rotateLeft(a, 13); - a = a * 5 + 0xe6546b64; - - return a; - } - - /** - * Implementation of Hash Combine from the Boost Library - * - *

This will not return the same value as {@link #combineHash(Object, int)} if you swap the - * object and integers. This function is dependent on the order - * - * @see #combineHash(int,int) - * @param a the first of the two values to combine into a hash - * @param b the second of the two values to combine into a hash - * @return the result of the hash combining function - */ - public static int combineHash(int a, Object b) { - return combineHash(a, b.hashCode()); - } - - /** - * Implementation of Hash Combine from the Boost Library - * - *

This will not return the same value as {@link #combineHash(int, Object)} if you swap the - * object and integers. This function is dependent on the order - * - * @see #combineHash(int,int) - * @param a the first of the two values to combine into a hash - * @param b the second of the two values to combine into a hash - * @return the result of the hash combining function - */ - public static int combineHash(Object a, int b) { - return combineHash(a.hashCode(), b); - } - - /** - * Implementation of Hash Combine from the Boost Library - * - * @see #combineHash(int,int) - * @param a the first of the two values to combine into a hash - * @param b the second of the two values to combine into a hash - * @return the result of the hash combining function - */ - public static int combineHash(Object a, Object b) { - return combineHash(a.hashCode(), b.hashCode()); - } - - /****************************/ - /*** Class Implementation ***/ - /****************************/ - - // Internal Pool to store hash - private int mHashPool; - - /** - * Create a HashBuilder with a custom initial state, usually unnecessary - * - * @param initial initial starting value for the HashBuilder - */ - public HashBuilder(int initial) { - this.mHashPool = initial; - } - - /** Create a HashBuilder with the default initialized state */ - public HashBuilder() { - this(DEFAULT_INITIALER); - } - - /*** Getting the HashCode Back ***/ - - /** @return the digested hashCode of everything that was added */ - @Override - public int hashCode() { - return mHashPool; - } - - /** @return the digested hashCode of everything that was added */ - public int toHashCode() { - return this.hashCode(); - } - - /*** Appending single variables ***/ - - /** - * @param value integer to append to hashCode - * @return this - */ - public HashBuilder append(int value) { - mHashPool = combineHash(mHashPool, value); - return this; - } - - /** - * @param value boolean to append to hashCode - * @return this - */ - public HashBuilder append(boolean value) { - return append(Boolean.hashCode(value)); - } - - /** - * @param value byte to append to hashCode - * @return this - */ - public HashBuilder append(byte value) { - return append(Byte.hashCode(value)); - } - - /** - * @param value char to append to hashCode - * @return this - */ - public HashBuilder append(char value) { - return append(Character.hashCode(value)); - } - - /** - * @param value short to append to hashCode - * @return this - */ - public HashBuilder append(short value) { - return append(Short.hashCode(value)); - } - - /** - * @param value long to append to hashCode - * @return this - */ - public HashBuilder append(long value) { - return append(Long.hashCode(value)); - } - - /** - * @param value float to append to hashCode - * @return this - */ - public HashBuilder append(float value) { - return append(Float.hashCode(value)); - } - - /** - * @param value double to append to hashCode - * @return this - */ - public HashBuilder append(double value) { - return append(Double.hashCode(value)); - } - - /** - * @param value object to append to hashCode - * @return this - */ - public HashBuilder append(Object value) { - return append(value.hashCode()); - } - - /*** Appending multiple variables ***/ - - /** - * @param values integers to append to hashCode - * @return this - */ - public HashBuilder append(int... values) { - for (int v : values) append(v); - return this; - } - - /** - * @param values booleans to append to hashCode - * @return this - */ - public HashBuilder append(boolean... values) { - for (boolean v : values) append(v); - return this; - } - - /** - * @param values bytes to append to hashCode - * @return this - */ - public HashBuilder append(byte... values) { - for (byte v : values) append(v); - return this; - } - - /** - * @param values chars to append to hashCode - * @return this - */ - public HashBuilder append(char... values) { - for (char v : values) append(v); - return this; - } - - /** - * @param values shorts to append to hashCode - * @return this - */ - public HashBuilder append(short... values) { - for (short v : values) append(v); - return this; - } - - /** - * @param values longs to append to hashCode - * @return this - */ - public HashBuilder append(long... values) { - for (long v : values) append(v); - return this; - } - - /** - * @param values floats to append to hashCode - * @return this - */ - public HashBuilder append(float... values) { - for (float v : values) append(v); - return this; - } - - /** - * @param values doubles to append to hashCode - * @return this - */ - public HashBuilder append(double... values) { - for (double v : values) append(v); - return this; - } - - /** - * @param values objects to append to hashCode - * @return this - */ - public HashBuilder append(Object... values) { - for (Object v : values) append(v); - return this; - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/AngleSeries.java b/src/com/stuypulse/stuylib/util/plot/AngleSeries.java deleted file mode 100644 index 999ed103..00000000 --- a/src/com/stuypulse/stuylib/util/plot/AngleSeries.java +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.math.Vector2D; -import com.stuypulse.stuylib.streams.angles.AStream; - -import java.util.LinkedList; -import java.util.List; - -/** - * An AngleSeries is used to plot a stream of points (AStream) that changes over time. - * - * @author Benjamin Goldfisher (ben@goldfisher.com) - */ -public class AngleSeries extends Series { - - /** Contains the (x, y) data points */ - private List xValues; - - private List yValues; - - /** Outputs values to be plotted */ - private final AStream stream; - - /** Magnitude of points to be plotted */ - private final double magnitude; - - /** - * Creates an AngleSeries and specifies that it is polling. - * - * @param config series config - * @param stream determines the points to be plotted - * @param magnitude magnitude of points - */ - public AngleSeries(Config config, AStream stream, double magnitude) { - super(config, true); - - xValues = new LinkedList<>(); - yValues = new LinkedList<>(); - - this.stream = stream; - this.magnitude = magnitude; - } - - /** @return copied list of x values */ - @Override - protected List getSafeXValues() { - return new LinkedList<>(xValues); - } - - /** @return copied list of y values */ - @Override - protected List getSafeYValues() { - return new LinkedList<>(yValues); - } - - /** Converts next angle from stream and adds to x and y values */ - @Override - protected void poll() { - Vector2D next = stream.get().getVector().mul(magnitude); - - xValues.add(next.x); - yValues.add(next.y); - } - - /** Removes oldest point from x and y values */ - @Override - protected void pop() { - xValues.remove(0); - yValues.remove(0); - } - - /** @return number of stored points */ - @Override - public int size() { - return yValues.size(); - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/FuncSeries.java b/src/com/stuypulse/stuylib/util/plot/FuncSeries.java deleted file mode 100644 index 0ca6b8bc..00000000 --- a/src/com/stuypulse/stuylib/util/plot/FuncSeries.java +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.streams.numbers.filters.IFilter; - -import java.util.ArrayList; -import java.util.List; - -/** - * A FuncSeries plots a function (IFilter) over a given domain. - * - *

A FuncSeries data is precomputed, so its x and y values are non-changing. This means that the - * series does not get polled and does not implement pop() or poll(). - * - * @author Ben Goldfisher - */ -public class FuncSeries extends Series { - - /** Domain describes the x-values that the series will be graphed over */ - public static class Domain { - - /** min and max x-values that will be graphed */ - public final double min, max; - - /** - * Creates a Domain - * - * @param min smallest x-value that will be graphed - * @param max largest x-value that will be graphed - */ - public Domain(double min, double max) { - this.min = min; - this.max = max; - } - } - - /** Contains the precomputed (x, y) data values */ - private List xValues; - - private List yValues; - - /** - * Creates a FuncSeries and specifies that it is not polling. - * - * @param config series config - * @param domain range of x-values inputted to the function - * @param func a function with one input and output to be graphed - */ - public FuncSeries(Config config, Domain domain, IFilter func) { - super(config, false); - - xValues = new ArrayList(); - yValues = new ArrayList(); - - // Fill the series capacity with evenly spaced points in the given domain - for (int i = 0; i < config.getCapacity(); i++) { - double x = (i * (domain.max - domain.min)) / config.getCapacity() + domain.min; - - xValues.add(x); - yValues.add(func.get(x)); - } - } - - /** @return max number of stored (x, y) values */ - @Override - public int size() { - return getConfig().getCapacity(); - } - - /** - * Returns reference to x values, which is safe because they are precompted and non-changing - * - * @return reference to x values - */ - @Override - protected List getSafeXValues() { - return xValues; - } - - /** - * Returns reference to y values, which is safe because they are precompted and non-changing - * - * @return reference to y values - */ - @Override - protected List getSafeYValues() { - return yValues; - } - - /** No-op because series is non-polling */ - @Override - protected void pop() {} - - /** No-op because series is non-polling */ - @Override - protected void poll() {} -} diff --git a/src/com/stuypulse/stuylib/util/plot/KeyTracker.java b/src/com/stuypulse/stuylib/util/plot/KeyTracker.java deleted file mode 100644 index 018c6a43..00000000 --- a/src/com/stuypulse/stuylib/util/plot/KeyTracker.java +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.util.HashSet; -import java.util.Set; - -/** - * Key tracker for swing components with key bindings. - * - * @author Myles Pasetsky (selym3) - */ -public final class KeyTracker extends KeyAdapter { - - /** Set of key codes that will contain keys currently pressed. */ - private Set values; - - /** Initialize set of key presses and key bindings. */ - public KeyTracker() { - values = new HashSet(); - } - - /** - * @param e Key Event from KeyPress - * @return sanitized key name - */ - private static String getKeyName(KeyEvent e) { - return sanatizeKeyName(KeyEvent.getKeyText(e.getKeyCode())); - } - - /** - * @param name input key name - * @return the sanatized key name - */ - private static String sanatizeKeyName(String name) { - return name.strip().toUpperCase(); - } - - /** - * Get the value of a key press. - * - * @param key name of the key to check - * @return if a key is pressed - */ - public boolean hasKey(String key) { - return values.contains(sanatizeKeyName(key)); - } - - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0); - - values.add(getKeyName(e)); - } - - @Override - public void keyReleased(KeyEvent e) { - values.remove(getKeyName(e)); - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/MouseTracker.java b/src/com/stuypulse/stuylib/util/plot/MouseTracker.java deleted file mode 100644 index 5bbb4c86..00000000 --- a/src/com/stuypulse/stuylib/util/plot/MouseTracker.java +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.math.Vector2D; - -import java.awt.*; - -/** - * Tracks the mouse on a container without the need for a listener. - * - * @author Sam Belliveau (@Sam-Belliveau) - * @author Myles Pasetsky (@selym3) - */ -public class MouseTracker { - - /** Panel for size reference */ - private final Container panel; - - /** - * Initialize panel and x and y - * - * @param panel Panel to track on - */ - public MouseTracker(Container panel) { - this.panel = panel; - } - - /** - * Get mouse x - * - * @return mouse x position as a percentage of the screen width - */ - public double getX() { - double x = MouseInfo.getPointerInfo().getLocation().x; - x -= panel.getLocationOnScreen().x; - x /= panel.getWidth(); - return x; - } - - /** - * Get mouse y - * - * @return mouse y position as a percentage of the screen height - */ - public double getY() { - double y = MouseInfo.getPointerInfo().getLocation().y; - y -= panel.getLocationOnScreen().y; - y /= panel.getHeight(); - return 1.0 - y; - } - - /** @return position of mouse */ - public Vector2D getPosition() { - return new Vector2D(getX(), getY()); - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/Playground.java b/src/com/stuypulse/stuylib/util/plot/Playground.java deleted file mode 100644 index da76d8d7..00000000 --- a/src/com/stuypulse/stuylib/util/plot/Playground.java +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.math.Vector2D; -import com.stuypulse.stuylib.math.interpolation.*; -import com.stuypulse.stuylib.streams.angles.AFuser; -import com.stuypulse.stuylib.streams.angles.AStream; -import com.stuypulse.stuylib.streams.angles.filters.AHighPassFilter; -import com.stuypulse.stuylib.streams.angles.filters.ALowPassFilter; -import com.stuypulse.stuylib.streams.angles.filters.AMotionProfile; -import com.stuypulse.stuylib.streams.angles.filters.ARateLimit; -import com.stuypulse.stuylib.streams.booleans.*; -import com.stuypulse.stuylib.streams.booleans.filters.*; -import com.stuypulse.stuylib.streams.numbers.*; -import com.stuypulse.stuylib.streams.numbers.IStream; -import com.stuypulse.stuylib.streams.numbers.filters.*; -import com.stuypulse.stuylib.streams.vectors.*; -import com.stuypulse.stuylib.streams.vectors.filters.*; -import com.stuypulse.stuylib.util.plot.FuncSeries.Domain; -import com.stuypulse.stuylib.util.plot.Series.Config; -import com.stuypulse.stuylib.util.plot.TimeSeries.TimeSpan; - -public class Playground { - - public interface Constants { - int CAPACITY = 10; - - String TITLE = "StuyLib Plotting Library"; - String X_AXIS = "x-axis"; - String Y_AXIS = "y-axis"; - - int WIDTH = 800; - int HEIGHT = 600; - - double MIN_X = -1.0; - double MAX_X = 1.0; - - double MIN_Y = -1.0; - double MAX_Y = 1.0; - - Settings SETTINGS = - new Settings() - .setSize(WIDTH, HEIGHT) - .setAxes(TITLE, X_AXIS, Y_AXIS) - .setXRange(MIN_X, MAX_X) - .setYRange(MIN_Y, MAX_Y); - - public static Series make(String id, IFilter function) { - return new FuncSeries(new Config(id, CAPACITY), new Domain(MIN_X, MAX_X), function); - } - - public static Series make(String id, IStream series) { - return new TimeSeries(new Config(id, CAPACITY), new TimeSpan(MIN_X, MAX_X), series); - } - - public static Series make(String id, VStream series) { - return new XYSeries(new Config(id, CAPACITY), series); - } - - public static Series make(String id, AStream series, double magnitude) { - return new AngleSeries(new Config(id, CAPACITY), series, magnitude); - } - - public static Series make(String id, BStream series) { - return make(id, IStream.create(series)); - } - } - - public static void main(String[] args) throws InterruptedException { - Plot plot = new Plot(Constants.SETTINGS); - - VStream m = VStream.create(() -> plot.getMouse().sub(new Vector2D(0.5, 0.5)).mul(2)); - - AStream angle_mouse = AStream.create(() -> m.get().getAngle()); - AStream jerk_angle = angle_mouse.filtered(new AMotionProfile(-1, 4)); - AStream rate_angle = angle_mouse.filtered(new ARateLimit(1)); - AStream lpf_angle = angle_mouse.filtered(new ALowPassFilter(0.5)); - AStream hpf_angle = angle_mouse.filtered(new AHighPassFilter(0.5)); - AStream delay_angle = - angle_mouse - .filtered(new ALowPassFilter(0.25)) - .add( - AStream.create( - IStream.create(() -> Math.random() - 0.5) - .filtered(new LowPassFilter(1)))); - AStream afuser_angle = new AFuser(1, delay_angle, angle_mouse); - - VStream mouse = VStream.create(() -> angle_mouse.get().getVector().mul(1.0)); - VStream jerk = VStream.create(() -> jerk_angle.get().getVector().mul(0.95)); - VStream rate = VStream.create(() -> rate_angle.get().getVector().mul(0.9)); - VStream lpf = VStream.create(() -> lpf_angle.get().getVector().mul(0.85)); - VStream hpf = VStream.create(() -> hpf_angle.get().getVector().mul(0.8)); - VStream delay = VStream.create(() -> delay_angle.get().getVector().mul(1.1)); - VStream afuser = VStream.create(() -> afuser_angle.get().getVector().mul(1.05)); - - plot.addSeries(Constants.make("Angle", mouse)) - .addSeries(Constants.make("Jerk", jerk)) - .addSeries(Constants.make("Rate", rate)) - .addSeries(Constants.make("LPF", lpf)) - .addSeries(Constants.make("HPF", hpf)) - .addSeries(Constants.make("afuser", afuser)) - .addSeries(Constants.make("delayed", delay)) - .addSeries(Constants.make("mouse", m)); - // - // .addSeries(Constants.make("y=x", x -> x)) - // .addSeries( - // Constants.make( - // "interp", - // new LinearInterpolator( - // new Vector2D(0.0, 0.43), - // new Vector2D(0.2, 0.56), - // new Vector2D(0.4, 0.72), - // new Vector2D(0.6, 0.81), - // new Vector2D(0.8, 0.02), - // new Vector2D(1.0, 0.11)))) - // .addSeries(Constants.make("mouse y", IStream.create(plot::getMouseY))) - // .addSeries( - // Constants.make( - // "lpf", - // IStream.create(plot::getMouseY).filtered(new LowPassFilter(0.2)))) - // .addSeries( - // Constants.make("mouse bool", BStream.create(() -> plot.getMouseY() > 0.5))) - // .addSeries( - // Constants.make( - // "debounced", - // BStream.create(() -> plot.getMouseY() > 0.5) - // .filtered(new BDebounce.Both(1.0)))) - // .addSeries(Constants.make("mouse position", VStream.create(plot::getMouse))) - // .addSeries( - // Constants.make( - // "jerk limit", - // VStream.create(plot::getMouse) - // .filtered(new VJerkLimit(10.0, 5.0)))); - - while (plot.isRunning()) { - plot.update(); - Thread.sleep(10); - } - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/Plot.java b/src/com/stuypulse/stuylib/util/plot/Plot.java deleted file mode 100644 index 1b12e7ba..00000000 --- a/src/com/stuypulse/stuylib/util/plot/Plot.java +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.math.Vector2D; - -import java.awt.Dimension; -import java.awt.Toolkit; -import java.util.ArrayList; -import java.util.List; -import javax.swing.JFrame; -import org.knowm.xchart.XChartPanel; -import org.knowm.xchart.XYChart; -import org.knowm.xchart.XYChartBuilder; - -/** - * A plot contains and manages the window to which any data is drawn. - * - *

It stores the Series that it is going draw. It also has methods that read the mouse's - * position, which can be used as an input stream for a series. - * - * @author Myles Pasetsky (myles.pasetsky@gmail.com) - */ -public class Plot { - - /** A collection of Series to be graphed */ - private List plots; - - /** The window that is created */ - private JFrame frame; - - /** A reference to the XChart library */ - private XYChart instance; - - private XChartPanel panel; - - /** A utility for finding mouse positions */ - private MouseTracker mouse; - - /** A boolean to ensure the plot is updated at least once */ - private boolean runOnce; - - /** - * Creates a configured plot - * - * @param settings plot and window settings - */ - public Plot(Settings settings) { - // Setup series - plots = new ArrayList<>(); - - // Setup window - frame = new JFrame(settings.getTitle()); - - frame.getContentPane() - .setPreferredSize(new Dimension(settings.getWidth(), settings.getHeight())); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - // Create XYChart using settings - instance = - new XYChartBuilder() - .title(settings.getTitle()) - .xAxisTitle(settings.getXAxis()) - .yAxisTitle(settings.getYAxis()) - .build(); - - instance.getStyler().setYAxisMin(settings.getYMin()); - instance.getStyler().setYAxisMax(settings.getYMax()); - - instance.getStyler().setXAxisMin(settings.getXMin()); - instance.getStyler().setXAxisMax(settings.getXMax()); - - panel = new XChartPanel(instance); - panel.setName(settings.getTitle()); - - mouse = new MouseTracker(panel); - - frame.getContentPane().add(panel); - frame.setResizable(false); - - frame.pack(); - - frame.setLocationRelativeTo(null); - frame.setVisible(true); - - runOnce = true; - } - - /** Creates a plot with default settings */ - public Plot() { - this(new Settings()); - } - - /** @return mouse position */ - public Vector2D getMouse() { - return mouse.getPosition(); - } - - /** @return mouse y position */ - public double getMouseY() { - return mouse.getY(); - } - - /** @return mouse x position */ - public double getMouseX() { - return mouse.getX(); - } - - /** - * Adds series to be graphed - * - * @param series series to add - * @return reference to self - */ - public Plot addSeries(Series... series) { - for (Series e : series) plots.add(e); - return this; - } - - /** allows the series to update the XYChart */ - public void updateSeries() { - for (Series plot : plots) { - plot.update(instance); - } - } - - /** repaints the screen */ - public void display() { - Toolkit.getDefaultToolkit().sync(); - panel.revalidate(); - panel.repaint(); - } - - public void update() { - updateSeries(); - display(); - } - - /** - * Checks if any series are polling to see if the plot should still update. - * - * @return if the plot should still run - */ - public boolean isRunning() { - if (runOnce) { - runOnce = false; - return true; - } - - for (Series e : plots) { - if (e.isPolling()) return true; - } - return false; - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/Series.java b/src/com/stuypulse/stuylib/util/plot/Series.java deleted file mode 100644 index ed142254..00000000 --- a/src/com/stuypulse/stuylib/util/plot/Series.java +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import java.awt.BasicStroke; -import java.util.List; -import org.knowm.xchart.XYChart; -import org.knowm.xchart.XYSeries.XYSeriesRenderStyle; -import org.knowm.xchart.style.markers.SeriesMarkers; - -/** - * A series handles (x, y) data that will be graphed. It supports getting safe copies of this data, - * as well optionally supporting pushing and popping this data. - * - *

Using these operations, a series can update its data points and add itself to an XYChart. - * - *

A series must be created with a config, which has the label of the series (which appears in - * the legend) and its maximum number of entries. - * - *

A series must also specifiy whether or not it is polling. If a series is "polling", it means - * that its values will change when the poll operation is performed. This is useful as the plot - * doesn't have to redraw if its series aren't polling because they will never change. - * - * @author Myles Pasetsky (myles.pasetsky@gmail.com) - */ -public abstract class Series { - - /** Config describes the baseline settings for a series that need to be configured. */ - public static class Config { - - /** label of a series that appears on the legend */ - private String label; - - /** max number of entries before old ones get removed */ - private int capacity; - - /** - * Creates a config - * - * @param label series label, which appears on legend - * @param capacity capacity, which sets max number of entries for a series - */ - public Config(String label, int capacity) { - this.label = label; - this.capacity = capacity; - } - - /** @return label */ - public String getLabel() { - return label; - } - - /** @return capacity */ - public int getCapacity() { - return capacity; - } - } - - /** the config for this series */ - private final Config config; - - /** whether or not this series polls */ - private final boolean polling; - - /** - * Creates a series given a config and if it's polling - * - * @param config series config - * @param polling whether or not this series polls - */ - public Series(Config config, boolean polling) { - this.config = config; - this.polling = polling; - } - - /** @return series config */ - public Config getConfig() { - return config; - } - - /** @return the number of data points the series has */ - public abstract int size(); - - /** @return a "safe" copy of the x-data that can be read by XYChart's threads */ - protected abstract List getSafeXValues(); - - /** @return a "safe" copy of the y-data that can be read by XYChart's threads */ - protected abstract List getSafeYValues(); - - /** removes oldest data point (can be a no-op depending on implementation) */ - protected abstract void pop(); - - /** pushes new data point (can be a no-op depending on implementation) */ - protected abstract void poll(); - - /** @return if the series is polling */ - protected final boolean isPolling() { - return polling; - } - - /** - * Pushes new data point and removes data points if over capacity in the config - * - *

Depending on the implementation of a series, this may be a no-op - */ - private final void update() { - final int capacity = getConfig().getCapacity(); - poll(); - while (size() > capacity) { - pop(); - } - } - - /** - * Puts the 'safe' data into the chart instance under the label specified in the config. - * - * @param chart chart to put x, y data into - */ - protected final void update(XYChart chart) { - update(); - - String label = getConfig().getLabel(); - var x = getSafeXValues(); - var y = getSafeYValues(); - - if (chart.getSeriesMap().containsKey(label)) { - chart.updateXYSeries(label, x, y, null); - } else { - chart.addSeries(label, x, y); - chart.getSeriesMap() - .get(label) - .setXYSeriesRenderStyle(XYSeriesRenderStyle.Line) - .setMarker(SeriesMarkers.NONE) - .setLineStyle(new BasicStroke(2.5f)); - } - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/Settings.java b/src/com/stuypulse/stuylib/util/plot/Settings.java deleted file mode 100644 index 29587bf6..00000000 --- a/src/com/stuypulse/stuylib/util/plot/Settings.java +++ /dev/null @@ -1,280 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -/** - * Settings for a plot. - * - *

Supports changing labels, axis bounds, and window size. - * - * @author Myles Pasetsky (myles.pasetsky@gmail.com) - */ -public final class Settings { - - /** Convenience struct to represent axis labels */ - public static class Axes { - - /** all the labels stored */ - private String title, x, y; - - /** - * Create an axes object - * - * @param title title - * @param x x-axis label - * @param y y-axis label - */ - public Axes(String title, String x, String y) { - this.title = title; - this.x = x; - this.y = y; - } - } - - /** labels of the plot */ - private String title; - - private String xAxis; - private String yAxis; - - /** window size */ - private int width; - - private int height; - - /** x-axis bounds */ - private double xMin; - - private double xMax; - - /** y-axis bounds */ - private double yMin; - - private double yMax; - - /** Create a settings object with default values */ - public Settings() { - title = "Plot"; - xAxis = "x"; - yAxis = "y"; - - width = 640; - height = 480; - - xMin = 0.0; - xMax = 1.0; - - yMin = 0.0; - yMax = 1.0; - } - - /** @return title */ - public String getTitle() { - return title; - } - - /** @return x-axis label */ - public String getXAxis() { - return xAxis; - } - - /** @return y-axis label */ - public String getYAxis() { - return yAxis; - } - - /** @return width of window */ - public int getWidth() { - return width; - } - - /** @return height of window */ - public int getHeight() { - return height; - } - - /** @return lower bound of x-axis */ - public double getXMin() { - return xMin; - } - - /** @return upper bound of x-axis */ - public double getXMax() { - return xMax; - } - - /** @return lower bound of y-axis */ - public double getYMin() { - return yMin; - } - - /** @return upper bound of y-axis */ - public double getYMax() { - return yMax; - } - - /** - * Sets title of plot - * - * @param title title - * @return reference to self for chaining methods - */ - public Settings setTitle(String title) { - this.title = title; - return this; - } - - /** - * Sets x-axis label - * - * @param xAxis x-axis label - * @return reference to self for chaining methods - */ - public Settings setXAxis(String xAxis) { - this.xAxis = xAxis; - return this; - } - - /** - * Set y-axis label - * - * @param yAxis y-axis label - * @return reference to self for chaining methods - */ - public Settings setYAxis(String yAxis) { - this.yAxis = yAxis; - return this; - } - - /** - * Set all axis labels at once - * - * @param title title - * @param xAxis x-axis label - * @param yAxis y-axis label - * @return reference to self for chaining methods - */ - public Settings setAxes(String title, String xAxis, String yAxis) { - setTitle(title); - setXAxis(xAxis); - setYAxis(yAxis); - return this; - } - - /** - * Sets all the axis labels at once - * - * @param axes object containing axis labels - * @return reference to self for chaining methods - */ - public Settings setAxes(Axes axes) { - return setAxes(axes.title, axes.x, axes.y); - } - - /** - * Sets lower bound for x-axis - * - * @param xMin lower bound for x-axis - * @return reference to self for chaining methods - */ - public Settings setXMin(double xMin) { - this.xMin = xMin; - return this; - } - - /** - * Sets upper bound for x-axis - * - * @param xMax upper bound for x-axis - * @return reference to self for chaining methods - */ - public Settings setXMax(double xMax) { - this.xMax = xMax; - return this; - } - - /** - * Sets range of x-values on plot - * - * @param min x axis lower bound - * @param max x axis upper bound - * @return reference to self for chaining methods - */ - public Settings setXRange(double min, double max) { - setXMax(max); - setXMin(min); - return this; - } - - /** - * Sets lower bound for y-axis - * - * @param yMin lower bound for y-axis - * @return reference to self for chaining methods - */ - public Settings setYMin(double yMin) { - this.yMin = yMin; - return this; - } - - /** - * Sets upper bound for y-axis - * - * @param yMax upper bound for y-axis - * @return reference to self for chaining methods - */ - public Settings setYMax(double yMax) { - this.yMax = yMax; - return this; - } - - /** - * Sets range of y-values on plot - * - * @param min y axis lower bound - * @param max y axis upper bound - * @return reference to self for chaining methods - */ - public Settings setYRange(double min, double max) { - setYMax(max); - setYMin(min); - return this; - } - - /** - * Sets width of window - * - * @param width width of window - * @return reference to self for chaining methods - */ - public Settings setWidth(int width) { - this.width = width; - return this; - } - - /** - * Sets height of window - * - * @param height height of window - * @return reference to self for chaining methods - */ - public Settings setHeight(int height) { - this.height = height; - return this; - } - - /** - * Sets size of window - * - * @param width width of window - * @param height height of window - * @return reference to self for chaining methods - */ - public Settings setSize(int width, int height) { - setWidth(width); - setHeight(height); - return this; - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/TimeSeries.java b/src/com/stuypulse/stuylib/util/plot/TimeSeries.java deleted file mode 100644 index 95a39647..00000000 --- a/src/com/stuypulse/stuylib/util/plot/TimeSeries.java +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.streams.numbers.IStream; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * A TimeSeries is used to plot a stream of values (IStream) that changes over time. - * - *

A TimeSeries is created with a TimeSpan, which the stream is always assumed to be in. This - * allows the x-axis to be precomputed with evenly spaced points in the time span. - * - * @author Myles Pasetsky (myles.pasetsky@gmail.com) - */ -public class TimeSeries extends Series { - - /** The span of time that the series is within */ - public static class TimeSpan { - - /** bounds of time span */ - public final double min, max; - - /** - * Create a TimeSpan - * - * @param min minimum time - * @param max maximum time - */ - public TimeSpan(double min, double max) { - this.min = min; - this.max = max; - } - } - - /** precomputed x-values */ - private List xValues; - - /** y-values from stream */ - private List yValues; - - /** stream of values, source of data for this series */ - private final IStream stream; - - /** - * Creates a time series. - * - * @param config series config - * @param span time span - * @param stream input stream for getting y-data - */ - public TimeSeries(Config config, TimeSpan span, IStream stream) { - super(config, true); - - xValues = new ArrayList<>(); - yValues = new LinkedList<>(); - - final double delta = (span.max - span.min) / config.getCapacity(); - for (int i = 0; i < config.getCapacity(); ++i) { - xValues.add(span.min + i * delta); - yValues.add(0.0); - } - - this.stream = stream; - } - - /** - * Returns reference to x values, which is safe because they are precompted and non-changing - * - * @return reference to x values - */ - @Override - protected List getSafeXValues() { - return xValues; - } - - /** @return copy of y-values because the y-values changes from the stream */ - @Override - protected List getSafeYValues() { - return new LinkedList<>(yValues); - } - - /** adds a value from the stream to the y-values */ - @Override - protected void poll() { - yValues.add(stream.get()); - } - - /** removes the oldest y-value */ - @Override - protected void pop() { - yValues.remove(0); - } - - /** returns the number of y-values (because x-values never change) */ - @Override - public int size() { - return yValues.size(); - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/XYSeries.java b/src/com/stuypulse/stuylib/util/plot/XYSeries.java deleted file mode 100644 index b29683ae..00000000 --- a/src/com/stuypulse/stuylib/util/plot/XYSeries.java +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved. */ -/* This work is licensed under the terms of the MIT license */ -/* found in the root directory of this project. */ - -package com.stuypulse.stuylib.util.plot; - -import com.stuypulse.stuylib.math.Vector2D; -import com.stuypulse.stuylib.streams.vectors.VStream; - -import java.util.LinkedList; -import java.util.List; - -/** - * An XYSeries is used to plot a stream of points (VStream) that changes over time. - * - * @author Myles Pasetsky (myles.pasetsky@gmail.com) - */ -public class XYSeries extends Series { - - /** Contains the (x, y) data points */ - private List xValues; - - private List yValues; - - /** Outputs values to be plotted */ - private final VStream stream; - - /** - * Creates a XYSeries and specifies that it is polling. - * - * @param config series config - * @param stream determines the points to be plotted - */ - public XYSeries(Config config, VStream stream) { - super(config, true); - - xValues = new LinkedList<>(); - yValues = new LinkedList<>(); - - this.stream = stream; - } - - /** @return copied list of x values */ - @Override - protected List getSafeXValues() { - return new LinkedList<>(xValues); - } - - /** @return copied list of y values */ - @Override - protected List getSafeYValues() { - return new LinkedList<>(yValues); - } - - /** Adds next point from the stream to x and y values */ - @Override - protected void poll() { - Vector2D next = stream.get(); - xValues.add(next.x); - yValues.add(next.y); - } - - /** Removes oldest point from x and y values */ - @Override - protected void pop() { - xValues.remove(0); - yValues.remove(0); - } - - /** @return number of stored points */ - @Override - public int size() { - return yValues.size(); - } -} diff --git a/src/com/stuypulse/stuylib/util/plot/readme.md b/src/com/stuypulse/stuylib/util/plot/readme.md deleted file mode 100644 index af5cf6e5..00000000 --- a/src/com/stuypulse/stuylib/util/plot/readme.md +++ /dev/null @@ -1,156 +0,0 @@ -# StuyLib Plotting Library - -A simple library for plotting streams and filters. Wraps [Knowm's XChart library](https://knowm.org/open-source/xchart/). - -The library is based around a `Plot` that can have various types of `Series`. A plot handles displaying data, while a Series handles organizing data. - -## What is a Series? - -A series represents any kind of function or data to be graphed. There are three things that series must say about itself: its "configuration", whether or not it's "polling", and its (x,y) data. The main assumption made about a series is that the data should be represented by a line. - -There are actual no methods in a `Series` that the programmer has to call, but the way a `Series` works and the methods that make it work are covered below: - -### Config - -A `Series` is created with a `Config` class that stores the name and capacity of a series. - -The capacity is the max amount of points that can be plotted at the same time. The `.pop()` method enables this feature, as is called when the oldest point should be removed from a series when it's reached its capacity. If a series is non-changing, it can leave this blank. - -The name of the config is what will appear on the legend of the plot. - -### Polling - -A series can be "polled", during which it can update what data it is storing. - -This is important because many series change with time, like following the user's mouse or adding points from a stream. A non-changing series (e.g. all data points can be pre-calculated) disable polling by setting `Series.polling` to false through its constructor. - -One method in Series enable polling: `.poll()`. Here a series should add a value from wherever its reading data to itself. If a series is non-changing it can leave this blank. - -### Data - -The actual data for a series is accessed through `.getSafeXValues()` and `.getSafeYValues()` in x, y pairs. These methods should return a 'safe' (e.g. copied) list. XChart can modify the returned list at the same time as the series, which will cause a concurrent modification exception. However, a 'safe' version will avoid the exception entirely. - -Some series don't modify their internal data, so these series don't need to copy and can simply return a reference to their data. - -## Types of Series - -### [TimeSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/TimeSeries.java) - -A [TimeSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/TimeSeries.java) is used to plot a stream of values that changes over time. - -A `TimeSeries` uses an [IStream](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/IStream.java) to get new values. A `TimeSeries` can be used to test [IFilters](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/filters/IFilter.java) because an `IStream` can be filtered. Note, the `IStream` does not have access to time, it is simply a stream of data. If a function of time is needed, see `FuncSeries`. - -A `TimeSeries` is created with a `TimeSpan`, which determines the time range that the series will be graphed on. Using `TimeSpan` and `Config.capacity`, the x-axis is precomputed to put points evenly through the TimeSpan. - -`TimeSeries` can be used with [MouseTracker](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/MouseTracker.java), like shown below: - -```java -TimeSeries mouse = new TimeSeries( - new Config("mouse", 500), - new TimeSpan(0, 1), - IStream.create(plot::getMouseY)); - -TimeSeries lpf = new TimeSeries( - new Config("low pass filter", 500), - new TimeSpan(0, 1), - IStream.create(plot::getMouseY) - .filtered(new LowPassFilter(0.2))); -``` - -### [FuncSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/FuncSeries.java) - -A [FuncSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/FuncSeries.java) is used to plot a function on a given domain. - -[FuncSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/FuncSeries.java) uses an [IFilter](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/filters/IFilter.java) to represent a function. - -A `FuncSeries` should graph static functions like x2 (e.g. functions whose outputs for a given x-value don't change with time). This is because a `FuncSeries` precomputes the graph on the entire domain, so if the outputs *did* change over time, they wouldn't be reflected. However, a `FuncSeries` can still be used to visualize filters like [Interpolators](https://github.com/StuyPulse/StuyLib/blob/bg/plot-docs/src/com/stuypulse/stuylib/math/interpolation/Interpolator.java). - -Similar to `TimeSeries`, `FuncSeries` is created with a `Domain` which limits the x-values that function is graped over. - -In the example below, x2 is graphed by inputting `x -> x * x` as an IFilter. - -```java -FuncSeries xsq = new FuncSeries( - new Config("x^2", 500), - new Domain(-2, 2), - x -> x * x); -``` - -### [XYSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/XYSeries.java) - -A [XYSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/XYSeries.java) is used to plot a stream of points (x,y values) that changes over time. - -[XYSeries](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/util/plot/XYSeries.java) uses [VStreams](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/vectors/VStream.java) to get data. These streams can be paired with [VFilters](https://github.com/StuyPulse/StuyLib/blob/main/src/com/stuypulse/stuylib/streams/vectors/filters/VFilter.java) using `.filtered(...)`. - -Like `TimeSeries`, it can be used with `MouseTracker` to demonstrate filters, but this time in two dimensions! XYSeries is helpful to test VFilters and visualize 2D data. - -```java -XYSeries mouse2d = new XYSeries( - new Config("mouse pos", 500), - VStream.create(plot::getMouse)); - -XYSeries jerk2d = new XYSeries( - new Config("jerk limit", 500), - VStream.create(plot::getMouse) - .filtered(new VJerkLimit(10.0, 5.0))); -``` - -## What is a Plot? - -A Plot contains all of the graphics elements and references to [Knowm's XChart library](https://knowm.org/open-source/xchart/). It also holds all of the Series to be graphed and a MouseTracker. - -### Creating a Plot - -A `Plot` has a default constructor for convenience, but it can be configured further by passing in a [Settings](https://github.com/StuyPulse/StuyLib/blob/bg/plot-docs/src/com/stuypulse/stuylib/util/plot/Settings.java) object. - -A `Settings` object can change the title, axis labels, size, and ranges of the plot. - -The example below demonstrates some methods used for configuration by `Settings`: - -```java -Plot plot = new Plot(); - -Plot configured = new Plot( - new Settings() - .setTitle("My Plot") - .setXAxis("Position") - .setYAxis("Velocity") - .setXRange(0.0, 1.0) - .setYRange(0.0, 1.0) -); -``` - -### Adding Series to a Plot - -The `.addSeries(Series... series)` method can be used to add Series to a plot. - -Like shown in the Series examples, the MouseTracker's methods are exposed through `.getMouse()`, `.getMouseY()`, and `.getMouseX()`. These methods can be useful in creating a `Series` and can be casted to streams, ex. `IStream.create(plot::getMouseY)`. - -The example below adds the series created above to a plot: - -```java - -plot.addSeries(mouse, lpf) - .addSeries(xsq) - .addSeries(mouse2d, jerk2d); - -``` - -### Working with a Plot - -All the series in a plot are updated with `.updateSeries()`, which can call the `.poll()` and `.pop()` methods of each series. - -The plot is redrawn with the `.display()` method. - -Both of these methods are packaged into `.update()`. - -The `.isRunning()` method will check if a plot needs to updates its series and redraw anymore. To do this, it checks if each of its Series and will keep running if any of them are polling. *For example, a plot conatining only a `FuncSeries` will not be polling and will only run once.* - -A typical plot loop might look like this: - -```java -while (plot.isRunning()) { - plot.update(); - Thread.sleep(20); -} -``` diff --git a/src/com/stuypulse/stuylib/util/readme.md b/src/com/stuypulse/stuylib/util/readme.md index 9db2b1d2..127887a5 100644 --- a/src/com/stuypulse/stuylib/util/readme.md +++ b/src/com/stuypulse/stuylib/util/readme.md @@ -1,3 +1,3 @@ -# StuyLib Misc Utils. +# StuyLib Misc Utils -WIP... \ No newline at end of file +WIP...