1

Тема: AHK: Узнать знак поворота.

Всем добра!

Коллеги, подскажите пожалуйста, как узнать знак поворота, отталкиваясь лишь от следующего:
Известно положение точки "A" в координатах [0, 0] и, что вектор всех точек направленных от неё имеет угол 90 градусов по отношению к оси "X".
Известно положение точки "B" в координатах [-2, -1].
Функция, вычисляющая угол между двумя векторами возвращает положительное значение градусов в диапазоне [0: 180] включительно.

То есть:


A->B и A->[0: любое значение Y] == (~116,57 градусов) == A->[0: любое значение Y] и [2: -1]

Как вычислить, следует результат функции вычитать из текущего значения угла, или прибавлять, чтобы развернуть вектор по направлению из "A" в "B", а не в другую сторону?

https://i.ibb.co/hMp9gxW/shot.jpg

2 (изменено: ypppu, 2023-01-18 23:13:38)

Re: AHK: Узнать знак поворота.

Судя по картинке, задача простая. Но, когда начинаешь читать текст, ничего не понятно.

Добавлено:
Точки принято обозначать заглавными латинскими буквами, а углы - греческими.

3 (изменено: Madmer, 2023-01-19 04:21:15)

Re: AHK: Узнать знак поворота.

KusochekDobra
Чтобы определить направление поворота из точки A в точку B, вам нужно сравнить угол между вектором от A до B и вектором от A до положительной оси X (которая имеет угол 90 градусов по отношению к A). Если угол между двумя векторами находится в диапазоне [0,90], то поворот происходит вправо. Если угол находится в диапазоне [90,180], то поворот осуществляется влево.
Вы можете использовать функцию, которая вычисляет угол между двумя векторами, чтобы определить это. Если возвращаемый угол меньше 90, вы можете добавить его к текущему углу A -> [0: любое значение Y]. Если угол больше 90, вы должны вычесть его из текущего угла.
Также можно использовать скалярное произведение. Скалярное произведение двух векторов будет положительным, если угол между ними против часовой стрелки, и отрицательным  по часовой.

4

Re: AHK: Узнать знак поворота.

Прошу прощения, за 20 с лишним лет не довелось воспользоваться тригонометрией ни разу, так что всё поистёрлось в памяти.

Можно представить, что машина расположена в координатах[0: 0] и она направлена на север, обозначая свой угол по отношению к началу отсчёта равным 90 градусов. Навигатору поступила команда прибыть в точку [-2: -1], для чего он вычисляет имеющимися средствами угол поворота(116.56505117707799) и дистанцию(2.23606797749979). Для наблюдателя рисунка, очевидно, что к текущему углу нужно прибавить положительное значение угла, чтобы поворот оказался верным. Вот только до точки [2: -1] возвращается тот же угол и дистанция.
Несколько упростил код расчёта угла между векторами отсюда.


class Point {
	__New(x, y) {
		this.x := x
		this.y := y
	}
	
	Dot(other_point) {		; -> float
		return this.x * other_point.x + this.y * other_point.y
	}
	
	Distance(other_point) { ; -> float
		diff_x := this.x - other_point.x
		diff_y := this.y - other_point.y
		return Sqrt(diff_x**2 + diff_y**2)
	}
}

class Vec {
	__New(start_point, end_point) {
		this.start := start_point
		this.end := end_point
	}
	
	DiffPoint() {			; -> Point
		s := this.start
		e := this.end
		return new Point(e.x - s.x, e.y - s.y)
	}
	
	Angle(other_vec) {		; -> float
		dp1 := this.DiffPoint()
		dp2 := other_vec.DiffPoint()
		return ACos(dp1.Dot(dp2) / dp1.Dot(dp1)**0.5 / dp2.Dot(dp2)**0.5) * 57.29578
	}
}

src_point  := new Point(0, 0)
dest_point := new Point(-2, -1)
anotnter_same_point := new Point(2, -1)
perpendicular_point := new Point(-2, 0)

; Вектор произвольной длины по оси Y в текущем направлении
vec1 := new Vec(src_point, new Point(0, 1))

vec2 := new Vec(src_point, dest_point)
vec3 := new Vec(src_point, anotnter_same_point)
vec4 := new Vec(src_point, perpendicular_point)

MsgBox % "Угол: " . vec1.Angle(vec2) . " | расстояние: " . src_point.Distance(dest_point)
MsgBox % "Угол: " . vec1.Angle(vec3) . " | расстояние: " . src_point.Distance(anotnter_same_point)
MsgBox % "Угол: " . vec1.Angle(vec4) . " | расстояние: " . src_point.Distance(perpendicular_point)
Madmer пишет:

Чтобы определить направление поворота из точки A в точку B, вам нужно сравнить угол между вектором от A до B и вектором от A до положительной оси X (которая имеет угол 90 градусов по отношению к A). Если угол между двумя векторами находится в диапазоне [0,90], то поворот происходит вправо. ...

Но потом, например, вектор будет иметь направление A -> B и находиться в точке B и для следующей произвольной точки, например в [-3: 2], это уже не сработает.

Madmer пишет:

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

