Implémentons la condition que la circonférence et l'intérieur de la forme Ougi soient inclus dans Java [Partie 2]

Ajouté à 7h00 le 12 décembre Nous avons corrigé les erreurs signalées dans les commentaires. (Nous n'avons pas considéré le cas où l'orientation minimum de la caméra de surveillance est inférieure à 0 ° et le maximum est de 360 ° ou plus) Je suis vraiment désolé de l'avoir publié avec une vérification insuffisante.

1. 1. Synopsis de la première partie

Nous avons créé une caméra de surveillance qui n'est pas liée au bon sens et qui permet aux gens de passer devant eux.

Le programme qui est apparu à la fin de la première partie (cliquez pour ouvrir)
import java.util.Scanner;

class CameraTest {
    public static void main(String[] args) {
        //contribution
        Scanner sc = new Scanner(System.in);
        //joueur
        double px = sc.nextDouble();    //Coordonnées du joueur x
        double py = sc.nextDouble();    //Coordonnées du joueur y
        Player player = new Player(px, py);
        //Caméra de surveillance
        int N = sc.nextInt();       //Nombre de caméras de surveillance
        for (int n = 0; n < N; n ++) {
            //Entrée / traitement pour chaque caméra de surveillance
            double x = sc.nextDouble(); //Coordonnées X de la caméra de surveillance
            double y = sc.nextDouble(); //Caméra de surveillance coordonnée y
            double d = sc.nextDouble(); //Distance que la caméra de surveillance peut voir
            double e = sc.nextDouble(); //Orientation de la caméra de surveillance(direction)Angle représentant
            double f = sc.nextDouble(); //Angle de vision de la caméra de surveillance
            Camera camera = new Camera(x, y, d, e, f);
            if (camera.findPlayer(player)) {
                System.out.println("J'ai pu voir");
            } else {
                System.out.println("Je ne pouvais pas voir");
            }
        }
        sc.close();
    }
}

class Player {
    private double x; //Coordonnées du joueur x
    private double y; //Coordonnée y du joueur

    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;   //Coordonnées X de la caméra de surveillance
    private double y;   //Caméra de surveillance coordonnée y
    private double distance;    //Distance que la caméra de surveillance peut voir
    private double dirAngle;    //Orientation de la caméra de surveillance(direction)Angle représentant
    private double viewAngle;   //Angle de vision de la caméra de surveillance

    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();

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

