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 static edu.wpi.first.units.Units.Meters;
008
009import edu.wpi.first.math.geometry.proto.Transform2dProto;
010import edu.wpi.first.math.geometry.struct.Transform2dStruct;
011import edu.wpi.first.units.Distance;
012import edu.wpi.first.units.Measure;
013import java.util.Objects;
014
015/** Represents a transformation for a Pose2d in the pose's frame. */
016public class Transform2d {
017  private final Translation2d m_translation;
018  private final Rotation2d m_rotation;
019
020  /**
021   * Constructs the transform that maps the initial pose to the final pose.
022   *
023   * @param initial The initial pose for the transformation.
024   * @param last The final pose for the transformation.
025   */
026  public Transform2d(Pose2d initial, Pose2d last) {
027    // We are rotating the difference between the translations
028    // using a clockwise rotation matrix. This transforms the global
029    // delta into a local delta (relative to the initial pose).
030    m_translation =
031        last.getTranslation()
032            .minus(initial.getTranslation())
033            .rotateBy(initial.getRotation().unaryMinus());
034
035    m_rotation = last.getRotation().minus(initial.getRotation());
036  }
037
038  /**
039   * Constructs a transform with the given translation and rotation components.
040   *
041   * @param translation Translational component of the transform.
042   * @param rotation Rotational component of the transform.
043   */
044  public Transform2d(Translation2d translation, Rotation2d rotation) {
045    m_translation = translation;
046    m_rotation = rotation;
047  }
048
049  /**
050   * Constructs a transform with x and y translations instead of a separate Translation2d.
051   *
052   * @param x The x component of the translational component of the transform.
053   * @param y The y component of the translational component of the transform.
054   * @param rotation The rotational component of the transform.
055   */
056  public Transform2d(double x, double y, Rotation2d rotation) {
057    m_translation = new Translation2d(x, y);
058    m_rotation = rotation;
059  }
060
061  /**
062   * Constructs a transform with x and y translations instead of a separate Translation2d. The X and
063   * Y translations will be converted to and tracked as meters.
064   *
065   * @param x The x component of the translational component of the transform.
066   * @param y The y component of the translational component of the transform.
067   * @param rotation The rotational component of the transform.
068   */
069  public Transform2d(Measure<Distance> x, Measure<Distance> y, Rotation2d rotation) {
070    this(x.in(Meters), y.in(Meters), rotation);
071  }
072
073  /** Constructs the identity transform -- maps an initial pose to itself. */
074  public Transform2d() {
075    m_translation = new Translation2d();
076    m_rotation = new Rotation2d();
077  }
078
079  /**
080   * Multiplies the transform by the scalar.
081   *
082   * @param scalar The scalar.
083   * @return The scaled Transform2d.
084   */
085  public Transform2d times(double scalar) {
086    return new Transform2d(m_translation.times(scalar), m_rotation.times(scalar));
087  }
088
089  /**
090   * Divides the transform by the scalar.
091   *
092   * @param scalar The scalar.
093   * @return The scaled Transform2d.
094   */
095  public Transform2d div(double scalar) {
096    return times(1.0 / scalar);
097  }
098
099  /**
100   * Composes two transformations. The second transform is applied relative to the orientation of
101   * the first.
102   *
103   * @param other The transform to compose with this one.
104   * @return The composition of the two transformations.
105   */
106  public Transform2d plus(Transform2d other) {
107    return new Transform2d(new Pose2d(), new Pose2d().transformBy(this).transformBy(other));
108  }
109
110  /**
111   * Returns the translation component of the transformation.
112   *
113   * @return The translational component of the transform.
114   */
115  public Translation2d getTranslation() {
116    return m_translation;
117  }
118
119  /**
120   * Returns the X component of the transformation's translation.
121   *
122   * @return The x component of the transformation's translation.
123   */
124  public double getX() {
125    return m_translation.getX();
126  }
127
128  /**
129   * Returns the Y component of the transformation's translation.
130   *
131   * @return The y component of the transformation's translation.
132   */
133  public double getY() {
134    return m_translation.getY();
135  }
136
137  /**
138   * Returns the rotational component of the transformation.
139   *
140   * @return Reference to the rotational component of the transform.
141   */
142  public Rotation2d getRotation() {
143    return m_rotation;
144  }
145
146  /**
147   * Invert the transformation. This is useful for undoing a transformation.
148   *
149   * @return The inverted transformation.
150   */
151  public Transform2d inverse() {
152    // We are rotating the difference between the translations
153    // using a clockwise rotation matrix. This transforms the global
154    // delta into a local delta (relative to the initial pose).
155    return new Transform2d(
156        getTranslation().unaryMinus().rotateBy(getRotation().unaryMinus()),
157        getRotation().unaryMinus());
158  }
159
160  @Override
161  public String toString() {
162    return String.format("Transform2d(%s, %s)", m_translation, m_rotation);
163  }
164
165  /**
166   * Checks equality between this Transform2d and another object.
167   *
168   * @param obj The other object.
169   * @return Whether the two objects are equal or not.
170   */
171  @Override
172  public boolean equals(Object obj) {
173    if (obj instanceof Transform2d) {
174      return ((Transform2d) obj).m_translation.equals(m_translation)
175          && ((Transform2d) obj).m_rotation.equals(m_rotation);
176    }
177    return false;
178  }
179
180  @Override
181  public int hashCode() {
182    return Objects.hash(m_translation, m_rotation);
183  }
184
185  public static final Transform2dStruct struct = new Transform2dStruct();
186  public static final Transform2dProto proto = new Transform2dProto();
187}