Простите, если путаю, но при гуглении, под векторами мне всё время предстают последовательности чисел, аля [1, 3, 5] и так далее и скалярное произведение двух векторов выглядит как сумма последовательно перемноженных членов этих векторов. А тут вектор — это последовательность точек. Если я правильно понимаю "Скалярное произведение векторов, заданных координатами", то метод Point.Dot() делает как раз это. Но для двух разных точек они эквивалентны:


p1 := new Point(0, 0)
p2 := new Point(0, 1)   ; Произвольная точка на векторе
p3 := new Point(2, -1)
p4 := new Point(-2, -1)

MsgBox % p2.Dot(p3)
MsgBox % p2.Dot(p4)

Я несомненно что-то упускаю и не могу понять, что.

5

Re: AHK: Узнать знак поворота.

Вот тут не то, что нужно?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6

Re: AHK: Узнать знак поворота.

KusochekDobra
Да, вы правы в том, что подход, который я описал ранее, будет работать только для определенного направления от А до В и не будет применим для других точек.
Что касается скалярного произведения, да, это сумма произведений соответствующих компонентов двух векторов. И в этом случае метод Point.Dot() вычисляет точечное произведение двух векторов, заданных координатами их конечных точек. Это эквивалентно скалярному произведению двух векторов.
Извиняюсь, я перепутал произведения. Для нахождения направления вращения от A до B лучше использовать векторное произведение двух векторов. Оно будет положительным, если угол между двумя векторами направлен против часовой стрелки, и отрицательным, если он направлен по часовой стрелке.

7 (изменено: KusochekDobra, 2023-01-19 18:59:26)

Re: AHK: Узнать знак поворота.

Коллеги, благодарю!
Правда я зарегистрировался в chat.open.ai и заморочил по этому поводу ChatGPT.
Вот дополненный вариант:


Cond(reason_num) {	; -> string
	if (!reason_num)
		return "без поворота"
	return reason_num > 0 ? "против часовой стрелки" : "по часовой стрелке"
}

class Point {
	__New(x, y) {
		this.x := x
		this.y := y
	}
	
	Dot(other_point) {		; -> float
		return this.x * other_point.x + this.y * other_point.y
	}
	
	Distance(other_point) { ; -> float
		diff_x := this.x - other_point.x
		diff_y := this.y - other_point.y
		return Sqrt(diff_x**2 + diff_y**2)
	}
}

class Vec {
	__New(start_point, end_point) {
		this.start := start_point
		this.end := end_point
	}
	
	CrossProd(other_vec) {	; -> number
		r1 := (this.end.x - this.start.x) * (other_vec.end.y - this.start.y)
		r2 := (this.end.y - this.start.y) * (other_vec.end.x - this.start.x)
		return r1 - r2
	}
	
	DiffPoint() {			; -> Point
		s := this.start
		e := this.end
		return new Point(e.x - s.x, e.y - s.y)
	}
	
	Angle(other_vec) {		; -> float
		dp1 := this.DiffPoint()
		dp2 := other_vec.DiffPoint()
		return ACos(dp1.Dot(dp2) / dp1.Dot(dp1)**0.5 / dp2.Dot(dp2)**0.5) * 57.29578
	}
}

src_point  := new Point(0, 0)
dest_point := new Point(-2, -1)
anotnter_same_point := new Point(2, -1)
perpendicular_point := new Point(-2, 0)
other_perpend_point := new Point(2, 0)
in_src_vec_point := new Point(0, 7)
reverse_src_vec_point := new Point(0, -7)

; Вектор произвольной длины по оси Y в текущем направлении
vec1 := new Vec(src_point, new Point(0, 1))

vec2 := new Vec(src_point, dest_point)
vec3 := new Vec(src_point, anotnter_same_point)
vec4 := new Vec(src_point, perpendicular_point)
vec5 := new Vec(src_point, other_perpend_point)
vec6 := new Vec(src_point, in_src_vec_point)
vec7 := new Vec(src_point, reverse_src_vec_point)


MsgBox,0x40,dest_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec2)
				, src_point.Distance(dest_point)
				, Cond(vec1.CrossProd(vec2)))
				
MsgBox,0x40,anotnter_same_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec3)
				, src_point.Distance(anotnter_same_point)
				, Cond(vec1.CrossProd(vec3)))
				
MsgBox,0x40,perpendicular_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec4)
				, src_point.Distance(perpendicular_point)
				, Cond(vec1.CrossProd(vec4)))
				
MsgBox,0x40,other_perpend_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec5)
				, src_point.Distance(other_perpend_point)
				, Cond(vec1.CrossProd(vec5)))
				
MsgBox,0x40,in_src_vec_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec6)
				, src_point.Distance(in_src_vec_point)
				, Cond(vec1.CrossProd(vec6)))
				
MsgBox,0x40,reverse_src_vec_point,% Format("Угол: {} | расстояние: {} | поворот: {}"
				, vec1.Angle(vec7)
				, src_point.Distance(reverse_src_vec_point)
				, Cond(vec1.CrossProd(vec7)))

Если интересно, так мы с ним поболтали, потом у меня кончился лимит на количество запросов в час, но я уже всё выяснил к тому моменту.
https://i.ibb.co/jgB0DS7/ChatGPT.jpg