Java как найти угол

I started with johncarls solution, but needed to adjust it to get exactly what I needed.
Mainly, I needed it to rotate clockwise when the angle increased. I also needed 0 degrees to point NORTH. His solution got me close, but I decided to post my solution as well in case it helps anyone else.

I’ve added some additional comments to help explain my understanding of the function in case you need to make simple modifications.

/**
 * Calculates the angle from centerPt to targetPt in degrees.
 * The return should range from [0,360), rotating CLOCKWISE, 
 * 0 and 360 degrees represents NORTH,
 * 90 degrees represents EAST, etc...
 *
 * Assumes all points are in the same coordinate space.  If they are not, 
 * you will need to call SwingUtilities.convertPointToScreen or equivalent 
 * on all arguments before passing them  to this function.
 *
 * @param centerPt   Point we are rotating around.
 * @param targetPt   Point we want to calcuate the angle to.  
 * @return angle in degrees.  This is the angle from centerPt to targetPt.
 */
public static double calcRotationAngleInDegrees(Point centerPt, Point targetPt)
{
    // calculate the angle theta from the deltaY and deltaX values
    // (atan2 returns radians values from [-PI,PI])
    // 0 currently points EAST.  
    // NOTE: By preserving Y and X param order to atan2,  we are expecting 
    // a CLOCKWISE angle direction.  
    double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x);

    // rotate the theta angle clockwise by 90 degrees 
    // (this makes 0 point NORTH)
    // NOTE: adding to an angle rotates it clockwise.  
    // subtracting would rotate it counter-clockwise
    theta += Math.PI/2.0;

    // convert from radians to degrees
    // this will give you an angle from [0->270],[-180,0]
    double angle = Math.toDegrees(theta);

    // convert to positive range [0-360)
    // since we want to prevent negative angles, adjust them now.
    // we can assume that atan2 will not return a negative value
    // greater than one partial rotation
    if (angle < 0) {
        angle += 360;
    }

    return angle;
}

Есть стрелка направленная от начала координат на координаты [1,1,1]
Как найти горизонтальный и вертикальный угол поворота, который направит её на координаты [1,2,3] ?

Kromster's user avatar

Kromster

13.5k12 золотых знаков43 серебряных знака72 бронзовых знака

задан 27 окт 2018 в 10:52

Ростислав's user avatar

  1. Узнаем нормальное направление на обе точки в плоскости XY (считаем длину вектора по XY и делим каждый компонент XY на эту длину).

  2. Используя тригонометрические функции, определяем угол каждого вектора – например:

    // Convert XY to euler value
    Angle := ArcTan2(-X, Y) / Pi * 180;
    
  3. Считаем разницу между углами

  4. Повторяем то же для плоскости YZ или XZ (на ваш выбор).

ответ дан 27 окт 2018 в 11:32

Kromster's user avatar

KromsterKromster

13.5k12 золотых знаков43 серебряных знака72 бронзовых знака


Содержание

  • 1. Общие сведения о классе Math
  • 2. Тригонометрические функции. Перечень
  • 3. Обратные тригонометрические функции. Перечень. Пример
  • 4. Гиперболические функции
  • Связанные темы

Поиск на других ресурсах:

1. Общие сведения о классе Math

Библиотека java.lang содержит средства для проведения математических вычислений, в частности, известный класс Math. Этот класс реализует математические функции, оперирующие числами в формате с плавающей запятой. Функции класса делятся на следующие группы:

  • тригонометрические функции;
  • экспоненциальные функции;
  • функции округления;
  • другие специальные функции.

Также класс содержит две константы, обращение к которым следующее:

  • Math.PI – число Пи (3.14…);
  • Math.E – экспонента (2.71…).

 

2. Тригонометрические функции. Перечень

Тригонометрические функции класса Math позволяют получить числовое значение известной математической функции. Эти функции оперируют радианами. Если известны градусы, то для получения радиан нужно применять формулу преобразования вроде

radians = Math.PI * degree / 180;

здесь

  • degree – угол, задаваемый в градусах;
  • radians – угол, задаваемый в радианах;
  • Math.PI – число 3.1415. Это константа из класса Math.

