Je veux déterminer si un clic est effectué entre les points et à peu près sur le segment de ligne qui relie ces deux points.

Ma question est similaire à Comment pouvez-vous déterminer qu'un point se situe entre deux autres points sur un segment de ligne? mais il diffère en deux points:

  1. Je travaille en javascript et les coordonnées sont en entiers (pixels)
  2. Il n'est pas nécessaire que le point soit exactement sur le segment de ligne. Une tolérance est nécessaire.

Le code suivant est adapté de cette réponse, mais je ne sais pas comment insérer une tolérance autour du segment de ligne

a et b sont les extrémités du segment de ligne et c est le point cliqué. Je veux vérifier si c se situe entre a et b et à peu près sur le segment qui relie a et b

PencilTool.prototype._isBetween = function(a,b,c){
    //test if a, b and c are aligned
    var crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y);
    if(Math.abs(crossproduct) !== 0){ return false; }

    var dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if(dotproduct < 0){ return false }

    var squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y);
    if(dotproduct > squaredlengthba){ return false; }

    return true;
}
1
Below the Radar 10 juil. 2015 à 20:29

3 réponses

Meilleure réponse

Voici la dernière fonction javascript que j'utilise maintenant.

La première partie utilise la formule de distance comme expliqué dans la réponse d'Ashley Tharp, nous testons d'abord si c est à l'intérieur une distance prédéfinie (tolerance) d'une ligne passant par a et b.

La deuxième partie est tirée de la réponse de Cyrille Ka d'une question similaire.

Ensuite, pour savoir si c se situe entre a et b, vous devez également vérifier que le produit scalaire de (b-a) et (c-a) est positif et inférieur que le carré de la distance entre a et b.

// a and b are vertices of the segment AB and c is the tested point (here from a mouseclick event (e))
var a={}, b={}, c={};
a.x = 100;
a.y = 100;
b.x = 200;
b.y = 200;
c.x = e.screenX
c.y = e.screeny

console.log(isBetween(a, b, c, 5));

function isBetween(a, b, c, tolerance) {

    //test if the point c is inside a pre-defined distance (tolerance) from the line
    var distance = Math.abs((c.y - b.y)*a.x - (c.x - b.x)*a.y + c.x*b.y - c.y*b.x) / Math.sqrt(Math.pow((c.y-b.y),2) + Math.pow((c.x-b.x),2));
    if (distance > tolerance) { return false; }

    //test if the point c is between a and b
    var dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y);
    if (dotproduct < 0) { return false; }

    var squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y);
    if (dotproduct > squaredlengthba) { return false; }

    return true;
};
1
Below the Radar 6 avril 2018 à 12:05

Vous pouvez superposer un div entre les deux points, pivoter au besoin et aussi épais que nécessaire. Attachez hover CSS ou cliquez sur des événements à la div.

Utilisez la formule de distance pour déterminer la largeur du div:

enter image description here

Utilisez cette formule pour déterminer l'angle de rotation en degrés:

Math.atan2((y1-y2),(x1-x2))*(180/Math.PI)

Par souci de simplicité, j'utilise jQuery dans mon extrait de code, mais je pourrais rapidement réécrire en JavaScript vanille:

var x1= 10+Math.random()*500/4,
    y1= 10+Math.random()*300/4,
    x2= Math.random()*500/2 + 500/4,
    y2= Math.random()*300/2 + 300/4,
    pt= $('.a').width()/2,
    dx= (x2-x1),
    dy= (y2-y1),
    angle= Math.atan2((y1-y2),(x1-x2))*(180/Math.PI),
    tolerance= 30;

$('.a').css({left: x1, top : y1});
$('.b').css({left: x2, top : y2});

$('div.c').css({
  width: Math.sqrt(dx*dx + dy*dy),
  height: tolerance,
  left: x2+pt,
  top: y2+pt,
  transformOrigin: '0px '+tolerance/4+'px',
  transform: 'rotate('+angle+'deg)'
});

$('div.c')
  .click(function() {
    alert('clicked!');
  });
body {
  margin: 0;
  padding: 0;
}

div.a, div.b, div.c {
  position: absolute;
  border-radius: 50%;
  height: 1.2em;
  width: 1.2em;
  text-align: center;
  background: orange;
}

div.c {
  border: 1px solid #eee;
  background: transparent;
  border-radius: 0;
}

div.c:hover ~ div.a, div.c:hover ~ div.b {
  background: lightgreen;
}

div.c hr {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  height: 1.2em;
  border: none;
  border-top: 1px solid orange;
}

div.c:hover hr {
  border-top: 1px solid green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="c"><hr></div>
<div class="a">A</div>
<div class="b">B</div>
2
Rick Hitchcock 10 juil. 2015 à 19:09

enter image description here

C'est probablement la formule que vous voulez.

Voici le lien vers la page wikipedia pour cette formule.

Cette source est très complète, mais probablement pas la plus facile à lire. Vous pouvez lire l'explication sur le wiki, mais je vais l'expliquer ici d'une autre manière dans l'espoir de pouvoir vous aider, vous et d'autres lecteurs, à la visualiser.

X0 et y0 sont les coordonnées de votre point de clic. x1 et y1 sont les coordonnées de votre premier point d'extrémité de ligne. x2 et y2 sont les coordonnées de votre deuxième point final sur cette même ligne.

Cette formule prend trois ensembles de coordonnées pour trois points comme paramètres.
Les deux premiers ensembles de coordonnées forment la ligne.
Le troisième paramètre est votre point de clic. Il renvoie une distance.

Bon, essayons maintenant de visualiser ce que fait cette formule. Vous prenez donc le point de clic et les deux extrémités de la ligne, et vous imaginez un triangle. Nous avons trois points, c'est tout ce dont nous avons besoin pour faire un triangle.

Donc, pour trouver la hauteur du triangle, vous avez une formule, qui est un réarrangement du familier A = (1/2) bh

enter image description here

Ainsi, lorsque vous trouvez la hauteur du triangle comme ça, vous trouvez la distance entre le point de clic et la ligne. (C'est la distance la plus courte entre le point de clic et la ligne pour être précis)

La formule de distance plus grande ci-dessus fait essentiellement cela. La différence ici, et pourquoi cela semble plus compliqué, est que la partie où A est calculé est indiquée explicitement.

Concernant la tolérance dont vous parliez, il suffit de définir une variable de tolérance et de comparer la distance à cette tolérance. Si vous voulez quelque chose d'un peu plus "flou" pour la tolérance aux clics près de la ligne, vous devrez faire plus de calcul, mais je suppose que vous voulez seulement savoir si le clic était à une certaine distance de la ligne.

Lorsque vous écrivez cette fonction, assurez-vous de bien tenir la comptabilité et de définir les coordonnées appropriées au bon endroit, sinon vous obtiendrez une distance mais pas celle que vous souhaitez. Puisque vous avez mentionné que vous utilisez des entiers, vous ne pouvez pas obtenir un entier parfait en arrière à partir de la formule de distance, je veux dire, regardez cette racine carrée, donc si vous n'obtenez pas un entier parfait en arrière, pas de soucis, juste arrondi vers le haut ou vers le bas ,

6
sitting-duck 24 juil. 2015 à 15:10