Comment déterminer si un point est dans un contour ?

Dernière mise à jour : samedi 15 novembre 2025

On a souvent besoin de déterminer si un point est dans un contour. Par exemple quand on a des zones qui sont étiquetées. Il faut arriver à faire le lien entre une polyligne fermée et le texte qui se trouve à l'intérieur.

Il y a plusieurs façons de procéder, mais pour moi la plus simple et la plus fiable, c'est d'utiliser l'API BRep d'AutoCAD. BRep c'est pour Boundary REPresentation. C'est une API 3D, mais on peut l'utiliser avec les objets 2D que sont les régions.

La première étape est de créer une région à partir des courbes qui forment le contour. On peut le faire avec la méthode Region.CreateFromCurves :

DBObjectCollection regions = Region.CreateFromCurves(new DBObjectCollection { curve })!;
using var region = (Region)regions[0]!;

Ici, on imagine qu'on a une seule courbe (polyligne fermée, cercle ou ellipse). On utilise le mot clé using pour s'assurer que l'objet region sera détruit à la fin, car on n'en a besoin que temporairement.

La seconde étape est de créer un objet BRep, toujours avec using :

using var brep = new Brep(region);

La troisième étape est de tester si le point est dans la région avec la méthode GetPointContainment() :

brep.GetPointContainment(point, out PointContainment _);

C'est là que ça se complique un peu. Comme je vous l'ai indiqué plus tot, l'API BRep est une API 3D. GetPointContainement() sert à déterminer si un point se trouve ou pas à l'intérieur d'un objet 3D comme un cube.

Comme ici, on a un point A à l'intérieur du cube et un point B à l'extérieur.

Point dans un cube

C'est pour ça que le paramètre out PointContainment est une énumération qui peut être Inside ou Outside. Mais il y a également une autre possibilité : le point peut se trouver sur la coquille (Shell) qui sépare l'intérieur du cube de l'extérieur. PointContainment prendra alors la valeur OnBoundary.

Si on regarde la signature de GetPointContainment(), on voit qu'elle retourne un objet BrepEntity :

public BrepEntity GetPointContainment(
    Point3d point, 
    out Autodesk.AutoCAD.BoundaryRepresentation.PointContainment containment
);

La coquille est en fait composée de faces, d'arêtes et de sommets. Donc si le point est situé à l'intérieur d'une face, un objet Face sera retourné. Si le point est sur une arête ou un sommet, un objet Edge ou Vertex sera retourné.

Mais dans le cas de notre région qui est un objet 2D, on n'a pas un solide, mais une seule face plane qui ne délimite pas un volume. Donc GetPointContainment() ne retournera jamais Inside.

Point dans une région

Si le point est dans la région, c'est OnBoundary qui sera retourné dans le paramètre containment et un objet Face ou Edge sera retourné. On n'aura pas de Vertex dans ce cas, même si on passe un point qui correspond à un sommet d'une des courbes qui forment le contour.

Si le point est à l'extérieur de la région, Outside sera retourné dans le paramètre containment et null sera retourné.

Voici le code d'une petite commande pour vous permettre d'expérimenter :

[CommandMethod("PTINCONTOUR")]
public static void PointInContour()
{
    Document document = Application.DocumentManager!.MdiActiveDocument!;
    Editor editor = document.Editor!;
    PromptEntityResult entityResult = editor.GetEntity("\nSélectionnez une courbe fermée :")!;
    if (entityResult.Status != PromptStatus.OK)
        return;
    PromptPointResult pointResult = editor.GetPoint("\nSélectionnez un point :")!;
    if (pointResult.Status != PromptStatus.OK)
        return;
    using Transaction transaction = document.TransactionManager!.StartTransaction()!;
    var curve = (Curve)entityResult.ObjectId.GetObject(OpenMode.ForRead)!;
    DBObjectCollection regions = Region.CreateFromCurves(new DBObjectCollection { curve })!;
    using var region = (Region)regions[0]!;
    using var brep = new Brep(region);
    BrepEntity? entity = brep.GetPointContainment(pointResult.Value, out PointContainment containment);
    editor.WriteMessage($"\nContainment: {containment}, Entity: {entity}");
    transaction.Commit();
}

Donc si GetPointContainment retourne null, le point est à l'extérieur de la région. S'il retourne un objet Face, le point est à l'intérieur de la région. S'il retourne un objet Edge, le point est sur la bordure de la région.

Vous pouvez donc écrire une méthode IsInside qui retourne un PointContainment en passant un point et un ou plusieurs courbes qui forment le contour.

public static PointContainment IsInside(Point3d point, Curve[] curves)
{
    ArgumentNullException.ThrowIfNull(curves);

    var collection = new DBObjectCollection();
    foreach (Curve curve in curves)
        collection.Add(curve);
    DBObjectCollection regions;
    try
    {
        regions = Region.CreateFromCurves(collection)!;
    }
    catch (Autodesk.AutoCAD.Runtime.Exception exception) when (exception.ErrorStatus == ErrorStatus.InvalidInput)
    {
        throw new ArgumentException("Les courbes ne forment pas une région valide.", nameof(curves), exception);
    }
    using var region = (Region)regions[0]!;
    using var brep = new Brep(region);
    using BrepEntity? entity = brep.GetPointContainment(point, out PointContainment _);
    return entity switch
    {
        null => PointContainment.Outside,
        Face => PointContainment.Inside,
        _ => PointContainment.OnBoundary
    };
}