001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.math.geometry;
006
007import com.fasterxml.jackson.annotation.JsonAutoDetect;
008import com.fasterxml.jackson.annotation.JsonCreator;
009import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
010import com.fasterxml.jackson.annotation.JsonProperty;
011import edu.wpi.first.math.MathUtil;
012import edu.wpi.first.math.interpolation.Interpolatable;
013import java.util.Objects;
014
015/**
016 * Represents a translation in 2d space. This object can be used to represent a point or a vector.
017 *
018 * <p>This assumes that you are using conventional mathematical axes. When the robot is placed on
019 * the origin, facing toward the X direction, moving forward increases the X, whereas moving to the
020 * left increases the Y.
021 */
022@SuppressWarnings({"ParameterName", "MemberName"})
023@JsonIgnoreProperties(ignoreUnknown = true)
024@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE)
025public class Translation2d implements Interpolatable<Translation2d> {
026  private final double m_x;
027  private final double m_y;
028
029  /** Constructs a Translation2d with X and Y components equal to zero. */
030  public Translation2d() {
031    this(0.0, 0.0);
032  }
033
034  /**
035   * Constructs a Translation2d with the X and Y components equal to the provided values.
036   *
037   * @param x The x component of the translation.
038   * @param y The y component of the translation.
039   */
040  @JsonCreator
041  public Translation2d(
042      @JsonProperty(required = true, value = "x") double x,
043      @JsonProperty(required = true, value = "y") double y) {
044    m_x = x;
045    m_y = y;
046  }
047
048  /**
049   * Constructs a Translation2d with the provided distance and angle. This is essentially converting
050   * from polar coordinates to Cartesian coordinates.
051   *
052   * @param distance The distance from the origin to the end of the translation.
053   * @param angle The angle between the x-axis and the translation vector.
054   */
055  public Translation2d(double distance, Rotation2d angle) {
056    m_x = distance * angle.getCos();
057    m_y = distance * angle.getSin();
058  }
059
060  /**
061   * Calculates the distance between two translations in 2d space.
062   *
063   * <p>This function uses the pythagorean theorem to calculate the distance. distance = sqrt((x2 -
064   * x1)^2 + (y2 - y1)^2)
065   *
066   * @param other The translation to compute the distance to.
067   * @return The distance between the two translations.
068   */
069  public double getDistance(Translation2d other) {
070    return Math.hypot(other.m_x - m_x, other.m_y - m_y);
071  }
072
073  /**
074   * Returns the X component of the translation.
075   *
076   * @return The x component of the translation.
077   */
078  @JsonProperty
079  public double getX() {
080    return m_x;
081  }
082
083  /**
084   * Returns the Y component of the translation.
085   *
086   * @return The y component of the translation.
087   */
088  @JsonProperty
089  public double getY() {
090    return m_y;
091  }
092
093  /**
094   * Returns the norm, or distance from the origin to the translation.
095   *
096   * @return The norm of the translation.
097   */
098  public double getNorm() {
099    return Math.hypot(m_x, m_y);
100  }
101
102  /**
103   * Applies a rotation to the translation in 2d space.
104   *
105   * <p>This multiplies the translation vector by a counterclockwise rotation matrix of the given
106   * angle. [x_new] [other.cos, -other.sin][x] [y_new] = [other.sin, other.cos][y]
107   *
108   * <p>For example, rotating a Translation2d of {2, 0} by 90 degrees will return a Translation2d of
109   * {0, 2}.
110   *
111   * @param other The rotation to rotate the translation by.
112   * @return The new rotated translation.
113   */
114  public Translation2d rotateBy(Rotation2d other) {
115    return new Translation2d(
116        m_x * other.getCos() - m_y * other.getSin(), m_x * other.getSin() + m_y * other.getCos());
117  }
118
119  /**
120   * Adds two translations in 2d space and returns the sum. This is similar to vector addition.
121   *
122   * <p>For example, Translation2d{1.0, 2.5} + Translation2d{2.0, 5.5} = Translation2d{3.0, 8.0}
123   *
124   * @param other The translation to add.
125   * @return The sum of the translations.
126   */
127  public Translation2d plus(Translation2d other) {
128    return new Translation2d(m_x + other.m_x, m_y + other.m_y);
129  }
130
131  /**
132   * Subtracts the other translation from the other translation and returns the difference.
133   *
134   * <p>For example, Translation2d{5.0, 4.0} - Translation2d{1.0, 2.0} = Translation2d{4.0, 2.0}
135   *
136   * @param other The translation to subtract.
137   * @return The difference between the two translations.
138   */
139  public Translation2d minus(Translation2d other) {
140    return new Translation2d(m_x - other.m_x, m_y - other.m_y);
141  }
142
143  /**
144   * Returns the inverse of the current translation. This is equivalent to rotating by 180 degrees,
145   * flipping the point over both axes, or simply negating both components of the translation.
146   *
147   * @return The inverse of the current translation.
148   */
149  public Translation2d unaryMinus() {
150    return new Translation2d(-m_x, -m_y);
151  }
152
153  /**
154   * Multiplies the translation by a scalar and returns the new translation.
155   *
156   * <p>For example, Translation2d{2.0, 2.5} * 2 = Translation2d{4.0, 5.0}
157   *
158   * @param scalar The scalar to multiply by.
159   * @return The scaled translation.
160   */
161  public Translation2d times(double scalar) {
162    return new Translation2d(m_x * scalar, m_y * scalar);
163  }
164
165  /**
166   * Divides the translation by a scalar and returns the new translation.
167   *
168   * <p>For example, Translation2d{2.0, 2.5} / 2 = Translation2d{1.0, 1.25}
169   *
170   * @param scalar The scalar to multiply by.
171   * @return The reference to the new mutated object.
172   */
173  public Translation2d div(double scalar) {
174    return new Translation2d(m_x / scalar, m_y / scalar);
175  }
176
177  @Override
178  public String toString() {
179    return String.format("Translation2d(X: %.2f, Y: %.2f)", m_x, m_y);
180  }
181
182  /**
183   * Checks equality between this Translation2d and another object.
184   *
185   * @param obj The other object.
186   * @return Whether the two objects are equal or not.
187   */
188  @Override
189  public boolean equals(Object obj) {
190    if (obj instanceof Translation2d) {
191      return Math.abs(((Translation2d) obj).m_x - m_x) < 1E-9
192          && Math.abs(((Translation2d) obj).m_y - m_y) < 1E-9;
193    }
194    return false;
195  }
196
197  @Override
198  public int hashCode() {
199    return Objects.hash(m_x, m_y);
200  }
201
202  @Override
203  public Translation2d interpolate(Translation2d endValue, double t) {
204    return new Translation2d(
205        MathUtil.interpolate(this.getX(), endValue.getX(), t),
206        MathUtil.interpolate(this.getY(), endValue.getY(), t));
207  }
208}