IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

Algorithme pour savoir si une forme est à l'intérieur d'une autre


Sujet :

Delphi

  1. #1
    Membre à l'essai
    Homme Profil pro
    responsable process chimique, hoby l'electronique, informatique
    Inscrit en
    Décembre 2015
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : responsable process chimique, hoby l'electronique, informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2015
    Messages : 12
    Points : 12
    Points
    12
    Par défaut Algorithme pour savoir si une forme est à l'intérieur d'une autre
    Bonjour,
    A partir d’entités simples: ligne, arc, spline,cercle,ellipse, point (définies avec toutes les coordonnées x,y nécessaires) qui misent bout à bout définissent une forme fermée que je nomerai :F1
    J'ai la même chose pour une forme F2 également fermée.
    Quel pourrais être l'algorithme pour savoir si F2 est a intérieur ou a l’extérieur de F1 et vis et versa.
    les lignes sont définies par une origine et une extrémité ( cad 2 points)
    les arcs sont définies de la même façon que le canvas, Cad les points extrêmes du cadre qui englobe l'arc, point de départ et point final de l'arc.
    les splines sont une succession de points reliés par des lignes.
    les cercles: idem au arc avec point de départ=point final.
    les ellipses, 2 points qui définissent le grand axe, et 2 points qui définissent le petit axe. Les 2 axes se croisent au centre de l’ellipse.
    les points: une coordonnée X,Y.

    Merci pour vos proposition.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 685
    Points : 10 718
    Points
    10 718
    Par défaut
    Vu comme cela, cela peut-être à la fois simple et à la fois compliqué

    Je ferais comme cela ... dans un premier temps

    Il faut faire le tri entre les entités 2D et 1D.
    • 1D -> ligne, spline, point
    • 2D -> arc, cercle, ellipse


    Un point ou une ligne ne peuvent pas contenir une entité.
    Par contre la spline peut-être fermée et être 2D

    Ensuite, déduire les boites englobantes rectangulaires de chaque entités. D'après tes définitions, c'est bien le cas.
    Par exemple, avec un cercle tu n'as pas d'angle ni de rayon, mais 3-4 points de la boite englobante

    Donc il faut faire cela en 2 tests pour savoir si F1 est à l'intérieur de F2:
    1. Premier test trivial: Si la boite englobante de F1 est entièrement contenue dans celle de F2. Si non -> pas contenue ou chevauchante, c'est fini
    2. Deuxième test: L'idée c'est que la boite englobante de F2 a des parties "à l'extérieur". Donc cela va dépendre de tes formes 2D. Mais comme tu as un cercle et un arc, c'est assez trivial. Il faut déduire le rayon (qui est le demi d'1 des côtés) et le centre, et faire un test de distance (la distance entre le côté le plus éloigné du centre de la boite englobante de F1 et le centre doit être inférieur ou égal au rayon)



    Édit: Comme le propose Gilbert Geyer, la bibliothèque win32 (VCL) a une notion de régions

    Edit2: Comme le propose Gilbert Geyer (encore 1 fois) , si cela fonctionne on pourrait optimiser un chouïa en prenant non plus les boites englobantes rectangulaires (c.a.d les côtés parallèles ou perpendiculaires au repère), mais les boites englobantes "englobant le plus".
    Par exemple, en reliant les extrémités ou, avec un cercle, les tangentes passant par 4 points séparés de 90°C ou avec un arc, un triangle.
    Une grosse partie des maths collège , avec les triangle - cercle - ... inscrit - circonscrit - ... médiane - médiatrice - tangente - ...

  3. #3
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Jp1664 : Quel pourrais être l'algorithme pour savoir si F2 est a intérieur ou a l’extérieur de F1 et vis et versa.
    Si F1 et F2 sont toutes les deux constitués par des ensembles de points formant deux polygones , pour savoir si F2 est à entièrement à l'intérieur de F1
    il suffit vérifier si tous les points du Polygone F2 sont à l'intérieur du polygone F1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function PointDansPolygone(const x, y: integer; Polygone: array of TPoint): boolean;
    //       Renvoie True si le point x,y est à l'intérieur du Polygone de points
    var Handle: HRGN;
    begin 
      Handle := CreatePolygonRgn(Polygone[0], length(Polygone), Winding);
      Result := PtInRegion(Handle, X, Y);
      DeleteObject(Handle);
    end;
    ceci peut convenir si F2 et F1 sont toutes deux des splines puisque tu dis qu'elles "sont une succession de points reliés par des lignes".

    Par contre pour les arcs définis par "les points extrêmes du cadre qui englobe l'arc, point de départ et point final de l'arc" cela ne marche pas : il faudra trouver autre chose.

    Pour toute Ellipse tu peux créer pour chacune son polygone de 359 points de contour à partir des équations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     t := 2 * Pi / 360;
    x:= xc + a * cos(t); 
    y:= yc + b * sint(t) // avec xc,yc = coordonnées du centre, a = Grand Rayon et b = Petit Rayon
    puis utiliser la function PointDansPolygone()

    Pour tout Cercle tu peux faire comme pour les Ellipses puisque b = Petit Rayon est égal à a = Grand Rayon.

    A+.

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 845
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 845
    Points : 13 622
    Points
    13 622
    Par défaut
    Il faut effectivement passer par des régions.

    Pour les lignes, il faudra appliquer ce que propose Gilbert, soit tester si les points se trouvent à l'intérieur de la région.

    Ce n'est pas plus compliqué pour les formes
    Il suffit de combiner les deux régions par CombineRgn(RGN_AND) et contrôler si le résultat équivaut à l'une d'elles par EqualRgn.

    Un arc est une fraction de cercle, un CombineRgn entre une ellipse et un rectangle puisque les formes sont fermées.

  5. #5
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Andnotor : Un arc est une fraction de cercle, un CombineRgn entre une ellipse et un rectangle puisque les formes sont fermées.
    Bin comme un arc est une fraction de cercle voire une fraction d'ellipse c.à.d une succession de points formant un polygone ont peut considérer qu'il est fermé par la ligne qui relie ses extrémités.
    Du coup on peut se simplifier la vie en créant pour chaque forme une fonction qui en renvoie le polygone des points de contour.

    Le bout de code du ZIP ci-joint n'en contient que 2 pour l'instant : celles qui renvoient l'Astroïde et l'Ellipse sont obtenues à partir d'équations polaires, pour des figures formées par des lignes ça se fait les doigts dans le nez, et en as de besoin on peut trouver plein d'équations (Trèfle, Coeur, Papillon) ici :http://www.mathcurve.com/courbes2d/o...mentales.shtml

    Comme l'objectif de la manip était seulement de détecter si une forme est ou n'est pas dans une autre je n'ai pas utilisé GDI+ pour améliorer le rendu (crade) du tracé.
    En outre, dans le cas où il s'agirait de formes qui subissent des changements de taille ou de fréquentes rotations il serait préférable de remplacer les Erray Of TPoint du type integer par des Array Of PointsDuTypeSingle.

    A+.

    EDIT : Oups, en revenant chez moi, je viens de m'apercevoir que je n'ai pas supprimé dans le code la function RoEllipse devenue superflue par l'achèvement de la function PolyEllipse mais il suffit de virer la superflue.
    Images attachées Images attachées  
    Fichiers attachés Fichiers attachés

  6. #6
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 845
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 845
    Points : 13 622
    Points
    13 622
    Par défaut
    Ce qui est dommage est de boucler autant de fois alors que par une combinaison de régions, on teste toutes les variantes en deux/trois lignes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    if CombineRgn(RgnR, Rgn1, Rgn2, RGN_AND) = NULLREGION then
      //Ne se chevauchent pas
     
    else if EqualRgn(Rgn1, RgnR) then
      //Rgn1 dans Rgn2
     
    else if EqualRgn(Rgn2, RgnR) then
      //Rgn2 dans Rgn1
     
    else
     //Se chevauchent partiellement
    Pour l'arc, tu peux le faire par polygone mais tu ajoutes une source d'erreur (certainement négligeable ici) puisque ce n'est qu'une suite de cordes. Si deux points se trouvent sur le même vertex que le conteneur, ta fonction renverra vrai alors qu'effectivement le segment (manquant) sera à l'extérieur.

  7. #7
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Andnotor : Ce qui est dommage est de boucler autant de fois alors que par une combinaison de régions, on teste toutes les variantes en deux/trois lignes.
    En fait lorsque F2 est entièrement en-dehors de F1 (cas fréquent) on ne boucle pas du tout puisque pour i = 0 ça provoque immédiatement l'EXIT :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function FormeF2estdansF1(F2, F1: TArrayOfTPoint): boolean;
    var i: integer;
    begin
      Result := False;
      for i := 0 to high(F2) do begin
        if not PointDansPolygone(F2[i], F1) then EXIT;
      end;
      Result := True;
    end;
    Ce n'est que lorsque F2 est entièrement incluse dans F2 que l'on boucle jusqu'à la fin.

    J'ajoute à ceci que si ce bout de code laisse voir qu'il y a une boucle, celle-ci fait très certainement un travail équivalent à celui de toutes les boucles
    encapsulées dans le code de CombineRgn(RgnR, Rgn1, Rgn2, RGN_AND) et de EqualRgn(Rgn1, RgnR)

    Puis il y a une autre raisons pour laquelle je n'ai pas utilisé ta solution : elle nécessite que l'on passe des handle à CombineRgn et à EqualRgn alors que je préfère les routines auxquelles on passe directement les Array de Points qui délimitent ces régions.

    Pour l'arc, tu peux le faire par polygone mais tu ajoutes une source d'erreur (certainement négligeable ici) puisque ce n'est qu'une suite de cordes. Si deux points se trouvent sur le même vertex que le conteneur, ta fonction renverra vrai alors qu'effectivement le segment (manquant) sera à l'extérieur.
    Absolument d'accord jusqu'à un certain point : on fait également une erreur de la taille d'un point en utilisant Handle := CreatePolygonRgn(MonArray[0], length(MonArray),Winding) puisque on travaille également avec des TPoint du type integer et non du type réel. Donc quelle que soit la solution utilisée le résultat est étroitement lié à l'importance de l'espacement entre deux points successifs de l'Array.

    Vivement que les nanotechnologies nous apportent des écrans avec des Nano-Pixels, ça nous permettra d'utiliser des solutions graphiques dans le domaine des nombres réels, et EXIT les tracés en escalier...

    A+.

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 845
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 845
    Points : 13 622
    Points
    13 622
    Par défaut
    Citation Envoyé par Gilbert Geyer Voir le message
    (cas fréquent)
    Ce n'est qu'une supposition en te basant sur tes "petites" formes en comparaison de la zone de travail
    De plus la donnée est "... et vice-versa". Dans le cas le plus favorable (les formes ne se touchent pas), tu testeras seulement deux points mais si elles sont identiques et se chevauchent parfaitement, c'est tous les points (les deux formes) qu'il faudra tester.

    Citation Envoyé par Gilbert Geyer Voir le message
    J'ajoute à ceci que si ce bout de code laisse voir qu'il y a une boucle, celle-ci fait très certainement un travail équivalent à celui de toutes les boucles
    encapsulées dans le code de CombineRgn(RgnR, Rgn1, Rgn2, RGN_AND) et de EqualRgn(Rgn1, RgnR)
    Il y a sans doute une boucle dans CombineRgn mais certainement pas dans EqualRgn. Pour moi, EqualRgn ne fait que comparer deux blocs mémoire. Si je devais le coder moi-même, je ferais ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function EqualRegions(aRgn1, aRgn2 :hRgn): boolean;
    var
      Data1  :PRgnData;
      Data2  :PRgnData;
      Count1 :integer;
      Count2 :integer;
     
    begin
      Count1 := GetRegionData(aRgn1, 0, nil);
      Count2 := GetRegionData(aRgn2, 0, nil);
     
      //1er test rapide
      if Count1 <> Count2 then Exit(FALSE);
     
      GetMem(Data1, SizeOf(TRgnData) *Count1);
      GetMem(Data2, SizeOf(TRgnData) *Count2);
     
      GetRegionData(aRgn1, Count1, Data1);
      GetRegionData(aRgn2, Count2, Data2);
     
      //2ème test
      Result := CompareMem(Data1, Data2, Count1);
     
      FreeMem(Data1);
      FreeMem(Data2);
    end;
    Mais même dans le cas de CombineRgn(RGN_AND), il n'y aura pas forcément de boucle si un rectangle de délimitation est inclus dans l'autre. La plus petite région peut être immédiatement renvoyée.

    Citation Envoyé par Gilbert Geyer Voir le message
    Puis il y a une autre raisons pour laquelle je n'ai pas utilisé ta solution : elle nécessite que l'on passe des handle à CombineRgn et à EqualRgn alors que je préfère les routines auxquelles on passe directement les Array de Points qui délimitent ces régions.
    J'ai remarqué et cela t'oblige à recréer le polygone de test à chaque appel. Pas très optimisé tu en conviendras !

    Citation Envoyé par Gilbert Geyer Voir le message
    on fait également une erreur de la taille d'un point en utilisant Handle := CreatePolygonRgn(MonArray[0], length(MonArray),Winding) ...
    Oui mais ce n'était pas mon approche qui consistait en la combinaison d'un cercle et d'un rectangle

  9. #9
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Re-bonjour,

    Tu as raison AndNotOr, et à propos de "Pas très optimisé tu en conviendras !" j'ajoute que je cherche toujours à me simplifier la vie. Ce n'est que si une routine est trop lente à mon goût que je cherche à optimiser.
    Et rien n'empêche jp1664 d'utiliser CombineRgn() et EqualRgn() s'il a besoin d'une solution optimisée.

    A+.

  10. #10
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    J'ai dit hier une bêtise en écrivant "elle nécessite que l'on passe des handle à CombineRgn et à EqualRgn alors que je préfère les routines auxquelles on passe directement les Array de Points qui délimitent ces régions."
    en fait c'est faux puisque ont peut faire ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function FormeF2estdansF1(F2, F1: TArrayOfTPoint): Char;
    // Result =
    // - H : si F2 Hors F1
    // - D : si F2 Hors F1
    // - C : si F2 Chevauche F1
    var RgnR, Rgn1, Rgn2: HRGN;
    begin
      Result := 'H';
      RgnR := CreateRectRgn(0, 0, 0, 0);
      Rgn1 := CreatePolygonRgn(F1[0], length(F1), Winding);
      Rgn2 := CreatePolygonRgn(F2[0], length(F2), Winding);
      if CombineRgn(RgnR, Rgn1, Rgn2, RGN_AND) = NULLREGION then begin Result := 'H'; EXIT; end // Ne se chevauchent pas
      else if EqualRgn(Rgn1, RgnR) then begin Result := 'H'; EXIT; end // Rgn1 dans Rgn2
      else if EqualRgn(Rgn2, RgnR) then begin Result := 'D'; EXIT; end // Rgn2 dans Rgn1
      else begin Result := 'C'; EXIT; end; // Se chevauchent partiellement
    end;
    Par contre ça ne marche pas dans le cas de 2 tronçons de droite dont l'un peut dans la pratique être entièrement inclus dans l'autre (voir trait bleu inclus entièrement dans trait rouge sur les captures d'écran)
    Cela ne marche pas car ce sont 2 régions de surface nulle.

    Mais pour le cas particulier des droites on peut s'en sortir avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function Distance2Points(P1, P2: TPoint): Extended;
    begin
      Result := hypot(P2.X - P1.X, P2.Y - P1.Y);
    end;
     
    function DistancePointDroite(OD, ED, Pt: tPoint): Extended;
    var Figure: TArrayOfTPoint; IncliRad: Extended;
    begin
      SetLength(Figure, 3);
      IncliRad := arcTan22(ED.Y - OD.Y, ED.X - OD.X);
      Figure[0] := OD; Figure[1] := ED; Figure[2] := PT;
      // Rotation de la figure qui ramène la droite inclinée en position horizontale
      RotaPolygone(Figure, OD, -RadToDeg(IncliRad));
      Result := abs(Figure[2].Y - OD.Y);
    end;
     
    function TronconDroite2estDansTronconDroite1(D2, D1: TArrayOfTPoint): boolean;
    var di1, di2,lg1: Extended; ok1, ok2, ok3: boolean;
    begin
      di1 := DistancePointDroite(D1[0], D1[1], D2[0]);
      di2 := DistancePointDroite(D1[0], D1[1], D2[1]);
      ok1 := (di1 < 1.0E-493) and (di2 < 1.0E-493);
      lg1:=Distance2Points(D1[0], D1[1]); // longueur Tronçon D1
      di1 := Distance2Points(D2[0], D1[0]);  // Distance d'une extrémité de D2 à la Première extrémité de D1
      di2 := Distance2Points(D2[1], D1[0]);  // Distance de l'autre
      ok2:=(di1<=lg1) and (di2<lg1);
      di1 := Distance2Points(D2[0], D1[1]);  // Distance d'une extrémité de D2 à la Deuxième extrémité de D1
      di2 := Distance2Points(D2[1], D1[1]);  // Distance de l'autre
      ok3:=(di1<=lg1) and (di2<lg1);
      Result:=ok1 and ok2 and ok3;
    end;
    Et pour tester si un tronçon de droite est à l'intérieur d'un autre truc il suffit de vérifier si chacun des 2 points d'extrémité du tronçon sont à l'intérieur du polygone du truc en utilisant la routine PointDansPolygone(const Point: TPoint; Polygone: TArrayOfTPoint): boolean;

    A+.

    EDIT du 10/03/2016 11h 59 : Remplacé la fonction DistancePointDroite() par une autre plus simple et achevé la fonction Droite2estDansDroite1()
    Images attachées Images attachées   

  11. #11
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 845
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 845
    Points : 13 622
    Points
    13 622
    Par défaut
    On arriverait tout de même le faire aussi par région pour deux lignes, mais en deux étapes.

    1. Créer un polygone avec les quatre points (les deux lignes sont chacune un segment du polygone). Si les deux lignes sont sur le même axe, la région est nulle. Sinon elles se croisent peut être mais nulle n'est incluse dans l'autre (on peut sortir).
    2. Mais même sur le même axe, le chevauchement peut n'être que partiel (ex. une ligne en X de 0 à 100 et l'autre de 50 à 150). Le workaround est de créer deux triangles en ajoutant un troisième point quelconque communs aux deux formes. On peut ainsi à nouveau passer par EqualRgn


    Cela dit, est-ce correct de considérer qu'une ligne peut être DANS une autre, ça se discute !

    ps: pas sûr que ce sujet intéresse encore jp1664...

  12. #12
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Andnotor : On arriverait tout de même à le faire aussi par région pour deux lignes, mais en deux étapes.
    Oui, mais c'est bien compliqué.

    Cela dit, est-ce correct de considérer qu'une ligne peut être DANS une autre, ça se discute !
    Bin que non : il suffit de renommer la routine TronconDroite2estDansTronconDroite1(D2, D1: TArrayOfTPoint): boolean;
    car un tronçon (situé entre 2 points) peut très bien être inclus dans un autre.
    Par contre il ne suffit pas seulement de la renommer car celle que j'ai postée hier est inachevée et en plus je vais y remplacer la function DistancePointDroite par une autre bien plus simple.
    (Je vais donc rectifier mon message d'Hier, 11h43 avec un EDIT)

    ps: pas sûr que ce sujet intéresse encore jp1664...
    Il a posé sa question le 06 mars qui est un Dimanche : il s'agit probablement d'un programmeur du Dimanche occupé à autre chose la semaine ... ???
    Attendons donc Dimanche prochain...

    A+.

  13. #13
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Voici une routine qui renvoie selon les paramètres d'appel l'array des points d'un Cercle, d'une Ellipse ou d'un Arc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    function PolyArcOuEllipse(W, H: single; Centre: TPoint; ADegOri, ADegExt, IncliDeg: Extended): TArrayOfTPoint;
    // Paramètres :
    // W = largeur du Rectangle-encadrant et H = hauteur
    // Centre = centre du Rectangle-encadrant
    // ADegOri et ADegExt = respectivement Inclinaison des rayons qui rejoignent le point-Origine, et le point-Extrémité, de l'Ellipse ou de l'Arc-d'Ellipse
    // IncliDeg := Inclinaison globale de l'Ellipse ou de l'arc d'Ellipse
    // Exemple : si ADegOri = -180° et ADegExt = 0° et IncliDeg = 0° on obtient l'Arc d'Ellipse égal à la moitié supérieure de l'Ellipse
    // et pour obtenir une Ellipse (ou) un Cercle entiers : ADegOri = -180° et ADegExt = +180°
    var Theta, dTheta, RR, dxro, dyro, si, co, Alpha,tmp: Extended; i: integer;
    begin
      SetLength(Result, 0);
      dTheta := Pi / 180;
      if ADegOri > ADegExt then begin // ADegOri doit être inférieur à ADegExt
       tmp:= ADegOri; ADegOri:= ADegExt; ADegExt:=tmp;
      end;
      Theta := DegToRad(ADegOri);
      i := 0;
      repeat
        SetLength(Result, length(Result)+1);
        SinCos(Theta, si, co);
        dxro := W * co / 2.0;
        dyro := H * si / 2.0;
        RR := Hypot(dxro, dyro);
        Alpha := arcTan22(dyro, dxro);
        SinCos(Alpha, si, co);
        Result[i].x := round(Centre.X + RR * co);
        Result[i].y := round(Centre.Y + RR * si);
        Theta := Theta + dTheta;
        inc(i);
      until Theta >= DegToRad(ADegExt);
      if IncliDeg <> 0 then RotaPolygone(Result, Centre, IncliDeg);
    end;
    Mais l'utilisation de la fonction ci-après, me renvoie un résultat aberrant : voir images.:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function FormeF2estdansF1(F2, F1: TArrayOfTPoint): Char;
    // Result =
    // - H : si F2 Hors F1
    // - D : si F2 Hors F1
    // - C : si F2 Chevauche F1
    var RgnR, Rgn1, Rgn2: HRGN;
    begin
      RgnR := CreateRectRgn(0, 0, 0, 0);
      Rgn1 := CreatePolygonRgn(F1[0], length(F1), Winding);
      Rgn2 := CreatePolygonRgn(F2[0], length(F2), Winding);
      if CombineRgn(RgnR, Rgn1, Rgn2, RGN_AND) = NULLREGION then begin Result := 'H'; EXIT; end // Ne se chevauchent pas
      else if EqualRgn(Rgn1, RgnR) then begin Result := 'H'; EXIT; end // Rgn1 dans Rgn2
      else if EqualRgn(Rgn2, RgnR) then begin Result := 'D'; EXIT; end // Rgn2 dans Rgn1
      else begin Result := 'C'; EXIT; end; // Se chevauchent partiellement
    end;
    Y aurait-il un bug de logique dans la fonction FormeF2estdansF1 : j'ai beau m'écarquiller les yeux, je ne trouve pas ??? .
    Par contre il y manque juste 3 fois le DeleteObject des trucs créés.

    A+.
    Images attachées Images attachées   

  14. #14
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    N'ayant toujours pas trouvé le bug de logique dans la version de la fonction FormeF2estdansF1 qui utilise CombineRgn, pour s'en sortir il suffit d'utiliser le première version qui boucle mais qui fonctionne correctement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function FormeF2estdansF1(F2, F1: TArrayOfTPoint): boolean;
    var i: integer;
    begin
      Result := False;
      for i := 0 to high(F2) do begin
        if not PointDansPolygone(F2[i], F1) then EXIT;
      end;
      Result := True;
    end;
    A+.

  15. #15
    Membre à l'essai
    Homme Profil pro
    responsable process chimique, hoby l'electronique, informatique
    Inscrit en
    Décembre 2015
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : responsable process chimique, hoby l'electronique, informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2015
    Messages : 12
    Points : 12
    Points
    12
    Par défaut Algorithme pour savoir si une forme est à l'intérieur d'une autre
    Merci pour toutes vos propositions.
    Que pensez vous de cette solution:
    - je définis un Timage (Timage étant limité à 2Go prévoir un facteur de réduction sur le dessin)
    ou alors passer en mode 256 couleurs pour augmenter l'espace de dessin, mais impossible de trouver la fonction.
    je dessine la forme F1 avec une couleur exp: rouge
    je rempli la forme avec la même couleur: procedure FloodFill(X, Y: Integer; Color: TColor; FillStyle: TFillStyle);
    je dessine la forme F2 avec une couleur exp: bleu
    je rempli la forme avec la même couleur: procedure FloodFill(X, Y: Integer; Color: TColor; FillStyle: TFillStyle);

    si je prend un point de F1 Pixels[X, Y: Integer]: TColor;
    si le résultat est rouge F1 n'est pas a l’intérieur de F2
    rouge+bleu F1 est a l'interieur de F2.
    idem pour un point de F2 Pixels[X, Y: Integer]: TColor;
    si le résultat est bleu F2 n'est pas a l’intérieur de F1
    rouge+bleu F2 est a l'interieur de F1.
    Est ce réalisable.

    Merci

  16. #16
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 845
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 845
    Points : 13 622
    Points
    13 622
    Par défaut
    Citation Envoyé par jp1664 Voir le message
    Que pensez vous de cette solution:
    Franchement, pas grand chose

    Citation Envoyé par jp1664 Voir le message
    Timage
    Pourquoi un TImage, il n'y a pas d'image. Un TPaintBox.

    Citation Envoyé par jp1664 Voir le message
    rouge+bleu F2 est a l'interieur de F1.
    Et comment pourrait-il être rouge+bleu ? Ta fonction de remplissage va remplacer le rouge par le bleu et non les mélanger. Pour cela il faut deux bitmaps et les mixer pixel par pixel ou passer par AlphaBlend en spécifiant une transparence.

    Citation Envoyé par jp1664 Voir le message
    Est ce réalisable.
    Ca l'est oui. Est-ce une bonne approche ? Définitivement non
    Et sans vouloir te vexer, pour un "Responsable des études", ont pourrait s'attendre à mieux...

  17. #17
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 685
    Points : 10 718
    Points
    10 718
    Par défaut
    LOL Cela s'apparente à la méthode de Monte-Carlo

    En gros tu prends X points (X à définir) aléatoires à l'intérieur de F1.
    Et pour ces X points tu fais un test d'inclusion dans F2.

    Et si le pourcentage est de 0% F2 n'est pas dans F1 ... mais ce n'est pas sûr parce que c'est au X grand près (<- ou un truc mathématiques comme cela )

  18. #18
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    jp1664 : Que pensez vous de cette solution:
    je dessine la forme F1 avec une couleur exp: rouge
    je dessine la forme F2 avec une couleur exp: bleu
    ... + FloodFill qui remplace le rouge par le bleu
    C'est rigolo.

    Tout d'abord pour dessiner tes formes complexes t'es obligé d'utiliser un Array de Points des points du contour, donc autant utiliser cet Array directement pour détecter si F2 est ou n'est pas à l'intérieur de F1,
    et ensuite on n'est pas obligé de dessiner F1 et F2 sauf si on veut visualiser.

    A+.

  19. #19
    Membre à l'essai
    Homme Profil pro
    responsable process chimique, hoby l'electronique, informatique
    Inscrit en
    Décembre 2015
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : responsable process chimique, hoby l'electronique, informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2015
    Messages : 12
    Points : 12
    Points
    12
    Par défaut Algorithme pour savoir si une forme est à l'intérieur d'une autre
    Je suis un peu triste de vos réactions, certes je suis responsable d’études mais dans le process chimique?
    L'informatique est un hobby, donc rien de professionnel, autodidacte et plutôt au niveau amateur.
    Si j'utilise la fonction 'Merge' dans les fonctions canvas , la couleur finale sera bien le OU des 2 couleurs ?

  20. #20
    Membre à l'essai
    Homme Profil pro
    responsable process chimique, hoby l'electronique, informatique
    Inscrit en
    Décembre 2015
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : responsable process chimique, hoby l'electronique, informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2015
    Messages : 12
    Points : 12
    Points
    12
    Par défaut Algorithme pour savoir si une forme est à l'intérieur d'une autre
    Pour andnotor:

    Si vous avez besoin de dimensionner un équipement (pompe,tuyauterie,réservoir)
    Donnez moi les caractéristiques de la réaction chimique (thermique principalement),
    ensuite toutes les données du process, et une vue d'ensemble du process sous forme
    de PFD (Process Flow Diagram) et de PID (Process Instrum Diagram).

    Si je peux vous aider, ce sera avec plaisir.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 4
    Dernier message: 05/04/2013, 16h08
  2. Réponses: 0
    Dernier message: 14/07/2009, 14h12
  3. Réponses: 3
    Dernier message: 28/07/2006, 16h45
  4. [Delphi] Comment savoir si un disque existe ?
    Par Jayceblaster dans le forum Langage
    Réponses: 7
    Dernier message: 29/03/2006, 15h15
  5. tableau croisé dynamique sous delphi, comment ?
    Par Brice Yao dans le forum Bases de données
    Réponses: 2
    Dernier message: 20/07/2005, 10h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo