Tracer une ligne ou un cercle avec anticrènelage

Soyez le premier à donner votre avis sur cette source.

Vue 8 083 fois - Téléchargée 603 fois

Description

voici un code permettant de tracer une ligne ou un cercle avec un anticrènelage

il vous suffit de mettre ça dans un module et d'appeller les fonctions DrawLineAA, DrawCircleAA (DrawLine et DrawCircle servent à la même chose sans anticrènelage et SetPixelAA c'est ce qui trace un pixel avec un antialias en fonction de ce qu'il y a après la virgule)

DeviceContext c'est le .hDC de l'objet sur lequel vous voulez tracer (par exemple Form1.hDC ou Picture1.hDC)

le ScaleMode de l'objet sur lequel on trace doit être sur 3 (vbPixel)

les autres paramètres sont assez explicites pour ne pas être commentés.

notez qu'avec SetPixelAA vous pouvez faire un code qui trace par exemple une élipse ou un triangle et au lieu de faire SetPixel vous remplaces par SetPixelAA en mettant des paramètres de type Double donc avec une virgule donc avec un anticrènelage :) et vous obtiendrez un superbe anticrènelage.

Source / Exemple :


' ======================================
' DECLARATIONS D'API
' ======================================

Private Declare Function GetPixel Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function SetPixelV Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long

' ======================================
' AVEC ANTICRENELAGE
' ======================================

' trace un pixel avec un anticrènelage
Public Sub SetPixelAA( _
    ByVal DeviceContext As Long, _
    ByVal XX As Single, _
    ByVal YY As Single, _
    ByVal r As Byte, _
    ByVal g As Byte, _
    ByVal b As Byte)
    
    Dim BackR       As Byte
    Dim BackG       As Byte
    Dim BackB       As Byte
    Dim BackCol     As Long
    
    Dim xi          As Long: xi = CLng(XX)
    Dim yi          As Long: yi = CLng(YY)
    
    Dim xp          As Single
    Dim yp          As Single
    
    Dim pa          As Single
    Dim pb          As Single
    Dim pc          As Single
    Dim pd          As Single
    
    If xi > XX Then xi = xi - 1
    If yi > YY Then yi = yi - 1
    
    If xi <> XX And yi <> YY Then
    
        xp = XX - xi
        yp = YY - yi
    
        pa = (1 - xp) * (1 - yp)
        pb = xp * (1 - yp)
        pc = (1 - xp) * yp
        pd = xp * yp
        
        BackCol = GetPixel(DeviceContext, xi, yi)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi, yi, RGB(r * pa + BackR * (1 - pa), g * pa + BackG * (1 - pa), b * pa + BackB * (1 - pa))
        
        BackCol = GetPixel(DeviceContext, xi + 1, yi)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi + 1, yi, RGB(r * pb + BackR * (1 - pb), g * pb + BackG * (1 - pb), b * pb + BackB * (1 - pb))
    
        BackCol = GetPixel(DeviceContext, xi, yi + 1)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi, yi + 1, RGB(r * pc + BackR * (1 - pc), g * pc + BackG * (1 - pc), b * pc + BackB * (1 - pc))

        BackCol = GetPixel(DeviceContext, xi + 1, yi + 1)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi + 1, yi + 1, RGB(r * pd + BackR * (1 - pd), g * pd + BackG * (1 - pd), b * pd + BackB * (1 - pd))
    
    ElseIf xi <> XX Then

        pc = XX - xi
        pa = 1 - (XX - xi)

        BackCol = GetPixel(DeviceContext, xi, yi)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi, yi, RGB(r * pa + BackR * (1 - pa), g * pa + BackG * (1 - pa), b * pa + BackB * (1 - pa))
        
        BackCol = GetPixel(DeviceContext, xi + 1, yi)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi + 1, yi, RGB(r * pc + BackR * (1 - pc), g * pc + BackG * (1 - pc), b * pc + BackB * (1 - pc))

    ElseIf yi <> YY Then
    
        pb = YY - yi
        pa = 1 - (YY - yi)

        BackCol = GetPixel(DeviceContext, xi, yi)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi, yi, RGB(r * pa + BackR * (1 - pa), g * pa + BackG * (1 - pa), b * pa + BackB * (1 - pa))
        
        BackCol = GetPixel(DeviceContext, xi, yi + 1)
        BackR = BackCol And &HFF
        BackG = (BackCol \ &H100) And &HFF
        BackB = (BackCol \ &H10000) And &HFF
        SetPixelV DeviceContext, xi, yi + 1, RGB(r * pb + BackR * (1 - pb), g * pb + BackG * (1 - pb), b * pb + BackB * (1 - pb))
    
    Else
        
        SetPixelV DeviceContext, XX, YY, RGB(r, g, b)
        
    End If
    
