2010-10-11 6 views
1

Étant donné deux points sur la boussole (plage de début et plage de fin) pour former une plage. Exemple de 270 (plage de début) degrés à 45 (plage de fin) degrés et donné un autre point disons 7, comment puis-je travailler si ce point est entre début et fin de gamme? J'essaie d'écrire du code pour savoir si le vent (au point 3 ci-dessus) souffle de la mer ou de la terre, où la terre est défendue par la plage de début et la plage de fin.comment décider que le point est entre deux points sur la boussole

Merci beaucoup Andy

Mise à jour: 11/10/2010 18: 46BST De la solution de @ STH ce qui suit semble fonctionner pour comme prévu.

#!/usr/bin/perl -w 

sub isoffshore { 

     my ($beachstart,$beachend,$wind) = @_; 

     if($beachend < $beachstart) { 
       $beachend += 360; 
     } 

     if ($wind < $beachstart){ 
       $wind += 360; 
     } 

     if ($wind <= $beachend){ 
       print ("Wind is Onshore\n"); 
       return 0; 
     }else{ 
       print ("Wind is Offshore\n"); 
       return 1; 

     } 

} 

isoffshore ("0","190","3"); #Should be onshore 
isoffshore ("350","10","11"); #Should be offshore 
isoffshore ("270","90","180");#Should be offshore 
isoffshore ("90","240","0"); #Should be offshore 
isoffshore ("270","90","180");#Should be offshore 
isoffshore ("0","180","90"); #Should be onshore 
isoffshore ("190","0","160"); #Should be offshore 
isoffshore ("110","240","9"); #Should be offshore 
isoffshore ("0","180","9"); #Should be onshore 
isoffshore ("0","180","179"); #Should be onshore 

Résultats

@localhost ~]$ ./offshore2.pl 
Wind is Onshore 
Wind is Offshore 
Wind is Offshore 
Wind is Offshore 
Wind is Offshore 
Wind is Onshore 
Wind is Offshore 
Wind is Offshore 
Wind is Onshore 
Wind is Onshore 

Répondre

1

est ici une fonction d'une ligne qui utilise l'opérateur modulo (%) pour gérer le wraparound. Les valeurs d'entrée sont supposées être dans la gamme 0..359 (degrés):

int inRange(int start, int end, int point) 
{ 
    return (point + 360 - start) % 360 <= (end + 360 - start) % 360; 
} 

// 
// Test harness 
// 

#include <assert.h> 
#include <stdlib.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    assert(inRange(90, 270, 0) == 0); 
    assert(inRange(90, 270, 45) == 0); 
    assert(inRange(90, 270, 180) == 1); 
    assert(inRange(90, 270, 315) == 0); 
    assert(inRange(270, 90, 0) == 1); 
    assert(inRange(270, 90, 45) == 1); 
    assert(inRange(270, 90, 180) == 0); 
    assert(inRange(270, 90, 315) == 1); 

    if (argc >= 4) 
    { 
     int start = atoi(argv[1]); 
     int end = atoi(argv[2]); 
     int point = atoi(argv[3]); 
     int result = inRange(start, end, point); 

     printf("start = %d, end = %d, point = %d -> result = %d\n", start, end, point, result); 
    } 
    return 0; 
} 

Notez que le terme + 360 de chaque côté de l'essai est nécessaire en C/C++ en raison de la façon regrettable que % traite négatif valeurs.

+1

Très bien. Une solution simple :-) – AndyM

+0

@AndyM: merci - J'étais déterminé à trouver une solution sans branchement. C'est dommage pour l'opérateur% C/C++ - si cela fonctionnait correctement pour les valeurs négatives, la solution aurait été plus simple. –

1

Cela devrait fonctionner si tous vos points sont comme 0 <= point < 360:

def between(lower, upper, point): 
    if upper < lower: 
     upper += 360 
    if point < lower: 
     point += 360 
    return (point <= upper) 