Список тригонометрических функций в классе Math следующий

  • sin(x) – возвращает синус от угла x, заданный в радианах;
  • cos(x) – вычисляет косинус от угла x;
  • tan(x) – вычисляет тангенс угла x.

Соответственно объявление функций в классе Math имеет вид

static double sin(double x)
static double cos(double x)
static double tan(double x)

здесь x – значение угла, заданное в радианах.

Пример.

public class MathFunctions {

  public static void main(String[] args) {
    // 1. Задан угол 45 градусов
    double degree = 45; // задан угол в градусах

    // 2. Получить из градусов радианы
    double radian = Math.PI * degree / 180;

    // 3. Получить синус от угла 45 градусов
    double resSin = Math.sin(radian);

    // 4. Взять косинус
    double resCos = Math.cos(radian);

    // 5. Взять тангенс
    double resTan = Math.tan(radian);

    // 6. Вывести результат
    System.out.println("resSin = " + resSin);
    System.out.println("resCos = " + resCos);
    System.out.println("resTan = " + resTan);
  }
}

Результат выполнения программы

resSin = 0.7071067811865475
resCos = 0.7071067811865476
resTan = 0.9999999999999999

 

3. Обратные тригонометрические функции. Перечень. Пример

Обратные тригонометрические функции получают результат вычисления соответствующей тригонометрической функции и возвращают угол в радианах. При надобности полученное значение в радианах можно преобразовать в градусы по формуле:

degree = 180 * radians / Math.PI;

здесь

  • degree – угол в градусах;
  • radians – угол в радианах;
  • Math.PI – число 3.1415. Это есть константа из класса Math.

Список обратных тригонометрических функций следующий:

  • asin() – арксинус от числа;
  • acos() – арккосинус;
  • atan() – арктангенс от числового значения;
  • atan2() – арктангенс, заданный пропорцией x/y.

Объявление обратных тригонометрических функций следующее

static double asin(double value)
static double acos(double value)
static double atan(double value)
static double atan2(double x, double y)

здесь

  • value – некоторое числовое значение. Для функций asin() и acos() значение value должно быть в пределах [0; 1].

Пример.

public class MathFunctions {

  public static void main(String[] args) {
    // 1. Задать значение
    double value = 1.0;

    // 2. Получить арккосинус, результат в радианах
    double aCos = Math.acos(value); // aCos = 0 радиан
    System.out.println("arcCos(1.0) = " + aCos);

    // 3. Отримати арксинус
    double aSin = Math.asin(value); // aSin = 1.57079 радіан
    System.out.println("arcSin(1.0) = " + aSin);

    // 4. Получить арктангенс.
    //    Сформировать значение, которое соответствует углу 45 градусов
    value = 1;
    double aTan = Math.atan(value); // aTan = 0.78 радиан
    System.out.println("aTan = " + aTan);

    // 5. Получить арктангенс от пропорции сторон
    double aTan2 = Math.atan2(1, 1); // угол 45 градусов
    System.out.println("aTan2 = " + aTan2); // aTan2 = 0.78
  }
}

Результат выполнения программы

arcCos(1.0) = 0.0
arcSin(1.0) = 1.5707963267948966
aTan = 0.7853981633974483
aTan2 = 0.7853981633974483

 

4. Гиперболические функции

Гиперболические функции возвращают значение от аргумента, заданного в радианах

  • sinh() – гиперболический синус;
  • cosh() – гиперболический косинус;
  • tanh() – гиперболический тангенс.

Объявление гиперболических функций следующее

static double sinh(double x)
static double cosh(double x)
static double tanh(double x)

здесь

  • x – значение в радианах.

Пример.

public class MathFunctions {

  public static void main(String[] args) {
    // 1. Задать значение
    double value = 1.0;

    // 2. Синус гиперболический
    double SinH = Math.sinh(value); 
    System.out.println("SinH = " + SinH);

    // 3. Косинус гиперболический
    value = 1.0;
    double CosH = Math.cosh(value);
    System.out.println("CosH = " + CosH);

    // 4. Тангенс гиперболический
    value = 1.0;
    double TanH = Math.tanh(value); 
    System.out.println("TanH = " + TanH);
  }
}

Результат

SinH = 1.1752011936438014
CosH = 1.543080634815244
TanH = 0.7615941559557649

 


Связанные темы

  • Экспоненциальные функции

 