End Sub

' trace une ligne avec anticrènelage
Public Sub DrawLineAA( _
    ByVal DeviceContext As Long, _
    ByVal x1 As Single, _
    ByVal y1 As Single, _
    ByVal x2 As Single, _
    ByVal y2 As Single, _
    ByVal Color As Long)
    
    Dim m       As Single
    Dim b       As Single
    Dim XX      As Single
    Dim YY      As Single
    
    Dim rr       As Byte: rr = Color And &HFF
    Dim gg       As Byte: gg = (Color \ &H100) And &HFF
    Dim bb       As Byte: bb = (Color \ &H10000) And &HFF
    
    If x2 = x1 Then
        m = (y2 - y1) / 1
    Else
        m = (y2 - y1) / (x2 - x1)
    End If
    
    b = y1 - (m * x1)
    
    If Abs(m) <= 1 Then
        If x1 <= x2 Then
            For XX = x1 To x2 - 1
                YY = m * XX + b
                SetPixelAA DeviceContext, XX, YY, rr, gg, bb
            Next XX
        Else
            For XX = x2 + 1 To x1
                YY = m * XX + b
                SetPixelAA DeviceContext, XX, YY, rr, gg, bb
            Next XX
        End If
    Else
        If y1 <= y2 Then
            For YY = y1 To y2 - 1
                XX = (YY - b) / m
                SetPixelAA DeviceContext, XX, YY, rr, gg, bb
            Next YY
        Else
            For YY = y2 + 1 To y1
                XX = (YY - b) / m
                SetPixelAA DeviceContext, XX, YY, rr, gg, bb
            Next YY
        End If
    End If
    
End Sub

' trace un cercle avec anticrènelage
Public Sub DrawCircleAA( _
    ByVal DeviceContext As Long, _
    ByVal X As Single, _
    ByVal Y As Single, _
    ByVal Rayon As Single, _
    ByVal Color As Long)

    Dim XX      As Single
    Dim YY      As Single

    Dim rr       As Byte: rr = Color And &HFF
    Dim gg       As Byte: gg = (Color \ &H100) And &HFF
    Dim bb       As Byte: bb = (Color \ &H10000) And &HFF
    
    If Rayon = 0 Then Exit Sub
    
    SetPixelAA DeviceContext, X + Rayon, Y, rr, gg, bb
    SetPixelAA DeviceContext, X, Y + Rayon, rr, gg, bb
    SetPixelAA DeviceContext, X, Y - Rayon, rr, gg, bb
    SetPixelAA DeviceContext, X - Rayon, Y, rr, gg, bb
    
    For XX = 1 To Rayon * 0.71 ' = 1 / Sqr(2)
        
        YY = Sqr(Rayon * Rayon - XX * XX)
        
        SetPixelAA DeviceContext, XX + X, YY + Y, rr, gg, bb
        SetPixelAA DeviceContext, -XX + X, YY + Y, rr, gg, bb
        SetPixelAA DeviceContext, XX + X, -YY + Y, rr, gg, bb
        SetPixelAA DeviceContext, -XX + X, -YY + Y, rr, gg, bb

        SetPixelAA DeviceContext, YY + X, XX + Y, rr, gg, bb
        SetPixelAA DeviceContext, -YY + X, XX + Y, rr, gg, bb
        SetPixelAA DeviceContext, YY + X, -XX + Y, rr, gg, bb
        SetPixelAA DeviceContext, -YY + X, -XX + Y, rr, gg, bb
        
    Next XX
    
End Sub

' ======================================
' SANS ANTICRENELAGE
' ======================================