+1

Cela semble correct, mais les noms de variable supérieurs et inférieurs semblent un peu confus. Peut-être que startRange et endRange seraient un peu plus intuitifs. La vérification "upper Chris

+0

@sth, @Chris: Cela échoue si 'lower = 3 * pi/2',' upper = 3 * pi/2 - epsilon' et 'point = 3 * pi/2 - epsilon/2' où' epsilon 'est un petit nombre positif. Dans ce cas, votre algorithme détecterait que 'upper jason

+0

Cela fonctionne. Pour moi. – AndyM

2

par points sur une boussole, je suppose que vous voulez dire des points sur le cercle unité. Et par "entre" deux points sur le cercle d'unité, vous voulez dire que vous avez décrit un arc sur le cercle d'unité et que vous voulez savoir si un point donné est dans cet arc.

Supposons que tous les points sur le cercle d'unité sont décrits par des angles et pour un tel angle t décrivant un point sur le cercle unité, nous exigeons que 0 <= t < 2 * pi.

Disons que votre arc est décrit comme l'arc (t_1, t_2) (qui est, traverse antihoraire du point sur le cercle unitaire correspondant à l'angle t_1 au point sur le cercle unitaire correspondant à l'angle t_2*). Ensuite, étant donné un point sur le cercle unité avec un angle correspondant t, il est vrai que t est le sens inverse des aiguilles d'arc à t_1t_2 si t_2 > t_1 et t_1 <= t <= t_2 ou t_1 > t_2 et non t_2 <= t <= t_1.

Ainsi,

public bool IsInArc(double t1, double t2, double t) { 
    Guard.Against<ArgumentOutOfRangeException>(t1 < 0 || t1 >= 2 * Math.PI); 
    Guard.Against<ArgumentOutOfRangeException>(t2 < 0 || t2 >= 2 * Math.PI); 
    Guard.Against<ArgumentOutOfRangeException>(t < 0 || t >= 2 * Math.PI); 
    return t2 > t1 ? IsInArcInternal(t1, t2, t) : !IsInArcInternal(t2, t1, t); 
} 

private bool IsInArcInternal(double t1, double t2, double t) { 
    Guard.Against<ArgumentException>(t2 < t1); 
    return t1 <= t && t <= t2; 
} 
+1

Cela ne semble pas correct. Si t1 = 3 * pi/2 et t2 = pi/2 et t est 0 alors t est dans l'arc (commençant à t1 et allant dans le sens des aiguilles d'une montre passé zéro à t2). Cependant, votre technique suggère que ce n'est pas le cas. Je crois que votre technique ne prend pas l'arc défini dans le sens des aiguilles d'une montre à partir de t1 mais toujours celui qui ne contient pas le point zéro (c'est-à-dire qui ne s'enroule pas). La seule valeur de t1, t2 qui permet au point zéro d'être inclus pour le vôtre est t1 = 0 ou t2 = 0. – Chris

+0

@Chris: Incorrect. Ma méthode fonctionne pour la situation que vous avez décrite. Notez que dans le cas que vous décrivez, 't1 = 3 * pi/2',' t2 = pi/2' et 't = 0'. Par conséquent, 't2> t1' est faux, de sorte que' IsInArcInternal' est appelé 'IsInArcInternal (pi/2, 3 * pi/2, 0)'. Alors nous avons que 'pi/2 <= 0 && 0 <= 3 * pi/2' est faux '. Mais notez qu'il y a un '! 'Devant l'appel de' IsInArcInternal' et que la valeur de retour de 'IsInArc' est vraie. C'est certainement possible j'ai gâché quelques autres cas, mais celui-ci est correct. – jason

+0

@ Paul R: Je ne suis pas d'accord. S'il vous plaît voir mon commentaire à Chris. Veuillez noter le '!' Devant l'appel à 'IsInArcInternal' quand' t2 <= t1'. – jason

Questions connexes