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}