Программирование: теория и практика

Вступление.

Практически любые исполняемые операции являются математическими вычисления каких-либо величин. Чаще всего приходится иметь дело с простейшими операциями, такими как вычитание, сложение, умножение и деление. Но в более сложных программах иногда требуются сложные операции (поиск большего/меньшего числа, вычисление степени числа и т.п.). В этих случаях целесообразно использование класса Math, который предоставляет различные способы работы с числовыми данными, упрощая написание кода.

В данной статье будут рассмотрены все методы публичного (public) абстрактного (abstract) класса Math.

Конструктор.

Экземпляр этого класса создать нельзя. Единственный конструктор помечен модификатором private и снабжён комментарием от создателей класса: «Никому не позволяйте создать экземпляр этого класса».

Переменные.

Данный класс обладает четырьмя доступными константами и двумя внутренними переменными:

· public static final double E = 2.7182818284590452354; — число «E» (основание натурального логарифма);

· public static final double PI = 3.14159265358979323846; — число «Пи» (соотношение диаметра и окружности);

· private static final double DEGREES_TO_RADIANS = 0.017453292519943295; — отношение градусов к радианам;

· private static final double RADIANS_TO_DEGREES = 57.29577951308232; — отношение радианов к градусам.

· static double twoToTheDoubleScaleUp – внутренняя переменная для работы метода scalb(), вычисляется при помощи метода powerOfTwoD(512);

· static double twoToTheDoubleScaleDown – внутренняя переменная для работы метода scalb(), вычисляется при помощи метода powerOfTwoD(-512);

Классы.

Содержит внутренний класс private static final class RandomNumberGeneratorHolder, внутри которого находится переменная типа Random.

Методы.

Класс Math обладает большим количеством статических методов по работе с числами. Для удобства чтения они будут разбиты на группы по тематикам.

Работа с углами.

· public static double sin(double a) – возвращает синус указанного в радианах значения.

· public static double cos(double a) – возвращает косинус указанного в радианах значения.

· public static double tan(double a) – возвращает тангенс указанного в радианах значения.

· public static double asin(double a) – возвращает арксинус указанного в радианах значения.

· public static double acos(double a) – возвращает арккосинус указанного в радианах значения.

· public static double atan(double a) – возвращает арктангенс указанного в радианах значения.

· public static double sinh(double x) – возвращает гиперболический синус двойного значения;

· public static double cosh(double x) – возвращает гиперболический косинус двойного значения;

· public static double tanh(double x) – возвращает гиперболический тангенс двойного значения;

· public static double hypot(double x, double y) – возвращает корень из x2 + y2 («евклидову норму»);

· public static double atan2(double y, double x) — возвращает double значение от -π до π, представляющее угол тета точки (x, y). Это угол в радианах, отсчитываемый против часовой стрелки от положительного направления оси X до точки (x, y). Внимание! Первой в методе передаётся координата y, второй — координата x.

Перевод в радианы и градусы.

· public static double toRadians(double angdeg) – перевод градусов в радианы.

· public static double toDegrees(double angrad) – перевод радиан в градусы.

Примечание: при переводе из градусов в радианы и из радиан в градусы возможна потеря точности из-за особенностей работы типа Double.

Простые математические операции.

· public static double random() – возвращает случайное число от 0 (включая) до 1 (исключая);

· public static int addExact(int x, int y)

public static long addExact(long x, long y) – возвращает результат сложения x и y;

· public static int subtractExact(int x, int y)

public static long subtractExact(long x, long y) – возвращает результат вычитания y из x;

· public static int multiplyExact(int x, int y)

public static long multiplyExact(long x, int y) –

public static long multiplyExact(long x, long y) – возвращает результат умножения x на y;

· public static long negateExact(long a) – меняет положительное значение числа на отрицательное, а отрицательное – на положительное.

· public static int toIntExact(long value) – превращает входящее значение в тип int и возвращает значение;

· public static long multiplyFull(int x, int y) – возвращает произведение x и y в формате long;

· public static int floorDiv(int x, int y)

public static long floorDiv(long x, int y)

public static long floorDiv(long x, long y) – возвращает результат деления x на y без возможной дробной части;

· public static int abs(int a)

public static long abs(long a)

public static float abs(float a)

