Minimum knowledge required when dealing with "angles" and "coordinates" in Ruby + In what direction is Mr. B from the perspective of Mr. A? Algorithm

The other day, I had the opportunity to handle coordinates and angles in Ruby, so I made all the knowledge necessary to handle them compact and carefully summarized them. In the second half, as an example, there is a simple code that allows you to check in units of 8 directions, such as "Which direction is Mr. B from the perspective of Mr. A?". I'm glad if you can use it as a reference. (Version: ruby 2.5.1)

su.png

There are two commonly used units for angles

Just as there are different standards for expressing length, such as "meters" and "feet," there are multiple ways to express angles. When we express an angle, we generally use something like 90 ° (90 degrees). However, on the module provided by __Ruby, a unit called radian (rad) is used __.

Concept of degree (°)

In this unit, __1 lap is 360 ° __. So, for example, if you "rotate 360 ° to the right (or left)", you can return to the exact same direction as the original.

Radian (rad) way of thinking

In this unit, 1 lap is 2 × π rad. So, for example, if you "rotate 2 x π rad to the right (or left)", you can return to the exact same direction as the original. (Π = pi ≒ 3.14)

For those who have lost their memory as a student like me, how long is pi relative to the diameter of the circle? It is the ratio of, and the ratio is fixed at about 3.14 times. If the diameter of the circle is 1 cm, the circumference of the circle is 1 x π cm, or about 3.14 cm. Click here for details on π (Pi)

Therefore

You can convert degrees (°) to radians (rad) as follows.

= 0 × π = 0.00000… rad __45 ° __ = (2 × π) ÷ 8 = 0.78539… rad (45 ° is divided into 8 equal parts of “2 × π”) __90 ° __ = (2 × π) ÷ 4 = 1.57079… rad (90 ° is divided into 4 equal parts of “2 × π”) __180 ° __ = (2 × π) ÷ 2 = 3.14159… rad (180 ° is bisected “2 × π”) __270 ° __ = (2 × π) ÷ 4 × 3 = __4.71238 __… rad (270 ° is 3/4 of “2 × π”) __360 ° __ = (2 × π) = 6.28318… rad (360 ° is “2 × π”)

It's a bit of a roundabout explanation, but it's easier to remember if you keep the criteria __180 (°) = π (rad) __.

In the Ruby world, π = "Math :: PI"

Let's suppress one essential knowledge of Ruby here. To express π (≈3.14) in code, we need the help of a module called "Math". To call the module, write ʻinclude Mathat the top of the code. If you call the module, you can express π just by writingPI`.

include Math

puts PI
#Output result :: 3.141592653589793

If you want to call the module in a single shot instead of the whole file, call it by the following method (include Math unnecessary version).

puts Math::PI
#Output result :: 3.141592653589793

Reference ... The link below also introduces the mutual conversion method between degrees (°) and radians (rad). "Ruby code that converts radians and degrees" by @niwasawa

How to use "Math :: atan2" to find the angle from the coordinates

location.png