        //Jugement par 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. déboguer

Problème n ° 1

Le plus gros inconvénient de __ dans cette programmation est que j'ai utilisé la bibliothèque de manière ambiguë sans même l'examiner. Ne vous méprenez pas, ce n'est pas mal d'utiliser une bibliothèque (c'est plutôt beaucoup plus efficace de l'utiliser que de créer vos propres méthodes étranges). __ Il est mauvais de l'utiliser sans le chercher __. Voyons précisément quelle partie était mauvaise. Pour conclure, c'est la partie qui utilise la méthode atan2 de la librairie dans le jugement par l'angle dans la méthode findPlayer de la classe Camera. Faisons attention à la valeur de retour de cette méthode.

Quel type de méthode est la méthode atan2?

Depuis le site Web d'Oracle * L'apparence a été légèrement modifiée pour en faciliter la lecture. https://docs.oracle.com/javase/jp/1.4/api/java/lang/Math.html#atan2(double,%20double)

<détails>

double atan2 statique public (double y, double x) (cliquez pour ouvrir) </ summary>
Convertit les coordonnées orthogonales (x, y) en coordonnées polaires (r, thêta). Cette méthode calcule la tangente inverse (arc tangente) de y / x dans la plage __- pi à pi __ </ font> pour trouver la phase thêta. Comme cas particulier

-Si l'un des arguments est NaN, le résultat est NaN. -Si le premier argument est zéro positif et le deuxième argument est positif, ou si le premier argument est fini positif et le deuxième argument est l'infini positif, le résultat est zéro positif. -Si le premier argument est zéro négatif et le deuxième argument est positif, ou le premier argument est fini négatif et le deuxième argument est l'infini positif, le résultat est zéro négatif. -Si le premier argument est zéro positif et le deuxième argument est négatif, ou le premier argument est fini positif et le deuxième argument est l'infini négatif, le résultat est une valeur double qui ressemble le plus à pi. Devenir. -Si le premier argument est zéro négatif et le deuxième argument est négatif, ou le premier argument est fini négatif et le deuxième argument est l'infini négatif, le résultat est une valeur double qui ressemble le plus à -pi. Sera. -Si le premier argument est positif et le deuxième argument est zéro positif ou négatif, ou le premier argument est l'infini positif et le deuxième argument est fini, le résultat est un double qui ressemble le plus à pi / 2. Ce sera une valeur. -Si le premier argument est négatif et le deuxième argument est zéro positif ou négatif, ou le premier argument est l'infini négatif et le deuxième argument est fini, le résultat est le plus proche de -pi / 2. Ce sera une valeur double. -Si les deux arguments sont positifs à l'infini, le résultat est une valeur double la plus proche de pi / 4. -Si le premier argument est l'infini positif et le second argument est l'infini négatif, le résultat sera la valeur double la plus proche de 3 * pi / 4. -Si le premier argument est l'infini négatif et le second argument est l'infini positif, le résultat sera la valeur double la plus proche de -pi / 4. -Si les deux arguments sont négatifs à l'infini, le résultat est une valeur double plus proche de -3 * pi / 4.

Le résultat doit être à moins de 2 ulp du résultat correctement arrondi. Les résultats sont limités à semi-monotones.

__ Paramètres: __ y - Coordonnées verticales coordonnées x-horizontales __Valeur de retour: __ Composante thêta du point (r, thêta) sur les coordonnées polaires correspondant au point (x, y) sur les coordonnées orthogonales (coordonnées de décart)

Le fait est que si vous utilisez simplement la fonction inverse de tan (méthode atan de la bibliothèque), vous ne pouvez connaître que la __direction __ [^ 1] du vecteur avec le composant $ x $ et le composant $ y $ de l'argument. Vous devez également regarder le signe de chaque composant pour connaître la __direction __ [^ 1] du vecteur. La méthode atan2 met en œuvre un processus aussi merveilleux. [^ 1]: Dans le monde des mathématiques et de la physique, il y a une distinction claire entre «direction» et «direction». À titre d'exemple approximatif, s'il y a une route reliant deux points, la route elle-même est la "direction", et la distinction entre la voie dans laquelle vous vous trouvez et la voie opposée est la "direction" ("direction" nord-sud, etc. On l'appelle «direction» au nord et «direction» au sud).

La partie la plus importante est la valeur de retour affichée en rouge gras, et la plage de -pi à pi est l'angle exprimé par la méthode du degré d'arc [^ 2], qui est convertie en méthode de fréquence [^ 2]. Une fois converti (méthode toDegrees de la librairie), il passe de -180 ° à 180 °. Si vous regardez d'un peu plus près, lorsque le composant $ x $ vaut -1 et le composant $ y $ vaut 0, la valeur renvoyée par la méthode atan2 est convertie en méthode de fréquence par la méthode toDegrees, et devient 180,0, donc elle semble être tournée vers la gauche. Semble être 180 ° au lieu de -180 ° pour le vecteur de. En d'autres termes, il renverra une valeur supérieure à __- 180 ° et inférieure à 180 ° __. [^ 2]: Grosso modo, la méthode du degré d'arc est celle qui détermine l'angle central de la forme d'oie avec un rayon de 1 et la longueur de l'arc de 1 comme 1 radian, et la méthode de la fréquence est celle que nous utilisons habituellement, 1 La circonférence est réglée sur 360 °. Puisque la circonférence du rayon 1 est 2 $ \ pi $, le radian 2 $ \ pi $ représente un angle aussi grand que 360 °.

Je suis enfin arrivé au cœur. J'ai d'abord décidé que l'angle de vision de la caméra de surveillance était de __0 ° ou plus et inférieur à 360 ° __. Cependant, l'orientation du joueur obtenue par le programme était supérieure à __- 180 ° et inférieure à 180 ° __. En fait, utilisons l'exemple qui a échoué la dernière fois pour vérifier tout en affichant également l'angle qui représente l'orientation du joueur.

quiita_おうぎ形4.png

10 16 8 270 120
a = -90.0
aMin = 210.0, aMax = 330.0
Je ne pouvais pas voir