' trace une ligne
Public Sub DrawLine( _
    ByVal DeviceContext As Long, _
    ByVal x1 As Long, _
    ByVal y1 As Long, _
    ByVal x2 As Single, _
    ByVal y2 As Single, _
    ByVal Color As Long)
    
    Dim m       As Single
    Dim b       As Single
    Dim XX      As Long
    Dim YY      As Long
    
    If x2 = x1 Then
        m = (y2 - y1) / 1
    Else
        m = (y2 - y1) / (x2 - x1)
    End If
    
    b = y1 - (m * x1)
    
    If Abs(m) <= 1 Then
        If x1 <= x2 Then
            For XX = x1 To x2 - 1
                YY = m * XX + b
                SetPixelV DeviceContext, XX, YY, Color
            Next XX
        Else
            For XX = x2 + 1 To x1
                YY = m * XX + b
                SetPixelV DeviceContext, XX, YY, Color
            Next XX
        End If
    Else
        If y1 <= y2 Then
            For YY = y1 To y2 - 1
                XX = (YY - b) / m
                SetPixelV DeviceContext, XX, YY, Color
            Next YY
        Else
            For YY = y2 + 1 To y1
                XX = (YY - b) / m
                SetPixelV DeviceContext, XX, YY, Color
            Next YY
        End If
    End If
    
End Sub

' trace un cercle
Public Sub DrawCircle( _
    ByVal DeviceContext As Long, _
    ByVal X As Long, _
    ByVal Y As Long, _
    ByVal Rayon As Long, _
    ByVal Color As Long)

    Dim XX      As Long
    Dim YY      As Long

    Dim rr       As Byte: rr = Color And &HFF
    Dim gg       As Byte: gg = (Color \ &H100) And &HFF
    Dim bb       As Byte: bb = (Color \ &H10000) And &HFF
    
    If Rayon = 0 Then Exit Sub
    
    SetPixelV DeviceContext, X + Rayon, Y, Color
    SetPixelV DeviceContext, X, Y + Rayon, Color
    SetPixelV DeviceContext, X, Y - Rayon, Color
    SetPixelV DeviceContext, X - Rayon, Y, Color
    
    For XX = 1 To Rayon * 0.71 ' = 1 / Sqr(2)
        
        YY = Sqr(Rayon * Rayon - XX * XX)
        
        SetPixelV DeviceContext, XX + X, YY + Y, Color
        SetPixelV DeviceContext, -XX + X, YY + Y, Color
        SetPixelV DeviceContext, XX + X, -YY + Y, Color
        SetPixelV DeviceContext, -XX + X, -YY + Y, Color

        SetPixelV DeviceContext, YY + X, XX + Y, Color
        SetPixelV DeviceContext, -YY + X, XX + Y, Color
        SetPixelV DeviceContext, YY + X, -XX + Y, Color
        SetPixelV DeviceContext, -YY + X, -XX + Y, Color
        
    Next XX
    
End Sub

Conclusion :


14/09/2004 :
- j'ai corrigé la faute à "anticrènelage" selon l'académie française.

24/06/2004 :
- j'ai remplacé SetPixel par SetPixelV
- j'ai viré les Double que j'ai remplacé par des Long là ou il n'y avait pas lieu d'utiliser des Double.
- J'ai remplacé tous les Double par des Single qui sont plus rapides que les Doubles car moins précis (mais nous n'avons pas besoin de Double ici)

Merci à vlad2 ;)

22/06/2004
- J'ai modifié un peu le code dans SetPixelAA, en effet il y avait une erreur, maintenant c'est nickel !

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
25
Date d'inscription
lundi 15 novembre 2004
Statut
Membre
Dernière intervention
29 décembre 2009

Je peux ous mettre mon source pour vérification de mon topic
hobbyF1
Messages postés
25
Date d'inscription
lundi 15 novembre 2004
Statut
Membre
Dernière intervention
29 décembre 2009

hi
Mon petit mot en passant car je fais du delphi, tout le monde n'est pas parfait....hi,hi

Ligne 290:
YY = sqr(Rayon*Rayon - XX*XX) ??? bizarre

Je ne connais pas VB mais SQR en pascal fais le carré et non la racine carrée.EN Pascal c'est SQRT qu'il faut mettre. (bizare aussi)

