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

Langage Delphi Discussion :

Code "intelligent" de traçage d'un cercle sur un DrawGrid


Sujet :

Langage Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 20
    Par défaut Code "intelligent" de traçage d'un cercle sur un DrawGrid
    Bonjour,

    J'essaye de "dessiner" un cercle sur un DrawGrid comme présenté sur la figure dessous. Ceci doit étre réaliser avec un code en Delphi bien évidemment et non par la souris par exemple. Dans l'image en PJ j'ai fait un "zoom in" pour que vous poussiez analyser la situation. Chaque cellule (en rouge) ne doit avoir que 2 cellules voisines de 8 cellues autour d'elle. Dans le cas réel, ce DrawGrid aura comme largeur de cellule 1mm, donc je ne cherche pas vraiment un cercle "parfait" (comme le cercle en bleu) mais une bonne approximation de façon après faire un "zoom out" je vois presque un cercle parfait.

    Alors, j'ai codé ça :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    procedure TForm10.okClick(Sender: TObject);
    var
    x,y,r,i,k1,k2:integer;
    begin
    x:=strtoint(edit1.Text);
    y:=strtoint(edit1.Text);
    r:=strtoint(edit3.Text);
    if (r<0) then
    MessageBox(0,'Erreur : Rayon négatif !','Attention !',MB_OK)
    else
    begin
    k1:=x;
    k2:=y+r;
    for i:=0 to r do
      begin
      form7.dg.canvas.brush.color := clyellow;
      rect := form7.dg.CellRect(k1,k2);
      form7.dg.Canvas.FillRect(rect);
      k1:=k1+1;
      k2:=k2-1;
      end;
     
    for i:=0 to r do
      begin
      form7.dg.canvas.brush.color := clyellow;
      rect := form7.dg.CellRect(k1,k2);
      form7.dg.Canvas.FillRect(rect);
      k1:=k1-1;
      k2:=k2-1;
      end;
    for i:=0 to r do
      begin
      form7.dg.canvas.brush.color := clyellow;
      rect := form7.dg.CellRect(k1,k2);
      form7.dg.Canvas.FillRect(rect);
      k1:=k1-1;
      k2:=k2+1;
      end;
    for i:=0 to r do
      begin
      form7.dg.canvas.brush.color := clyellow;
      rect := form7.dg.CellRect(k1,k2);
      form7.dg.Canvas.FillRect(rect);
      k1:=k1+1;
      k2:=k2+1;
      end;
    end;
     
    end;
    Mais ce code trace un losange

    Les données à fournir par l'utilisateur pour tracer le cercle sont X et Y coordonnées du centre du cercle et R le rayon.

    J'ai essayé d'utilse une équation paramétrique d'un cercle mais toujours bloqué.

    Avez-vous une proposition (ou un code pourquoi pas ^^) pour améliorer le code au-dessus ou pour recommencer dès le début SVP ?

    Merci d'avance.
    Images attachées Images attachées  

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 089
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 089
    Par défaut
    Pourquoi ne pas appliquer Pythagore ?

    En Pseudo Code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for CurrX := 0 to MaxX do
    begin
      for CurrY := 0 to MaxY do
      begin
        if Sqr(CentreX - CurrX) + Sqr(CentreY - CurrY) <= Sqr(R) then
        begin
          DessinePastille
        end
      end;
    end;
    Cela va te remplir tout le disque, ... à toi de trouver la fourchette qui fera que cela ne remplira que le cercle ... genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (Sqr(CentreX - CurrX) + Sqr(CentreY - CurrY) <= Sqr(R) * 0.95)
    and (Sqr(CentreX - CurrX) + Sqr(CentreY - CurrY) <= Sqr(R) * 1.05) then
    à la place de la fourchette, tu peux aussi vérifier les 4 Pastilles à coté ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre Expert
    Avatar de Archimède
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2005
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 644
    Par défaut
    le mieux pour tracer un cercle, est de raisonner en coordonnées polaires
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    x:=O.x+round(R*cos teta);
    y:=O.y+round(R*sin teta);
    R représentera ton rayon en nombre de cases.

    O un tpoint, le centre de ton cercle (coordonnées d'une case Oarow,Oacol)
    dans ta drawgrid
    x et y seront les coordonnées des cases qui représentent le cercle.

    tu fais évoluer teta de 0 à 2 pi avec for to do et tu colories tes cases avec des fillrect.

  4. #4
    Expert confirmé Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Par défaut
    Bonjour,

    Si on est pas géné par le temps de calcul, on crée une liste de cellules candidates qui sont l'ensemble des cellules du plan telles que la distance de leur centre au cercle soit inférieure ou égale au coté de la cellule.

    Ensuite on traite la liste, jusqu'à ce qu'elle soit vide, de la façon suivante :
    • on valide la cellule de la liste dont le centre est le plus proche du cercle. En triant la liste sur la distance du centre de la cellule au cercle, il suffit de prendre le premier candidat.
    • on élimine de la liste la cellule retenue et les candidats restants devenus inadéquats (ceux qui ont plus de 2 cellules déjà tracées contigues). En fait si la liste est triée, il suffit au moment de traiter la case suivante de la liste de vérifier si elle reste toujours Ok en testant son nombre de voisins, et en cas d'échec on passe au suivant.

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 089
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 089
    Par défaut
    L'Idée d'exclusion de Graffito est pas mal, le calcul de distance peu se faire via Pythagore

    Pour le Sin\Cosinus, effectivement, c'est comme cela que j'ai procédé pour faire une horloge analogique sur mon HP48Gx il y a bien cela 10ans ... faudrait qu'un jour, je le refasse en delphi ...

    PS : Form10, Form7, ça va tu t'y retrouves, pense à prendre l'habitude de nommer tes labels, bouton, formulaire, ..
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    Le mieux c'est de dessiner un polygone avec suffisamment de segments pour lui donner l'apparence d'un cercle

    j'ai fait ça y'a déjà fort longtemps dans DOSBOX par exemple. Pour le tracé de chaque segment on prendra l'algorithme de bresenham qui donne cet effet d'escalier recherché.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 937
    Billets dans le blog
    6
    Par défaut
    un exemple d'implémentation de l'algo de Bresenham par firejoker sur Phidels.com : http://www.phidels.com/php/index.php...u=dessin#id609
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  8. #8
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 20
    Par défaut
    Bonjour,

    Merci à vous !

    @ ShaiLeTroll >> nickel disque plein ^^ mais du coup, la fourchette ne fonctionne pas correctement. Enfait j'ai mis l'application zippée en PJ, elle fonctionne pour une valeur de rayon =15 parfaitement mais si je change R=16 alors là j'ai un cercle non continu (ya des cellules qui n'ont qu'un seul voisin). En plus si j'augmente R, parfois j'aurais des cellules qui ont plus que 2 voisins. Aussi pour R<15 cela ne fonctionne pas (bon oublions R<15 pour le moment car je n'ai pas besoin de cercles de rayon inférieur à 15).

    J'ai remis tas solution deux fois successive pour vider le disque de façon que j'ai jouer sur les valeurs de la fourchette de façon que je dessine un disque blanc dans le disque rouge inférieur à lui d'un seul pas. bon à re-voir ceci dans ce code (il est commenté déjà).

    Donc je veux tracer un cercle de R=16 ou plus en respectant la condition mentionnée dans mon poste initiale : chaque cellule DOIT avoir QUE 2 seules cellules voisines.



    @ Archimède >> Hum .. là j'ai déjà pensé aussi aux coordonnées polaires (malgré que j'ai "sautté" le préparatoire dans mon cursus ). Mais je dois dans ce cas évoluer téta. La boucle FOR n'accepte que le type entier comme compteur, donc j'ai lancer un "i" de 0 à 360 en augmentant téta chaque fois mais j'ai pas eu le cercle malgré tout
    puis-je voir une petite boucle illustant ton idée STP ? car là, je vois pas trop comment rédiger ce que tu viens de dire.

    Et pour les autres postes, je n'ai pas lu que les deux premiers postes , donc je vais jetter un oeil ce soir et je vous tiendrais au courant demain ! Merci pour vous tous.


    A+
    Fichiers attachés Fichiers attachés

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