If the x-axis and y-axis are prepared as described above and the coordinates (values of x and y) are given, use another function ʻatan2` provided by the Math module mentioned above. You can find the angle (rad).

include Math

def radian(x, y)
  return atan2(y, x)
  #Note that the order of the arguments x and the argument y is reversed.
end

puts radian(5, 3)
#Output result::   0.5404195002705842

This is an output result by radians (rad), which is not very familiar, so in the following, I will add "÷ π × 180" in the method to convert it to degrees (°), and finally round it off.

include Math

def degree(x, y)
  return atan2(y, x)/PI*180
end

puts degree(5, 3).round
#Output result::   31

I was able to find the angle of 31 degrees safely.

In what direction is Mr. B from the perspective of Mr. A?

a_b.png

If you are given the coordinates of Mr. A and the coordinates of Mr. B as shown in the above figure, let's make a code so that you can answer which direction you are in in 8 directions. By the way, I would like to measure the distance between the two. (Unit of distance: m)

specification

Enter the coordinates of Mr. A (x, y) and the coordinates of Mr. B (x, y) ↓ Outputs the direction and distance from Mr. A to Mr. B

input


Coordinates of Mr. A(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. A's coordinates are?◯ ◯ ← Enter here
B's coordinates(x, y)Please enter two half-width numbers with a half-width space in between.
B's coordinates are?◯ ◯ ← Enter here

output


Mr. B is in the direction of ◆◆ when viewed from Mr. A, and is ▲▲ m away.

Exception handling


The two are in the same place.

Point 1 Think with Mr. A as the starting point (center)

As shown in the image below, in order to find out in which direction you are "as seen from Mr. A", consider Mr. A as the starting point (center). slide.mov.gif In this case, in order to bring Mr. A to the center, it is OK to move Mr. A by -3m in the x direction and + 2m in the y direction, so ask Mr. B to move the same distance as well.

A (3, -2) x is -3, y is +2 → A (0, 0) = This is the center! Similarly ... B (-2, -4) x to -3, y to +2 → __B (-5, -2) If you check the direction of this coordinate with Math :: atan2, it's OK! __

Point 2 Range of return value of Math :: atan2

This time we will examine all directions. I expected that the value between 0 ° and 360 ° could be obtained by utilizing ʻatan2, but in fact, the range of values returned by __ʻatan2 is -π to π (in terms of frequency- 180 ° ~ 180 °) is fixed __. In the case of "between 3:00 and 9:00" in the hands of the clock, a negative value will be returned.

There is no problem even if the algorithm is set up according to this specification, but for studying, I would like to take a method to convert the obtained angle value to a convenient value here. Reference: "Converting an angle to a positive angle (0 to 359 degrees) with Ruby" by @ massassiez

# -How to convert a value between 180 and 180 to a value between 0 and 360(-Taking 120 as an example)

(-120).modulo(360)
#Or
-120 % 360

#This will convert it to 240

The above % and modulo are doing exactly the same thing. By finding the remainder (too much) when divided by 360, it will be automatically converted to the range of 0 to 360. (By the way, modulo can be used without include Math)

Point 3 Distance uses the three-square theorem

Use the Three Squares Theorem to find the distance between two points A (x, y) and B (x, y). Let's do it.

AB= \sqrt{(x_b−x_a)^2+(y_b−y_a)^2}

If you do this in Ruby, it will look like the following.

def distance(a_x, a_y, b_x, b_y)
  return ((b_x - a_x)**2 + (b_y - a_y)**2)**(1/2.0)
end

#  **2 ← squared
#  **(1/2.0)← Route(square root)doing

Completion code

sampl.rb(Complete)



#This time I want to use atan2 and PI, so declare include Math first
include Math

#Method to find the angle
def degree(x, y)
  (atan2(y, x)/PI*180)%360
end

#Method to find the direction
def compass(degree)
  if degree > 15 && degree < 75
     "Northeast"
  elsif degree >= 75 && degree <= 105
     "North"
  elsif degree > 105 && degree < 165
     "Northwest"
  elsif degree >= 165 && degree <= 195
     "West"
  elsif degree > 195 && degree < 255
     "Southwest"
  elsif degree >= 255 && degree <= 285
     "South"
  elsif degree > 285 && degree < 345
     "Southeast"
  else
     "east"
  end
end

#Method to find the distance between two points
def distance(a_x, a_y, b_x, b_y)
   ((b_x - a_x)**2 + (b_y - a_y)**2)**(1/2.0)
end


puts "Coordinates of Mr. A(x, y)Please enter two half-width numbers with a half-width space in between."
print "Mr. A's coordinates are? "
a_x, a_y = gets.split.map(&:to_i)

puts "Mr. B's coordinates(x, y)Please enter two half-width numbers with a half-width space in between."
print "Mr. B's coordinates are? "
b_x, b_y = gets.split.map(&:to_i)

if a_x == b_x && a_y == b_y
  puts "The two are in the same place."
  exit
end

direction = compass(degree(b_x - a_x, b_y - a_y))
distance = distance(a_x, a_y, b_x, b_y).round(1)

puts "Mr. B sees from Mr. A#{direction}In the direction of#{distance}m away."
#Within 2 meters is dense
distance > 2 ? (puts "Social distance is maintained.") : (puts "It's dense!")

Output result

Mr. A(3,-2), B(-2,-4)in the case of


Coordinates of Mr. A(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. A's coordinates are? 3 -2
Mr. B's coordinates(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. B's coordinates are? -2 -4

↓ Result ↓

Mr. B is in the southwest direction as seen from Mr. A, 5.4m away.
Social distance is maintained.

Mr. A(-1,-7), B(1,-7)in the case of


Coordinates of Mr. A(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. A's coordinates are? -1 -7
Mr. B's coordinates(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. B's coordinates are? 1 -7

↓ Result ↓

Mr. B is in the east direction from Mr. A, 2.It is 0m away.
It's dense!

Mr. A(4,3), B(4,3)in the case of


Coordinates of Mr. A(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. A's coordinates are? 4 3
Mr. B's coordinates(x, y)Please enter two half-width numbers with a half-width space in between.
Mr. B's coordinates are? 4 3

↓ Result ↓

The two are in the same place.

As mentioned above, "Minimum knowledge required when dealing with" angles "and" coordinates "in Ruby + In what direction is Mr. B from the perspective of Mr. A? It was "algorithm". Thank you for visiting!

Recommended Posts

Minimum knowledge required when dealing with "angles" and "coordinates" in Ruby + In what direction is Mr. B from the perspective of Mr. A? Algorithm
[Python] Precautions when finding the maximum and minimum values in a numpy array with a small number of elements
What to do when a part of the background image becomes transparent when the transparent image is combined with Pillow
[Python] What to do when PEP8 is violated in the process of importing from the directory added to sys.path
[CleanArchitecture with Python] Apply CleanArchitecture step by step to a simple API and try to understand "what kind of change is strong" in the code base.
Calculate the shortest route of a graph with Dijkstra's algorithm and Python
What I investigated in the process of expressing (schematicizing) containers in a nested frame with Jupyter and making it
Function to extract the maximum and minimum values ​​in a slice with Go