public static double abs(double a) – возвращает абсолютное значение числа «a»;

· public static int max(int a, int b)

public static long max(long a, long b)

public static float max(float a, float b)

public static double max(double a, double b) – возвращает максимальное из двух чисел («a» и «b»);

· public static int min(int a, int b)

public static long min(long a, long b)

public static float min(float a, float b)

public static double min(double a, double b) – возвращает минимальное из двух чисел («a» и «b»).

Примечание: по сравнению со стандартными операторами сложения, вычитания, умножения и деления работает медленно при небольшом количестве операций. Но при количестве операций, превышающих 1 млрд., быстродействие методов класса Math становится более эффективным, чем использование стандартных математических операторов.

Сложные математические операции.

· public static double exp(double a) – возвращает натуральный логарифм по основанию числа Е и аргументу — показателю степени;

· public static double log(double a) – возвращает натуральный логарифм аргумента;

· public static double log10(double a) – возвращает десятичный (по основанию 10) логарифм числа. Если значение <= 0, то возвращаемое значение всегда будет равным NaN;

· public static double expm1(double x) – возвращает «ex – 1» (основание натурального логарифма в степени переданного аргумента минус 1);

· public static double log1p(double x) – возвращает натуральный логарифм суммы аргументов и 1;

· public static int getExponent(float f)

public static int getExponent(double d) – возвращает натуральный логарифм по основанию числа E и аргументу – показателю степени.

Работа со степенями.

· public static double sqrt(double a) – возвращает корень переданного числа;

· public static double cbrt(double a) – возвращает кубический корень переданного числа;

· public static double pow(double a, double b) – возвращает число ‘a’ в степени ‘b’.

Примечание: быстродействие метода pow(double a, double b) при целом и невысоком значении параметра b достаточно низкое по сравнению с операцией умножения; но при высоких (больше 7) значениях b метод pow(double a, double b) более эффективен, чем «вручную» прописанное перемножение.

Округления.

· public static double ceil(double a) – округление к большему целому числу;

· public static double floor(double a) – округление к меньшему целому числу;

· public static double rint(double a) – округление до ближайшего целого числа. Внимание! Значение 0.50 будет округлено в меньшую сторону (до 0); значение 0.51 будет округлено в большую сторону (до 1);

· public static long round(double a)

public static int round(float a) – округление до ближайшего целого числа. Внимание! Теперь значение 0.50 будет округлено в большую сторону (до 1).

Инкременты.

· public static int incrementExact(int a)

public static long incrementExact(long a) – увеличивает значение «a» на один и возвращает изменённое значение;

· public static int decrementExact(int a)

public static long decrementExact(long a) – уменьшает значение «a» на один и возвращает изменённое значение;

· public static double nextAfter(double start, double direction)

public static float nextAfter(float start, float direction) – возвращает число, максимально близкое к start, но при этом увеличенное/уменьшенное в сторону direction, в том числе может вернуть и само direction;

· public static double nextUp(double d)

public static float nextUp(float f) – возвращает число, максимально близкое к d(f), но при этом больше, чем d(f);

· public static double nextDown(double d)

public static float nextDown(float f) – возвращает число, максимально близкое к d(f), но при этом больше, чем d(f).

Примечание: методы incrementExact(int a) и decrementExact(int a) работают быстрее, чем синтаксис “a++” и “a—“.

Разное.

· public static double IEEEremainder(double f1, double f2) — вычисляет остаток для двух аргументов в соответствии со стандартом IEEE 754. Имеет схожие черты со стандартным делением с остатком и также по формуле «x – y * n», где x и y – переданные аргументы; но значение «n» при делении с остатком – целая часть от выражения «x/y», а при использовании метода IEEEremainder значение «n» — ближайшее целое число к выражению «x/y»;

· public static long multiplyHigh(long x, long y) — возвращает наиболее значимые 64 бит из 128-битного произведения двух 64-битных аргументов (типа long).

· public static int floorMod(int x, int y)

public static int floorMod(long x, int y)

public static long floorMod(long x, long y) – возвращает модуль основания целочисленных аргументов;

· public static double fma(double a, double b, double c)

public static float fma(float a, float b, float c) – возвращает исчисление a * b + c;

· public static double ulp(double d)