Je vois. La caméra de surveillance couvre la plage de 210 ° ou plus et 330 ° ou moins, mais le joueur est calculé comme un angle en dehors de la plage, il a donc été traversé. Voyons maintenant ce qu'il faut faire lorsque l'angle représentant l'orientation du joueur est en dehors de l'angle de vue de la caméra de surveillance, c'est-à-dire supérieur à __- 180 ° et inférieur à 0 ° __. En premier lieu, comme les angles négatifs sont rarement utilisés dans la vie quotidienne, certaines personnes peuvent être dépassées, mais une fois le principe compris, ce n'est pas si difficile. En termes simples, il s'agit simplement d'un angle positif lorsqu'il est tourné dans le sens antihoraire et d'un angle négatif lorsqu'il est tourné dans le sens horaire. Par exemple, une rotation de 90 ° dans le sens horaire équivaut finalement à une rotation de 270 ° dans le sens antihoraire. La position tournée de -90 ° est la même que la position tournée de 270 °. Par conséquent, s'il est supérieur à __- 180 ° et inférieur à 0 °, la bonne réponse est d'ajouter 360 ° et de le corriger dans la plage de 0 ° ou plus et de moins de 360 °.

Problème n ° 2

Maintenant que nous avons vérifié l'angle qui représente l'orientation du joueur, l'étape suivante est l'orientation de la caméra de surveillance. Par exemple, considérons l'exemple suivant.

  1. Si l'orientation de la caméra de surveillance est de 10 ° et l'angle de vue est de 60 °, la plage d'orientation de la caméra de surveillance sera de -20 ° à 40 °, donc la plage d'orientation de la caméra de surveillance doit être de 0 ° à 40 °. Il faut juger en divisant en deux, de 340 ° à 360 °.
  2. Si l'orientation de la caméra de surveillance est de 350 ° et l'angle de vue est de 60 °, la plage d'orientation de la caméra de surveillance sera de 320 ° à __380 ° __, donc la plage d'orientation de la caméra de surveillance sera de 320 ° à 360 °. Il faut juger en divisant en deux, de 0 ° à 20 °.

...... J'ai mal à la tête rien qu'en y pensant, mais je ne peux pas l'éviter. Un traitement doit être ajouté afin de pouvoir déterminer si le joueur peut être vu même s'il est inférieur à 0 ° ou supérieur à 360 °. Maintenant, dans la méthode findPlayer, réécrivez la partie qui fait le jugement en fonction de l'angle comme suit.

	public boolean findPlayer(Player player) {

		//Omission

		//Jugement par 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) {
			//Lorsque l'orientation minimale de la caméra est négative, aMin+Déterminez s'il est visible dans la plage de 360 à 360
			aMin += 360;
			if (aMin <= a && a < 360.0) {
				return true;
			}
			//Après cela, aMin+Vous n'avez pas à penser à la gamme de 360-360
			aMin = 0.0;
		}
		double aMax = this.dirAngle + this.viewAngle/2;
		if (aMax >= 360.0) {
			//0 à aMax lorsque l'orientation maximale de la caméra est de 360 ou plus-Déterminez s'il est visible dans la plage 360
			aMax -= 360.0;
			if (0.0 <= a && a <= aMax) {
				return true;
			}
			//Après cela, 0 à aMax-Vous n'avez pas à penser à la gamme 360
			aMax = 360.0;
		}
		System.out.println("aMin = " + aMin + ", aMax = " + aMax);
		if (aMin <= a && a <= aMax) {
			return true;
		}
		return false;
	}

Comme expliqué dans le problème 1, après avoir trouvé l'orientation du joueur (variable a), si la valeur est négative, ajoutez 360. Cela garantit que l'orientation du joueur est toujours supérieure ou égale à 0 ° et inférieure à 360 °. Ensuite, après avoir trouvé l'orientation minimale de la caméra (variable aMin), si la valeur est inférieure à 0 °, déterminez d'abord si le joueur peut être vu dans la plage de aMin + 360 ° ou plus et moins de 360 °, et s'il peut être vu, vrai. Renvoie (ignore le reste du processus). S'il n'est pas visible, il est nécessaire de juger de la plage restante pour que le processus se poursuive. Puisqu'il n'est plus nécessaire de considérer la plage de aMin + 360 ° ou plus et inférieure à 360 °, aMin est réglé sur 0 °. En conséquence, il sera jugé plus tard, même dans la plage de 0 ° ou plus et aMax ou moins. Il en va de même pour l'orientation maximale de la caméra (variable aMax).

3. 3. Achevée

