J'ai un segment de droite défini par deux points A (x1, y1, z1) et B (x2, y2, z2) et le point p (x, y, z). Comment puis-je vérifier si le point repose sur le segment de ligne?
Si le point est sur la ligne, alors:
(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1) = (z - z1) / (z2 - z1)
Calculez les trois valeurs et si elles sont identiques (avec un certain degré de tolérance), votre point est sur la ligne.
Pour vérifier si le point est dans le segment, pas seulement sur la ligne, vous pouvez vérifier que
x1 < x < x2, assuming x1 < x2, or
y1 < y < y2, assuming y1 < y2, or
z1 < z < z2, assuming z1 < z2
Trouver la distance du point P des deux points d'extrémité de ligne A, B. Si AB = AP + PB, alors P est situé sur le segment de ligne AB.
AB = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
AP = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1));
PB = sqrt((x2-x)*(x2-x)+(y2-y)*(y2-y)+(z2-z)*(z2-z));
if(AB == AP + PB)
return true;
Tout d'abord prenons le produit croisé de AB et AP . S'ils sont colinéaires, alors ce sera 0.
À ce stade, il pourrait toujours être sur la plus grande ligne allant de B ou avant A, alors je pense que vous devriez pouvoir vérifier si pz est compris entre az et bz.
Ceci semble être un doublon , en fait, et comme l’a mentionné une des réponses, il se trouve dans Beautiful Code .
dans le cas où quelqu'un cherche la version en ligne:
public static bool PointOnLine2D (this Vector2 p, Vector2 a, Vector2 b, float t = 1E-03f)
{
// ensure points are collinear
var zero = (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y);
if (zero > t || zero < -t) return false;
// check if x-coordinates are not equal
if (a.x - b.x > t || b.x - a.x > t)
// ensure x is between a.x & b.x (use tolerance)
return a.x > b.x
? p.x + t > b.x && p.x - t < a.x
: p.x + t > a.x && p.x - t < b.x;
// ensure y is between a.y & b.y (use tolerance)
return a.y > b.y
? p.y + t > b.y && p.y - t < a.y
: p.y + t > a.y && p.y - t < b.y;
}
Votre segment est mieux défini par une équation paramétrique
l'équation suivante est vérifiée pour tous les points de votre segment: x = x1 + (x2 - x1) * p y = y1 + (y2 - y1) * p z = z1 + (z2 - z1 ) * p
Où p est un nombre dans [0; 1]
Donc, s'il existe un p tel que vos coordonnées de point satisfassent ces équations 3, votre point est sur cette ligne. Et il p est compris entre 0 et 1 -it est également sur le segment de ligne
Voici un code C # pour le cas 2D:
public static bool PointOnLineSegment(PointD pt1, PointD pt2, PointD pt, double epsilon = 0.001)
{
if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon ||
Math.Min(pt1.X, pt2.X) - pt.X > epsilon ||
pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon ||
Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
return false;
if (Math.Abs(pt2.X - pt1.X) < epsilon)
return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;
double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);
return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
}
J'utilise ceci pour calculer la distance AB entre les points a et b.
static void Main(string[] args)
{
double AB = segment(0, 1, 0, 4);
Console.WriteLine("Length of segment AB: {0}",AB);
}
static double segment (int ax,int ay, int bx, int by)
{
Vector a = new Vector(ax,ay);
Vector b = new Vector(bx,by);
Vector c = (a & b);
return Math.Sqrt(c.X + c.Y);
}
struct Vector
{
public readonly float X;
public readonly float Y;
public Vector(float x, float y)
{
this.X = x;
this.Y = y;
}
public static Vector operator &(Vector a, Vector b)
{
return new Vector((b.X - a.X) * (b.X - a.X), (b.Y - a.Y) * (b.Y - a.Y));
}
}
basé sur Calculez un point le long de la ligne A-B à une distance donnée de A
D'après la réponse de Konstantin ci-dessus, voici un code C permettant de déterminer si un point se trouve réellement sur un segment de ligne FINITE. Ceci prend en compte les segments de ligne horizontaux/verticaux. Cela tient également compte du fait que les nombres en virgule flottante ne sont jamais vraiment "exacts" quand on les compare. Le défaut epsilon de 0.001f suffira dans la plupart des cas. Ceci est pour les lignes 2D ... ajouter "Z" serait trivial. La classe PointF provient de GDI +, qui est fondamentalement juste: struct PointF{float X,Y};
J'espère que cela t'aides!
#define DEFFLEQEPSILON 0.001
#define FLOAT_EQE(x,v,e)((((v)-(e))<(x))&&((x)<((v)+(e))))
static bool Within(float fl, float flLow, float flHi, float flEp=DEFFLEQEPSILON){
if((fl>flLow) && (fl<flHi)){ return true; }
if(FLOAT_EQE(fl,flLow,flEp) || FLOAT_EQE(fl,flHi,flEp)){ return true; }
return false;
}
static bool PointOnLine(const PointF& ptL1, const PointF& ptL2, const PointF& ptTest, float flEp=DEFFLEQEPSILON){
bool bTestX = true;
const float flX = ptL2.X-ptL1.X;
if(FLOAT_EQE(flX,0.0f,flEp)){
// vertical line -- ptTest.X must equal ptL1.X to continue
if(!FLOAT_EQE(ptTest.X,ptL1.X,flEp)){ return false; }
bTestX = false;
}
bool bTestY = true;
const float flY = ptL2.Y-ptL1.Y;
if(FLOAT_EQE(flY,0.0f,flEp)){
// horizontal line -- ptTest.Y must equal ptL1.Y to continue
if(!FLOAT_EQE(ptTest.Y,ptL1.Y,flEp)){ return false; }
bTestY = false;
}
// found here: http://stackoverflow.com/a/7050309
// x = x1 + (x2 - x1) * p
// y = y1 + (y2 - y1) * p
// solve for p:
const float pX = bTestX?((ptTest.X-ptL1.X)/flX):0.5f;
const float pY = bTestY?((ptTest.Y-ptL1.Y)/flY):0.5f;
return Within(pX,0.0f,1.0f,flEp) && Within(pY,0.0f,1.0f,flEp);
}
Soit V1 le vecteur (B-A), et V2 = (p-A), normalisons V1 et V2.
Si V1 == (- V2) alors le point p est sur la ligne mais précédant A, et donc pas dans le segment . Si V1 == V2 le point p est sur la ligne. Obtenez la longueur de (p-A) et vérifiez si elle est inférieure ou égale à la longueur de (B-A). Si c'est le cas, le point est sur le segment, sinon il est passé B.
Le produit croisé (B - A) × (p - A) devrait être beaucoup plus court que B - A. Idéalement, le produit croisé est égal à zéro, mais cela est peu probable avec du matériel à virgule flottante de précision finie.