public static float ulp(float d) – возвращает размер «ulp-аргумента» («единицу наименьшей точности»);

· public static double signum(double d)

public static float signum(float d) – возвращает 0, если входящий аргумент = 0; 1, если входящий аргумент больше 0; -1, если входящий аргумент меньше 0.

· public static double copySign(double magnitude, double sign)

public static float copySign(float magnitude, float sign) – возвращает первый аргумент со знаком второго аргумента;

· public static double scalb(double d, int scaleFactor)

· public static float scalb(float f, int scaleFactor) – возвращает d*2scaleFactor (d умножить на 2 в степени scaleFactor);

· static double powerOfTwoD(int n) – внутренний метод, обеспечивающий работу методов scalb(double/float d, int scaleFactor).

Итоги.

Библиотека Math представляет собой инструментарий, значительно упрощающий работу с большим количеством однотипных вычислений. Не рекомендуется использовать эту библиотеку для вычисления простых операций (например, поиск числа в степени два), так как это приведёт к усложнению читаемости кода и снижению его быстродействия. Но при операциях, в которых требуется многократное количество повторений одной и той же операции – Math может оказаться весьма полезным ресурсом, так как внутри реализации методов содержит инструменты для ускорения работы кода. То же вычисление числа в степени 100 будет значительно быстрее выполнено библиотекой, чем в цикле. Или вычисление дробной степени числа, альтернативы которому в стандартных библиотеках Java просто нет.

Также библиотека Math предоставляет пользователю возможность работать с достаточно тонкими и редко используемыми вычислениями (как, например, вычисление ulp), что может оказаться весьма полезным при написании специфических программ, основанных на арифметических вычислениях.

Примеры кода.

Задача нижеприведенных примеров – не показать оптимальную работу кода, а продемонстрировать различные возможности библиотеки Math. Уверен, что некоторые из методов могут быть написаны в ином формате, а в некоторых случаях использование данной библиотеки не является обязательным.

/**
 * 1. Вывод различной информации о представленном угле
 *
 * @param num   - значение угла в радианах или градусах
 * @param isRad - введено значение в радианах (true) или градусах (false)?
 * @return - строка с информацией
 */
public String getInfo(double num, boolean isRad) {
	StringBuilder sb = new StringBuilder();
	String separator = String.format("-----------------------%s", System.lineSeparator());
	if (isRad) {
    	sb.append(String.format("Представлена информация по углу %.2f радиан (%f градусов).%s", num, Math.toDegrees(num), System.lineSeparator()));
	} else {
    	sb.append(String.format("Представлена информация по углу %.2f градусов (%f радиан).%s", num, num = Math.toRadians(num), System.lineSeparator()));
	}
	sb.append(separator);
	sb.append(String.format("Cинус угла = %f;%s", Math.sin(num), System.lineSeparator()));
	sb.append(String.format("Косинус угла = %f;%s", Math.cos(num), System.lineSeparator()));
	sb.append(String.format("Tангенс угла = %f;%s", Math.tan(num), System.lineSeparator()));
	sb.append(separator);
	sb.append(String.format("Арксинус угла = %s;%s", Math.asin(num) != Math.asin(num) ? "невозможное значение" : String.valueOf(Math.asin(num)), System.lineSeparator()));
	sb.append(String.format("Арккосинус угла = %s;%s", Math.acos(num) != Math.acos(num) ? "невозможное значение" : String.valueOf(Math.acos(num)), System.lineSeparator()));
	sb.append(String.format("Арктангенс угла = %f;%s", Math.atan(num), System.lineSeparator()));
	sb.append(separator);
	sb.append(String.format("Гиперболический синус двойного значения = %s;%s", Double.isInfinite(Math.sinh(num)) ? Character.toString((char) 8734) : String.valueOf(Math.sinh(num)), System.lineSeparator()));
	sb.append(String.format("Гиперболический косинус двойного значения  = %s;%s", Double.isInfinite(Math.cosh(num)) ? Character.toString((char) 8734) : String.valueOf(Math.cosh(num)), System.lineSeparator()));
	sb.append(String.format("Гиперболический тангенс двойного значения  = %f;%s", Math.tanh(num), System.lineSeparator()));
	return sb.toString();
}
 
 
/**
 * 2. Вывод информации о прямоугольном треугольнике по двум катетам
 *
 * @param a - длина одного катета
 * @param b - длина другого катета
 * @return - строка с информацией
 */
