Let's implement the condition that the circumference and the inside of the Ougi shape are included in Java [Part 2]

Added at 7:00 on December 12th We have corrected the mistakes pointed out in the comments. (We did not consider the case where the minimum orientation of the surveillance camera is less than 0 ° and the maximum is 360 ° or more) I am very sorry that I posted it with insufficient verification.

1. 1. Synopsis of the first part

We have created a surveillance camera that is not bound by common sense and allows people to pass through in front of them.

The program that appeared at the end of the first part (click to open)
import java.util.Scanner;

class CameraTest {
    public static void main(String[] args) {
        //input
        Scanner sc = new Scanner(System.in);
        //player
        double px = sc.nextDouble();    //Player x coordinate
        double py = sc.nextDouble();    //Player y coordinate
        Player player = new Player(px, py);
        //Surveillance camera
        int N = sc.nextInt();       //Number of surveillance cameras
        for (int n = 0; n < N; n ++) {
            //Input / processing for each surveillance camera
            double x = sc.nextDouble(); //X coordinate of surveillance camera
            double y = sc.nextDouble(); //Y coordinate of surveillance camera
            double d = sc.nextDouble(); //Distance visible to surveillance cameras
            double e = sc.nextDouble(); //Direction of surveillance camera(direction)Angle representing
            double f = sc.nextDouble(); //Viewing angle of surveillance camera
            Camera camera = new Camera(x, y, d, e, f);
            if (camera.findPlayer(player)) {
                System.out.println("I was able to see");
            } else {
                System.out.println("I couldn't see");
            }
        }
        sc.close();
    }
}

class Player {
    private double x; //Player x coordinate
    private double y; //Player y coordinate

    public Player(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public double getX() {
        return this.x;
    }
    public double getY() {
        return this.y;
    }
}

class Camera {
    private double x;   //X coordinate of surveillance camera
    private double y;   //Y coordinate of surveillance camera
    private double distance;    //Distance visible to surveillance cameras
    private double dirAngle;    //Direction of surveillance camera(direction)Angle representing
    private double viewAngle;   //Viewing angle of surveillance camera