En plus les boucles 'FOR' avec du boolean, ne sont pas acceptées.
J'ai été obligé de faire des 'REPEAT'.....'UNTIL' pour que les conditions booleenes soit acceptées.

En plus en VB vous melangez les 'byte avec les single' dans les operations,Qui n'est pas accepté non plus.

Resultat: je fais bien des lignes et des cercles, mais sans anti aliasing.
A+++ les VB
Messages postés
1488
Date d'inscription
mercredi 5 février 2003
Statut
Membre
Dernière intervention
3 décembre 2007
22
Encore merci pour toutes ces précisions...

Vlad2i : ok, maintenant je crois avoir vraiment tout compris...

XbY : Là je comprends mieux :-) Pour la 3D il faut considérer les objets au premier plan comme étant les plus précis et disparaissant au dessus(-1) de ce 1er plan. Le fichier, quant à lui, ne doit stocker que ce qui est important... Rien n'empêche d'utiliser des fonctions de flood 3D (entre autre)... Enfin, quand j'aurais le temps je pense faire une petite démo ici. Mais il est inévitable de passer par les "Wu" (ou du moins, une technique similaire).
Messages postés
337
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
15 avril 2006

ScSami >
"PI=4*ATN(1)... en radians. Ca marche, c'est super. Mais bon, je serais d'accord avec ça si je le comprennais..."

tu comprend pas pourquoi ca fait Pi ???
ATN(1) est l'angle dont la tangeante 1 c a d 45°.Puisque le tour du cercle fait 2Pi radiand 360°, 4*45° = 180° = Pi radian. dc 4*ATN(1) = Pi.

Pr la 3D volumique tu veux dire coder tout les pixels dans ton fichier??? tu va avoir plusieur probleme... qd les objets proche de l'observateur auront une resolution trop faible et on vera les "pixels cubique" alors que ceux plus loin auront de l'information qu'on ne verra pas.
A moins que tu dessine en axonometries c a d sans point de fuite puisque les objet auront la meme taille qu'il soit loin ou proche. La il y a une technique tout bête avec des matrices c vraiment tailler pour être coder ^^
Messages postés
285
Date d'inscription
mercredi 20 août 2003
Statut
Membre
Dernière intervention
13 février 2005

ScSami> je doutes que ce soit le lieu le plus approprié à tes questions métaphyisiques...

Pi = 4atn(1) ...

Tu as aussi pi²/6 = 1/1² + 1/2² + 1/3² + 1/4² + 1/5² + 1/6² etc ...

Le problème se trouvera au niveau de la précision des chiffres que tu utilises

pi ... 3.14159265358979323846264338327950288 41971693993751058209749445923 ...


En fait, il n'existe pas d'expression finie de Pi, car ce nombre est transcendant irrationnel, et on n'a que des algèbres infinies pour ce type de nombre. Donc, il faut faire tourner un calcul, théoriquement à l'infini, pour avoir le resultat exact. N'ayant pas tout ce temps, on se contente de le faire tourner "un certain temps" ce qui te donne "un certain nombre de décimales"

Ex: tu intègres de infini- à infini+ la fonction e^(-x²)dx et tu obtiendras la racine de pi... Ou la fonction gamma(1/2) = racine de pi ... ou l'intégrale de racine de (1--x²) sur [0;1] donne pi/4

Une meilleure méthode consiste à calculer les arctangentes, qui sont faciles a développer

ex: atn(1) = 4 (atn(1/5) - 4atn(1/239))
ou atn(1) = 44atn(1/57)+7atn(1/239)-12atn(1/682)+24atn(1/12943)

Et comme tu as atn(1) = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 ...

Tu peux facilement développer...

Liens utiles :
http://jc.michel.free.fr/pi.php
http://ktd.club.fr/programmation/cpp-metaprog.php

PS. Pour bézier, c'est une interpolation pondérée du troisième degré. Si tu as l'equation de bézier en 2D, il suffit d'ajouter la troisième, Z, pour avoir le resultat escompté. Quant aux rendus volumiques, nul besoin des Wu Pixels...

Bonne chance

Vlad
Afficher les 24 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.