C'est un programme qui reflète la vérification jusqu'à présent. C'était long ……… ~~ En fait, c'était un plus détour ~~

<détails>

Programme de visibilité des joueurs Reborn (cliquez pour ouvrir) </ summary>

import java.util.Scanner;

class CameraTest {
	public static void main(String[] args) {
		//contribution
		Scanner sc = new Scanner(System.in);
		//joueur
		double px = sc.nextDouble();	//Coordonnées du joueur x
		double py = sc.nextDouble();	//Coordonnées du joueur y
		Player player = new Player(px, py);
		//Caméra de surveillance
		int N = sc.nextInt();		//Nombre de caméras de surveillance
		for (int n = 0; n < N; n ++) {
			//Entrée / traitement pour chaque caméra de surveillance
			double x = sc.nextDouble();	//Coordonnées X de la caméra de surveillance
			double y = sc.nextDouble();	//Caméra de surveillance coordonnée y
			double d = sc.nextDouble();	//Distance que la caméra de surveillance peut voir
			double e = sc.nextDouble();	//Orientation de la caméra de surveillance(direction)Angle représentant
			double f = sc.nextDouble();	//Angle de vision de la caméra de surveillance
			Camera camera = new Camera(x, y, d, e, f);
			if (camera.findPlayer(player)) {
				System.out.println("J'ai pu voir");
			} else {
				System.out.println("Je ne pouvais pas voir");
			}
		}
		sc.close();
	}
}

class Player {
	private double x; //Coordonnées du joueur x
	private double y; //Coordonnée y du joueur

	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;	//Coordonnées X de la caméra de surveillance
	private double y;	//Caméra de surveillance coordonnée y
	private double distance;	//Distance que la caméra de surveillance peut voir
	private double dirAngle;	//Orientation de la caméra de surveillance(direction)Angle représentant
	private double viewAngle;	//Angle de vision de la caméra de surveillance

	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();

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

		//Jugement par 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) {
			//Lorsque l'orientation minimale de la caméra est négative, aMin+Déterminez s'il est visible dans la plage de 360 à 360
			aMin += 360;
			System.out.println("aMin = " + aMin + ", aMax = 360.0");
			if (aMin <= a && a < 360.0) {
				return true;
			}
			//Après cela, aMin+Vous n'avez pas à penser à la gamme de 360-360
			aMin = 0.0;
		}
		double aMax = this.dirAngle + this.viewAngle/2;
		if (aMax >= 360.0) {
			//0 à aMax lorsque l'orientation maximale de la caméra est de 360 ou plus-Déterminez s'il est visible dans la plage 360
			aMax -= 360.0;
			System.out.println("aMin = 0.0, aMax = " + aMax);
			if (0.0 <= a && a <= aMax) {
				return true;
			}
			//Après cela, 0 à aMax-Vous n'avez pas à penser à la gamme 360
			aMax = 360.0;
		}
		System.out.println("aMin = " + aMin + ", aMax = " + aMax);
		if (aMin <= a && a <= aMax) {
			return true;
		}
		return false;
	}
}

Dans la méthode findPlayer, lorsque la valeur de la variable a qui stocke l'angle indiquant la direction du joueur est négative, nous venons d'ajouter le processus d'ajout de 360. Et le résultat de la vengeance.

10 16 8 270 120
a = 270.0
aMin = 210.0, aMax = 330.0
J'ai pu voir

C'est parfait!

4. Cette leçon

C'est difficile à mentionner, mais cette fois, j'écrirai sur les points que j'ai particulièrement tirés.

Assurez-vous de vérifier les spécifications lorsque vous utilisez quelque chose de fabriqué par d'autres!

C'est le plus gros point de réflexion. J'ai appris la méthode atan2 il y a longtemps, et cette fois je l'ai utilisée pour la première fois depuis un moment, mais la valeur de retour a été complètement transmise. Au contraire, j'étais convaincu qu'il reviendrait à 0 ° ou plus et à moins de 360 °. Aussi, parce que j'étais convaincu, il m'a fallu beaucoup de temps pour remarquer la cause. Pour avouer plus loin, il est correct d'assigner les arguments de la méthode atan2 dans l'ordre du composant $ y $ et du composant $ x $, mais au début je les mets dans la direction opposée. C'est beaucoup. Il serait effrayant de penser qu'il s'agissait d'un site de développement. Le compilateur a réussi, mais il n'a pas fait la bonne chose, je crois que j'avais raison ... C'est une catastrophe. Bien sûr, j'en suis responsable, donc je ne peux trouver aucune excuse. Ainsi, lorsque vous utilisez quelque chose de fabriqué par quelqu'un d'autre, assurez-vous de vérifier la spécification __ __. En ce qui concerne la méthode atan2 cette fois, il est nécessaire de savoir ce qui est inclus dans l'argument, le type de valeur de la valeur de retour ou la plage. À ce moment-là, essayez d'éliminer toutes vos hypothèses.