public String triangoloInfo(double a, double b) {
	StringBuilder sb = new StringBuilder();
	return sb.append(String.format("Длина гипотенузы = %.2f; периметр треугольника = %.2f; площадь треугольника = %.2f.", Math.hypot(a, b), Math.hypot(a, b) + a + b, a * b / 2)).toString();
}
 
 
/**
 * 3. Сложение всех передаваемых значений
 *
 * @param args - значения
 * @return - сумма значений
 */
public int manyAdds(int... args) {
	int result = 0;
	for (int arg : args) {
    	result = Math.addExact(result, arg);
	}
	return result;
}
 
 
/**
 * 4. Ответ на вопрос - является ли корень из модуля данного числа целым числом
 *
 * @param number - число для проверки
 * @return - является (true) или нет (false)
 */
public boolean rootInt(long number) {
	return Math.sqrt(Math.abs(number)) == (int) Math.sqrt(Math.abs(number));
}
 
 
/**
 * 5. Возврат псевдослучайного значения в диапазоне от -rand до rand.
 *
 * @param rand - число для создания ограничения
 * @return - псевдослучайное число
 */
public int randomizeValue(int rand) {
	return (int) (Math.random() * Math.abs(rand) * 2) - Math.abs(rand);
}
 
 
/**
 * 6. Вывод информации о числе, является ли оно больше, меньше или равным нолю.
 *
 * @param f - число для проверки
 */
public void printValue(float f) {
	f = Math.signum(f);
	switch ((int) f) {
    	case -1 -> System.out.println("Число меньше 0.");
    	case 0 -> System.out.println("Число равно 0.");
    	default -> System.out.println("Число больше 0.");
	}
}
 
 
/**
 * 7. Возврат массива, который содержит наименьшее и наибольшее значение из переданных
 * @param arr - передаваемое значение
 * @return - массив с наименьшим и наибольшим числами
 */
public int[] minMax(int... arr) {
	int[] result = new int[]{Integer.MAX_VALUE, Integer.MIN_VALUE};
	for (int i = 0; i < arr.length; i++) {
    	result[0] = Math.min(result[0], arr[i]);
    	result[1] = Math.max(result[1], arr[i]);
	}
	return result;
}

Маслов Василий, после окончания базового курса, февраль 2021

EugeneV, Тут ничего сложного нет, школьный курс геометрии и базовые знания библиотеки joml

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        Vector3f v1 = new Vector3f(4, 0, 0);
        System.out.println("v1: " + v1);
        System.out.println("Length: " + v1.length());
        Vector3f vn = new Vector3f();
        v1.normalize(vn);
        System.out.println("vn: " + vn);
        System.out.println("Length: " + vn.length());
        Vector3f vn2 = new Vector3f(0, 1, 0);
        System.out.println("vn2: " + vn2);
        System.out.println("Length: " + vn2.length());
        Vector3f v2 = new Vector3f(0, 5, 0);
        System.out.println("v2: " + v2);
        System.out.println("Length: " + v2.length());
        System.out.println("Angle (vn, vn2): " + Math.toDegrees(vn.angle(vn2)));
        System.out.println("Angle (v1, v2): " + Math.toDegrees(v1.angle(v2)));
        System.out.println("Cos (vn, vn2): " + vn.dot(vn2));
        System.out.println("Arccos (vn, vn2): " + Math.toDegrees(Math.acos(vn.dot(vn2))));

Если вектора единичные (то есть нормализованы), то их длины равны 1. Нормализация это метод .normalize() а нахождение длины метод .length() оба метода есть у всех векторов (Vector2f, Vector3f, Vector4f и тд). В числителе дроби стоит скалярное произведение векторов, метод .dot(vec in) возвращает число, но есть еще готовый метод который находит угол между векторами .angle(vec in) который тоже возвращает число, равное углу между векторами в радианах

С кватернионами не сталкивался и нету жедания в них влезать, мне и углов Эйлера хватает, а вообще для поворота стоит использовать матрицы поворота, желательно в шейдерах, передавая в них матрицу модели. А в программе работать с моделью в локальных ее координатах

Добавить комментарий