    public Camera(double x, double y, double d, double e, double f) {
        this.x = x;
        this.y = y;
        this.distance = d;
        this.dirAngle = e;
        this.viewAngle = f;
    }
    public boolean findPlayer(Player player) {
        double px = player.getX();
        double py = player.getY();

        //Judgment by distance
        double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
        if (d > this.distance) {
            return false;
        }

        //Judgment by angle
        double a = Math.toDegrees(Math.atan2(py - this.y, px - this.x));
        double aMin = this.dirAngle - this.viewAngle/2;
        double aMax = this.dirAngle + this.viewAngle/2;
        if (a < aMin || aMax < a) {
            return false;
        }

        return true;
    }
}

2. debug

Problem # 1

The biggest evil __ in programming this time was that I used the library in an ambiguous manner without careful examination. Don't get me wrong, it's not a bad thing to use a library (rather, it's much more efficient to use it than to create your own weird methods). __ It's bad to use it without looking it up __. Let's see specifically which part was evil. To conclude, it is the part that uses the atan2 method of the library in the judgment by the angle in the findPlayer method of the Camera class. Let's pay attention to the return value of this method.

What kind of method is the atan2 method?

From the Oracle website * The appearance has been slightly changed to make it easier to read. https://docs.oracle.com/javase/jp/1.4/api/java/lang/Math.html#atan2(double,%20double)

public static double atan2 (double y, double x) (click to open)
Convert Cartesian coordinates (x, y) to polar coordinates (r, theta). This method calculates the arctangent of y / x in the range __-pi to pi __ to find the phase theta. As a special case

-If either argument is NaN, the result is NaN. -If the first argument is positive zero and the second argument is positive, or the first argument is positive finite and the second argument is positive infinity, the result is positive zero. -If the first argument is negative zero and the second argument is positive, or the first argument is negative finite and the second argument is positive infinity, the result is negative zero. -If the first argument is positive zero and the second argument is negative, or the first argument is positive finite and the second argument is negative infinity, the result is a double value that is closest to pi. Become. -If the first argument is negative zero and the second argument is negative, or the first argument is negative finite and the second argument is negative infinity, the result is a double value that is closest to -pi. Will be. -If the first argument is positive and the second argument is positive or negative zero, or the first argument is positive infinity and the second argument is finite, the result is double, which is the closest approximation to pi / 2. It will be a value. -If the first argument is negative and the second argument is positive or negative zero, or the first argument is negative infinity and the second argument is finite, the result is closest to -pi / 2. It has a double value. -If both arguments are positive infinity, the result is a double value that is the closest approximation to pi / 4. -If the first argument is positive infinity and the second argument is negative infinity, the result is a double value that is closest to 3 * pi / 4. -If the first argument is negative infinity and the second argument is positive infinity, the result is a double value that is closest to -pi / 4. -If both arguments are negative infinity, the result is a double value that is the closest approximation to -3 * pi / 4.

The result must be within 2 ulps of the correctly rounded result. Results are limited to semi-monotonous.

__ Parameters: __ y --Vertical coordinates x --Abscissa Return value: Theta component of a point (r, theta) on polar coordinates that corresponds to a point (x, y) on Cartesian coordinates (Descartes)

The point is that if you just use the inverse function of tan (atan method of the library), you can only know the __direction __ [^ 1] of the vector with the $ x $ and $ y $ components of the argument. You also need to look at the sign of each component to find out the __direction __ [^ 1] of the vector. The atan2 method implements such a wonderful process. [^ 1]: In the world of mathematics and physics, there is a clear distinction between "direction" and "direction". As a rough example, if there is a road connecting two points, the road itself is the "direction", and the distinction between the lane you are in and the opposite lane is the "direction" (north-south "direction", or It's called "direction" in the north and "direction" in the south).

The most important part is the return value shown in bold red, and the range from -pi to pi is the angle expressed by the radian method [^ 2], which is converted to the pi method [^ 2]. When converted (library toDegrees method), it becomes -180 ° to 180 °. If you look a little more closely, when the $ x $ component is -1 and the $ y $ component is 0, the value returned from the atan2 method is converted to the frequency method by the toDegrees method, and it becomes 180.0, so it seems to be facing left. Seems to be 180 ° instead of -180 ° for the vector of. In other words, it will return a value greater than __-180 ° and less than 180 ° __. [^ 2]: Roughly speaking, the arc degree method is the one in which the central angle of the goose shape with a radius of 1 and the arc length of 1 is determined to be 1 radian, and the frequency method is the one we usually use, 1 The circumference is set to 360 °. Since the circumference of radius 1 is 2 $ \ pi $, the 2 $ \ pi $ radians represent an angle as large as 360 °.

I finally got to the core. I first decided that the viewing angle of the surveillance camera would be __0 ° or more and less than 360 ° __. However, the orientation of the player obtained by the program was greater than __-180 ° and less than 180 ° __. In fact, let's use the example that failed last time to check while also displaying the angle that represents the player's orientation.

quiita_おうぎ形4.png

10 16 8 270 120
a = -90.0
aMin = 210.0, aMax = 330.0
I couldn't see

I see. The surveillance camera covers the range of 210 ° or more and 330 ° or less, but the player is calculated as an angle outside the range, so it was passed through. Now let's consider what to do when the angle representing the player's orientation is outside the viewing angle of the surveillance camera, that is, greater than __-180 ° and less than 0 ° __. In the first place, negative angles are rarely used in everyday life, so some people may be overwhelmed, but once the principle is understood, it is not so difficult. Simply put, it's just a positive angle when it's rotated counterclockwise, and a negative angle when it's rotated clockwise. For example, rotating 90 ° clockwise is ultimately the same as rotating 270 ° counterclockwise. The position rotated by -90 ° is the same as the position rotated by 270 °. Therefore, if it is larger than __-180 ° and less than 0 °, the correct answer is to add 360 ° and correct it to the range of 0 ° or more and less than 360 °.

Problem # 2

Now that we have verified the angle that represents the orientation of the player, the next step is the orientation of the surveillance camera. For example, consider the following example.

  1. If the orientation of the surveillance camera is 10 ° and the viewing angle is 60 °, the range of orientation of the surveillance camera will be -20 ° to 40 °, so the range of orientation of the surveillance camera should be 0 ° to 40 °. It is necessary to judge by dividing into two, 340 ° to 360 °.
  2. If the orientation of the surveillance camera is 350 ° and the viewing angle is 60 °, the range of orientation of the surveillance camera will be 320 ° to __380 ° __, so the range of orientation of the surveillance camera will be 320 ° to 360 °. It is necessary to judge by dividing into two, 0 ° to 20 °.

…… I have a headache just thinking about it, but I can't avoid it. You need to add some processing so that you can determine if the player is visible even if it is less than 0 ° or more than 360 °. Now, in the findPlayer method, rewrite the part that makes the judgment by angle as follows.

	public boolean findPlayer(Player player) {

		//Omission

		//Judgment by angle
		double a = Math.toDegrees(Math.atan2(py - this.y, px - this.x));
		if (a < 0) {
			a += 360.0;
		}
		System.out.println("a = " + a);
		double aMin = this.dirAngle - this.viewAngle/2;
		if (aMin < 0.0) {
			//When the minimum camera orientation is negative, aMin+Determine if it is visible in the range of 360 to 360
			aMin += 360;
			if (aMin <= a && a < 360.0) {
				return true;
			}
			//After that, aMin+You don't have to think about the range of 360-360
			aMin = 0.0;
		}
		double aMax = this.dirAngle + this.viewAngle/2;
		if (aMax >= 360.0) {
			//0 to aMax when the maximum camera orientation is 360 or more-Determine if it is visible in the 360 range
			aMax -= 360.0;
			if (0.0 <= a && a <= aMax) {
				return true;
			}
			//After that, 0 to aMax-You don't have to think about the 360 range
			aMax = 360.0;
		}
		System.out.println("aMin = " + aMin + ", aMax = " + aMax);
		if (aMin <= a && a <= aMax) {
			return true;
		}
		return false;
	}

As explained in Problem 1, after finding the orientation of the player (variable a), if the value is negative, add 360. This ensures that the player's orientation is always greater than or equal to 0 ° and less than 360 °. Next, after finding the minimum orientation of the camera (variable aMin), if the value is less than 0 °, first determine whether the player can be seen within the range of aMin + 360 ° or more and less than 360 °, and if it can be seen, true. Returns (skips the rest of the process). If it is not visible, it is necessary to judge the remaining range, so the process continues. Since it is no longer necessary to think about the range of aMin + 360 ° or more and less than 360 °, aMin is set to 0 °. As a result, it will be judged later even in the range of 0 ° or more and aMax or less. The same applies to the maximum camera orientation (variable aMax).

3. 3. Complete

It is a program that reflects the verification so far. It was long ……… ~~ Actually, it was a more detour ~~

Reborn player visibility program (click to open)
import java.util.Scanner;

class CameraTest {
	public static void main(String[] args) {
		//input
		Scanner sc = new Scanner(System.in);
		//player
		double px = sc.nextDouble();	//Player x coordinate
		double py = sc.nextDouble();	//Player y coordinate
		Player player = new Player(px, py);
		//Surveillance camera
		int N = sc.nextInt();		//Number of surveillance cameras
		for (int n = 0; n < N; n ++) {
			//Input / processing for each surveillance camera
			double x = sc.nextDouble();	//X coordinate of surveillance camera
			double y = sc.nextDouble();	//Y coordinate of surveillance camera
			double d = sc.nextDouble();	//Distance visible to surveillance cameras
			double e = sc.nextDouble();	//Direction of surveillance camera(direction)Angle representing
			double f = sc.nextDouble();	//Viewing angle of surveillance camera
			Camera camera = new Camera(x, y, d, e, f);
			if (camera.findPlayer(player)) {
				System.out.println("I was able to see");
			} else {
				System.out.println("I couldn't see");
			}
		}
		sc.close();
	}
}

class Player {
	private double x; //Player x coordinate
	private double y; //Player y coordinate

	public Player(double x, double y) {
		this.x = x;
		this.y = y;
	}
	public double getX() {
		return this.x;
	}
	public double getY() {
		return this.y;
	}
}

class Camera {
	private double x;	//X coordinate of surveillance camera
	private double y;	//Y coordinate of surveillance camera
	private double distance;	//Distance visible to surveillance cameras
	private double dirAngle;	//Direction of surveillance camera(direction)Angle representing
	private double viewAngle;	//Viewing angle of surveillance camera

	public Camera(double x, double y, double d, double e, double f) {
		this.x = x;
		this.y = y;
		this.distance = d;
		this.dirAngle = e;
		this.viewAngle = f;
	}
	public boolean findPlayer(Player player) {
		double px = player.getX();
		double py = player.getY();

		//Judgment by distance
		double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
		if (d > this.distance) {
			return false;
		}

		//Judgment by angle
		double a = Math.toDegrees(Math.atan2(py - this.y, px - this.x));
		if (a < 0) {
			a += 360.0;
		}
		System.out.println("a = " + a);
		double aMin = this.dirAngle - this.viewAngle/2;
		if (aMin < 0.0) {
			//When the minimum camera orientation is negative, aMin+Determine if it is visible in the range of 360 to 360
			aMin += 360;
			System.out.println("aMin = " + aMin + ", aMax = 360.0");
			if (aMin <= a && a < 360.0) {
				return true;
			}
			//After that, aMin+You don't have to think about the range of 360-360
			aMin = 0.0;
		}
		double aMax = this.dirAngle + this.viewAngle/2;
		if (aMax >= 360.0) {
			//0 to aMax when the maximum camera orientation is 360 or more-Determine if it is visible in the 360 range
			aMax -= 360.0;
			System.out.println("aMin = 0.0, aMax = " + aMax);
			if (0.0 <= a && a <= aMax) {
				return true;
			}
			//After that, 0 to aMax-You don't have to think about the 360 range
			aMax = 360.0;
		}
		System.out.println("aMin = " + aMin + ", aMax = " + aMax);
		if (aMin <= a && a <= aMax) {
			return true;
		}
		return false;
	}
}

In the findPlayer method, when the value of the variable a that stores the angle indicating the direction of the player is negative, we just added the process of adding 360. And the revenge result.

10 16 8 270 120
a = 270.0
aMin = 210.0, aMax = 330.0
I was able to see

It's perfect!

4. This lesson

It's hard to mention, but this time I'll write about the points that I especially pulled.

Be sure to check the specifications when using something made by others!

This is the biggest reflection point. I learned about the atan2 method a long time ago, and this time I used it for the first time in a while, but the return value was completely passed through. Rather, I was convinced that it would return at 0 ° or more and less than 360 °. Also, because I was convinced, it took me a long time to notice the cause. To confess further, it is correct to assign the arguments of the atan2 method in the order of $ y $ component and $ x $ component, but at the beginning I put it in the opposite direction. It's a lot. It would be scary to think that this was a development site. The compiler passed, but it didn't do the right thing, I believe I was right ... It's a catastrophe. Of course, I'm responsible for it, so I can't make any excuses. So, when you use something made by someone else, be sure to check the __ specification __. As for the atan2 method this time, we need to find out what is in the argument, what the return value is, or what range it is. At that time, try to eliminate all your assumptions.

Be sure to clarify the specifications when you want others to use what you have made!

This is a lesson for the future. When developing with a team of multiple people, it is necessary to properly organize what kind of input the program in charge is supposed to be, what kind of processing is performed, and what kind of result is output. There is. There are various rules depending on the site, such as leaving it as a comment in the program you wrote or saving it as a separate document, but be sure to leave it in any form (yourself). Even the ones made by will be forgotten over time!). Otherwise, it will cause a great deal of trouble to your teammates.

5. At the end

The other day, after posting the first part of the article, I learned a lot from the comments that I didn't know about methods and processing methods. I will continue to post articles on Qiita, and I will do my best so that I can give advice in the future. Thank you for reading this far.

Recommended Posts

Let's implement the condition that the circumference and the inside of the Ougi shape are included in Java [Part 2]
Let's implement the condition that the circumference and the inside of the Ougi shape are included in Java [Part 1]
This and that of the implementation of date judgment within the period in Java
[Java] The confusing part of String and StringBuilder
[Android 9.0 Pie Java] Implement setOnTouchListener in the margin of RecyclerView and close the soft keyboard
[Java] What to do if the contents saved in the DB and the name of the enum are different in the enum that reflects the DB definition
Shout Java at the heart of technology-Themes and elemental technologies that Java engineers should pursue in 2017-
JSON in Java and Jackson Part 1 Return JSON from the server
Identify threads in the Java process that are wasting CPU
[Java] Get the dates of the past Monday and Sunday in order
Let's create a TODO application in Java 5 Switch the display of TODO
This and that of the JDK
A collection of phrases that impresses the "different feeling" of Java and JavaScript
Specify the order in which configuration files and classes are loaded in Java
The problem that the contents of params are completely displayed in the [Rails] view
The story of forgetting to close a file in Java and failing
Let's think about what declarative programming is in Java and Elm (Part 1)
Sample program that returns the hash value of a file in Java
Find the maximum and minimum of the five numbers you entered in Java
Review of "strange Java" and Java knowledge that is often forgotten in Java Bronze
[Java] Implement a function that uses a class implemented in the Builder pattern
[Introduction to Computer Science Part 1: Let's try machine learning] Let's implement k-means clustering in Java-About the concept of coordinates-
Get the result of POST in Java
What are the updated features of java 13
The story of writing Java in Emacs
Discrimination of Enums in Java 7 and above
I received the data of the journey (diary application) in Java and visualized it # 001
[Java] Where is the implementation class of annotation that exists in Bean Validation?
Let's refer to C ++ in the module of AndroidStudio other project (Java / kotlin)
Code that deletes all files of the specified prefix in AWS S3 (Java)
10 barrages of drawing with ● or ■ that are likely to appear in training (Java)