Assurez-vous de clarifier les spécifications lorsque vous souhaitez que d'autres utilisent ce que vous avez fait!

C'est une leçon pour l'avenir. Lors du développement avec une équipe de plusieurs personnes, il est nécessaire d'organiser correctement le type d'entrée que le programme en charge est censé être, le type de traitement effectué et le type de résultat obtenu. Il y a. Je pense qu'il existe différentes règles en fonction du site, que ce soit pour le laisser en commentaire dans le programme que j'ai écrit ou le sauvegarder en tant que document séparé, mais assurez-vous de le laisser sous n'importe quelle forme (vous-même) Même ceux fabriqués par seront oubliés avec le temps!). Sinon, cela causera beaucoup de problèmes à vos coéquipiers.

5. À la fin

L'autre jour, après avoir publié la première partie de l'article, j'ai beaucoup appris des commentaires que je ne connaissais pas sur les méthodes et les méthodes de traitement. Je continuerai à publier des articles sur Qiita, et je ferai de mon mieux pour pouvoir donner des conseils à l'avenir. Merci d'avoir lu jusqu'ici.

Recommended Posts

Implémentons la condition que la circonférence et l'intérieur de la forme Ougi soient inclus dans Java [Partie 2]
Implémentons la condition que la circonférence et l'intérieur de la forme Ougi soient inclus dans Java [Partie 1]
Ceci et cela de la mise en œuvre du jugement en temps réel des dates en Java
[Java] La partie déroutante de String et StringBuilder
[Android 9.0 Pie Java] Implémentez setOnTouchListener dans la marge de RecyclerView et fermez le clavier virtuel
[Java] Que faire si le contenu enregistré dans la base de données et le nom de l’énumération sont différents dans l’énumération qui reflète la définition de la base de données
Crier Java au cœur des technologies-Thèmes et technologies élémentaires que les ingénieurs Java devraient poursuivre en 2017-
JSON en Java et Jackson Partie 1 Renvoyer JSON à partir du serveur
Identifiez les threads du processus Java qui gaspillent du processeur
[Java] Obtenez les dates des derniers lundi et dimanche dans l'ordre
Créons une application TODO en Java 5 Changer l'affichage de TODO
Ceci et cela de JDK
Une collection de phrases qui impressionne le "sentiment différent" de Java et de JavaScript
Spécifiez l'ordre dans lequel les fichiers de configuration et les classes sont chargés dans Java
Le problème que le contenu des paramètres est complètement affiché dans la vue [Rails]
L'histoire de l'oubli de fermer un fichier en Java et de l'échec
Pensons à ce qu'est la programmation déclarative en Java et Elm (partie 1)
Exemple de programme qui renvoie la valeur de hachage d'un fichier en Java
Trouvez le maximum et le minimum des cinq nombres saisis en Java
Revue des connaissances «étranges Java» et Java souvent oubliées dans Java Bronze
[Java] Implémenter une fonction qui utilise une classe implémentée dans le modèle Builder
[Introduction à l'informatique Partie 1: Essayons l'apprentissage automatique] Implémentons la méthode de calcul de la moyenne k en Java - À propos du concept de coordonnées -
Obtenez le résultat de POST en Java
Quelles sont les fonctionnalités mises à jour de Java 13
L'histoire de l'écriture de Java dans Emacs
Discrimination d'énum dans Java 7 et supérieur
J'ai reçu les données du voyage (application agenda) en Java et j'ai essayé de les visualiser # 001
[Java] Où est la classe d'implémentation de l'annotation qui existe dans BeanValidation?
AndroidStudio Faisons référence au C ++ dans le module des autres projets (Java / kotlin)
Code pour supprimer tous les fichiers du préfixe spécifié dans AWS S3 (Java)
10 barrages de dessin avec ● ou ■ qui sont susceptibles d'apparaître dans la formation (Java)