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.
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.
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;
}
}
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.
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.
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.
- 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 °.
- 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