Dessiner une règle graduée - problème d'arrondi selon le zoom

Résolu
mioumiounorris Messages postés 57 Date d'inscription dimanche 24 février 2008 Statut Membre Dernière intervention 4 septembre 2011 - 7 août 2009 à 14:25
mioumiounorris Messages postés 57 Date d'inscription dimanche 24 février 2008 Statut Membre Dernière intervention 4 septembre 2011 - 31 août 2009 à 11:27
Bonjour.
Je suis actuellement en train de programmer un petit logiciel où on peut charger un image et zoomer (+ ou -) dessus. Pas de soucis de ce côté là.
En haut et en bas de cette image, j'ai créée des règles graduées en pixels à la même manière que Photoshop.
J'utilise donc les fonctions de dessin du framework (DrawLine et DrawString) pour dessiner mes graduations. J'ai voulu recréer exactement le même comportement que Toshop, à savoir, selon la valeur de zoom, les graduations ne sont pas identiques. J'ai donc noté entièrement les différents cas de figure rencontrés dans Photoshop.
Jusque là pas de soucis. J'arrive selon la valeur de zoom, à dessiner des graduations identiques à Toshop, sauf que je me retrouve avec un sérieux problème d'arrondi.
En effet, je dois tracer une graduation en X a une valeur fixe, alors que forcément, en utilisant une formule de pourcentage par rapport à la taille d'origine de l'image, je me retrouve avec des valeurs à virgule.
Du coup, certaines graduations se retrouvent un coup avec un pixel de retard, un coup un pixel ou deux trop en avant, un coup c'est bon ...

Pour illustrer le problème voilà quelques captures:

Voici donc le cas de figure à zoom 100% où je n'ai pas de soucis
Mais ensuite ça se gatte...

Et un autre cas avec un style de graduation différent:


J'ai bien entendu essayé d'arrondir de toutes les façons possibles, mais ce n'est pas si simple. Un coup il me faudrait arrondir au dessus, un coup en dessous ... etc ... et là je suis perdu . Voici une partie de mon code (fonction exécutée à chaque fois que je zoom):
Public Sub drawHorizontalRegle(ByVal zoomValue As Integer, ByVal widthActuelleImg As Integer)
        bitmapRegleHorizontale = New Bitmap(CInt((widthActuelleImg * zoomValue) / 100), 16)
        Dim NewGraphic As Graphics = Graphics.FromImage(bitmapRegleHorizontale)
        NewGraphic.DrawLine(penRegles, 0, 15, 10000, 15) '1ere ligne horizontale en bas de la règle
        'NewGraphic.DrawString(Str(0), fontRegles, Brushes.Black, 0, -2)

        Dim typeRegle As Integer = 1
        Dim pasAafficher As Integer 'A caster en String pour l'afficher plus tard

        'pas des traits selon le zoom
        Dim grandeBarreTousLes As Integer = CInt((zoomValue * 50) / 100) '50px à zoom 100%
        Dim moyenneBarreTousLes As Integer = CInt((zoomValue * 10) / 100) '10px à zoom 100%
        Dim petiteBarreTousLes As Integer = CInt((zoomValue * 5) / 100) '5px à zoom 100%

        Select Case zoomValue 'test le zoom pour connaitre le type de règle...avec des traits petits ou moyens ou grands ou un mélange de tout ça
            Case 1 'si le zoom est à 1%
                typeRegle 1 : pasAafficher 5000
                grandeBarreTousLes = CInt((zoomValue * 5000) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 1000) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 500) / 100))
            Case 2
                typeRegle 2 : pasAafficher 2000
                grandeBarreTousLes = CInt((zoomValue * 2000) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 1000) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 500) / 100))
            Case 3
                typeRegle 3 : pasAafficher 2000
                grandeBarreTousLes = CInt((zoomValue * 2000) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 1000) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 200) / 100))
            Case 4
                typeRegle 4 : pasAafficher 1000
                grandeBarreTousLes = CInt((zoomValue * 1000) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 200) / 100))
            Case 5, 6
                typeRegle 3 : pasAafficher 1000
                grandeBarreTousLes = CInt((zoomValue * 1000) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 500) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 100) / 100))
            Case 7, 8, 9 'si le zoom est de 7% ou 8% ou 9%
                typeRegle 4 : pasAafficher 500
                grandeBarreTousLes = CInt((zoomValue * 500) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 100) / 100))
            Case 10 To 15 'si le zoom est entre 10% et 15% inclus
                typeRegle 1 : pasAafficher 500
                grandeBarreTousLes = CInt((zoomValue * 500) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 100) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 50) / 100))
            Case 16 To 24
                typeRegle 2 : pasAafficher 200
                grandeBarreTousLes = CInt((zoomValue * 200) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 100) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 50) / 100))
            Case 25 To 31
                typeRegle 3 : pasAafficher 200
                grandeBarreTousLes = CInt((zoomValue * 200) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 100) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 20) / 100))
            Case 32 To 49
                typeRegle 4 : pasAafficher 100
                grandeBarreTousLes = CInt((zoomValue * 100) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 20) / 100))
            Case 50 To 63
                typeRegle 3 : pasAafficher 100
                grandeBarreTousLes = CInt((zoomValue * 100) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 50) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 10) / 100))
            Case 64 To 99
                typeRegle 4 : pasAafficher 50
                grandeBarreTousLes = CInt((zoomValue * 50) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Ceiling((zoomValue * 10) / 100))
            Case 100 To 159
                typeRegle 1 : pasAafficher 50
                grandeBarreTousLes = CInt((zoomValue * 50) / 100) '50px à zoom 100%
                moyenneBarreTousLes = CInt((zoomValue * 10) / 100) '10px à zoom 100%
                petiteBarreTousLes = CInt(Floor((zoomValue * 5) / 100)) '5px à zoom 100%
            Case 160 To 249
                typeRegle 2 : pasAafficher 20
                grandeBarreTousLes = CInt((zoomValue * 20) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Floor((zoomValue * 5) / 100))
            Case 250 To 319
                typeRegle 3 : pasAafficher 20
                grandeBarreTousLes = CInt((zoomValue * 20) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Floor((zoomValue * 2) / 100))
            Case 320 To 499
                typeRegle 4 : pasAafficher 10
                grandeBarreTousLes = CInt((zoomValue * 10) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Floor((zoomValue * 2) / 100))
            Case 500 To 639
                typeRegle 3 : pasAafficher 10
                grandeBarreTousLes = CInt((zoomValue * 10) / 100)
                moyenneBarreTousLes = CInt((zoomValue * 5) / 100)
                petiteBarreTousLes = CInt(Floor(zoomValue / 100))
            Case 640 To 1599
                typeRegle 4 : pasAafficher 5
                grandeBarreTousLes = CInt(Ceiling((zoomValue * 5) / 100))
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Floor(zoomValue / 100))
            Case 1600 To 3199
                typeRegle 5 : pasAafficher 2
                grandeBarreTousLes = CInt((zoomValue * 2) / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                petiteBarreTousLes = CInt(Floor(zoomValue / 100))
            Case Is >= 3200 'si le zoom est supérieur ou égal à 3200%
                typeRegle 6 : pasAafficher 1
                grandeBarreTousLes = CInt(zoomValue / 100)
                'moyenneBarreTousLes = CInt((zoomValue * 10) / 100)
                'petiteBarreTousLes = CInt((zoomValue * 2) / 100)
        End Select

        'dessin des grandes barres ... y'en a toujours donc pas besoin de tester le type de règle
        Dim multiplicateurPasG As Integer = 0
        For g As Integer = 0 To widthActuelleImg * 2 Step grandeBarreTousLes
            NewGraphic.DrawLine(penRegles, g, 0, g, 16)
            NewGraphic.DrawString(Str(pasAafficher * multiplicateurPasG), fontRegles, Brushes.Black, g, -2)
            multiplicateurPasG = multiplicateurPasG + 1
        Next g

        If typeRegle 1 Or typeRegle 2 Or typeRegle = 3 Then 'si le type de règle est a/b ou c on peut dessiner les traits moyens
            'dessin des moyennes barres
            For m As Integer = moyenneBarreTousLes To widthActuelleImg * 2 Step moyenneBarreTousLes
                NewGraphic.DrawLine(penRegles, m, 9, m, 16)
            Next m
        End If
        
        If Not typeRegle = 6 Then
            'dessin des petites barres
            For p As Integer = petiteBarreTousLes To widthActuelleImg * 2 Step petiteBarreTousLes
                NewGraphic.DrawLine(penRegles, p, 12, p, 16)
            Next p
        End If
        

        Form1.regleHorizontale.Image = bitmapRegleHorizontale


    End Sub


Oui, vous aurez remarqué que je suis débutant en programmation, et que j'écris du code qui pourrait certainement être beaucoup plus court ou plus intelligemment écrit ... m'enfin.
Quelqu'un s'est-il déjà essayé à recréer un système de règle graduée selon un zoom ? Ou peut-être voyez-vous une astuce pour faire un test sur je ne sais quoi pour arrondir à la bonne valeur selon le cas ?
A voir également:

5 réponses

Shadowbiwan Messages postés 5 Date d'inscription mardi 1 août 2006 Statut Membre Dernière intervention 30 août 2009
8 août 2009 à 16:21
Salut mioumiounorris

Alors le problème que tu rencontres est du a un problème d'imprécision. En effet, tes 3 valeurs grandeBarreTousLes , moyenneBarreTousLes et petiteBarreTousLes ne devraient pas etre des entier car pour que ce soit des valeurs entières, il y aura un décalage de 0.5 au maximum entre la valeur réelle et la valeur réelle. Or tu utilises cette valeur un grand nombre de fois ce qui entraine une énorme imprécision : si tu utilises cette valeur 100 fois, tu pourrais avoir au maximum un décalage de 50pixels entre l'endroit ou ta barre devrait etre affichée et l'endroit ou elle est censée etre !!! (j'espère que tu as réussis à me comprendre car c'est un peu cafouilleux ce que je raconte)
Il y a donc ci dessous un code "corrigé" avec une boucle d'affichage que je trouve meilleure mais qui pourrais surement être améliorée.
Passes une bonne journée,
Cordialement, Shadowbiwan.

Public Sub drawHorizontalRegle(ByVal zoomValue As Integer, ByVal widthActuelleImg As Integer)

        Dim penRegles As New Pen(Color.Black, 1)
        Dim fontRegles As New Font("Arial", 8)
        Dim bitmapRegleHorizontale As New Bitmap(CInt((widthActuelleImg * zoomValue) / 100), 16)
        Dim NewGraphic As Graphics = Graphics.FromImage(bitmapRegleHorizontale)
        NewGraphic.DrawLine(penRegles, 0, 15, 10000, 15) '1ere ligne horizontale en bas de la règle

        Dim typeRegle As Integer = 1
        Dim pasAafficher As Integer 'A caster en String pour l'afficher plus tard

        'pas des traits selon le zoom
        '/!\ Changés en single !!
        Dim grandeBarreTousLes As Single = (zoomValue * 50) / 100 '50px à zoom 100%
        Dim moyenneBarreTousLes As Single = (zoomValue * 10) / 100 '10px à zoom 100%
        Dim petiteBarreTousLes As Single = (zoomValue * 5) / 100 '5px à zoom 100%

        Select Case zoomValue 'test le zoom pour connaitre le type de règle...avec des traits petits ou moyens ou grands ou un mélange de tout ça
            Case 1 'si le zoom est à 1%
                typeRegle 1 : pasAafficher 5000
                grandeBarreTousLes = (zoomValue * 5000) / 100
                moyenneBarreTousLes = (zoomValue * 1000) / 100
                petiteBarreTousLes = (zoomValue * 500) / 100
            Case 2
                typeRegle 2 : pasAafficher 2000
                grandeBarreTousLes = (zoomValue * 2000) / 100
                moyenneBarreTousLes = (zoomValue * 1000) / 100
                petiteBarreTousLes = (zoomValue * 500) / 100
            Case 3
                typeRegle 3 : pasAafficher 2000
                grandeBarreTousLes = (zoomValue * 2000) / 100
                moyenneBarreTousLes = (zoomValue * 1000) / 100
                petiteBarreTousLes = (zoomValue * 200) / 100
            Case 4
                typeRegle 4 : pasAafficher 1000
                grandeBarreTousLes = (zoomValue * 1000) / 100
                petiteBarreTousLes = (zoomValue * 200) / 100
            Case 5, 6
                typeRegle 3 : pasAafficher 1000
                grandeBarreTousLes = (zoomValue * 1000) / 100
                moyenneBarreTousLes = (zoomValue * 500) / 100
                petiteBarreTousLes = (zoomValue * 100) / 100
            Case 7, 8, 9 'si le zoom est de 7% ou 8% ou 9%
                typeRegle 4 : pasAafficher 500
                grandeBarreTousLes = (zoomValue * 500) / 100
                petiteBarreTousLes = (zoomValue * 100) / 100
            Case 10 To 15 'si le zoom est entre 10% et 15% inclus
                typeRegle 1 : pasAafficher 500
                grandeBarreTousLes = (zoomValue * 500) / 100
                moyenneBarreTousLes = (zoomValue * 100) / 100
                petiteBarreTousLes = (zoomValue * 50) / 100
            Case 16 To 24
                typeRegle 2 : pasAafficher 200
                grandeBarreTousLes = (zoomValue * 200) / 100
                moyenneBarreTousLes = (zoomValue * 100) / 100
                petiteBarreTousLes = (zoomValue * 50) / 100
            Case 25 To 31
                typeRegle 3 : pasAafficher 200
                grandeBarreTousLes = (zoomValue * 200) / 100
                moyenneBarreTousLes = (zoomValue * 100) / 100
                petiteBarreTousLes = (zoomValue * 20) / 100
            Case 32 To 49
                typeRegle 4 : pasAafficher 100
                grandeBarreTousLes = (zoomValue * 100) / 100
                petiteBarreTousLes = (zoomValue * 20) / 100
            Case 50 To 63
                typeRegle 3 : pasAafficher 100
                grandeBarreTousLes = (zoomValue * 100) / 100
                moyenneBarreTousLes = (zoomValue * 50) / 100
                petiteBarreTousLes = (zoomValue * 10) / 100
            Case 64 To 99
                typeRegle 4 : pasAafficher 50
                grandeBarreTousLes = (zoomValue * 50) / 100
                petiteBarreTousLes = (zoomValue * 10) / 100
            Case 100 To 159
                typeRegle 1 : pasAafficher 50
                grandeBarreTousLes = (zoomValue * 50) / 100 '50px à zoom 100%
                moyenneBarreTousLes = (zoomValue * 10) / 100 '10px à zoom 100%
                petiteBarreTousLes = (zoomValue * 5) / 100 '5px à zoom 100%
            Case 160 To 249
                typeRegle 2 : pasAafficher 20
                grandeBarreTousLes = (zoomValue * 20) / 100
                moyenneBarreTousLes = (zoomValue * 10) / 100
                petiteBarreTousLes = (zoomValue * 5) / 100
            Case 250 To 319
                typeRegle 3 : pasAafficher 20
                grandeBarreTousLes = (zoomValue * 20) / 100
                moyenneBarreTousLes = (zoomValue * 10) / 100
                petiteBarreTousLes = (zoomValue * 2) / 100
            Case 320 To 499
                typeRegle 4 : pasAafficher 10
                grandeBarreTousLes = (zoomValue * 10) / 100
                petiteBarreTousLes = (zoomValue * 2) / 100
            Case 500 To 639
                typeRegle 3 : pasAafficher 10
                grandeBarreTousLes = (zoomValue * 10) / 100
                moyenneBarreTousLes = (zoomValue * 5) / 100
                petiteBarreTousLes = zoomValue / 100
            Case 640 To 1599
                typeRegle 4 : pasAafficher 5
                grandeBarreTousLes = (zoomValue * 5) / 100
                petiteBarreTousLes = zoomValue / 100
            Case 1600 To 3199
                typeRegle 5 : pasAafficher 2
                grandeBarreTousLes = (zoomValue * 2) / 100
                petiteBarreTousLes = zoomValue / 100
            Case Is >= 3200 'si le zoom est supérieur ou égal à 3200%
                typeRegle 6 : pasAafficher 1
                grandeBarreTousLes = zoomValue / 100
        End Select

        Dim ActualLenght As Integer = 0
        Dim NbGrandeBarre As Integer = 0
        Dim NbMoyenneBarre As Integer = 0
        Dim NbPetiteBarre As Integer = 0
        Dim multiplicateurPasG As Integer = 0
        While ActualLenght <= widthActuelleImg
            If ActualLenght = CInt(NbGrandeBarre * grandeBarreTousLes) Then
                NewGraphic.DrawLine(penRegles, ActualLenght, 0, ActualLenght, 16)
                NewGraphic.DrawString(Str(pasAafficher * multiplicateurPasG), fontRegles, Brushes.Black, ActualLenght, -2)
                multiplicateurPasG = multiplicateurPasG + 1
                NbGrandeBarre += 1
                NbMoyenneBarre += 1
                NbPetiteBarre += 1
            ElseIf (typeRegle 1 Or typeRegle 2 Or typeRegle = 3) AndAlso ActualLenght = CInt(NbMoyenneBarre * moyenneBarreTousLes) Then
                NewGraphic.DrawLine(penRegles, ActualLenght, 9, ActualLenght, 16)
                NbMoyenneBarre += 1
                NbPetiteBarre += 1
            ElseIf Not typeRegle 6 AndAlso ActualLenght CInt(NbPetiteBarre * petiteBarreTousLes) Then
                NewGraphic.DrawLine(penRegles, ActualLenght, 12, ActualLenght, 16)
                NbPetiteBarre += 1
            End If

            ActualLenght += 1
        End While
        Pic.Image = bitmapRegleHorizontale

    End Sub
3
mioumiounorris Messages postés 57 Date d'inscription dimanche 24 février 2008 Statut Membre Dernière intervention 4 septembre 2011
7 août 2009 à 18:04
Ooops désolé pour la dernière image en double
Voici celle que je voulais mettre:

D'ailleurs, je n'ai pas vu de fonction "éditer ce message"
0
mioumiounorris Messages postés 57 Date d'inscription dimanche 24 février 2008 Statut Membre Dernière intervention 4 septembre 2011
20 août 2009 à 12:29
Salut Shadowbiwan !
Merci beaucoup pour ton aide ! Je n'ai pas réussi à faire fonctionner le truc avec ton système de boucle "While", je suis donc resté avec mes "For / Next".
En revanche ça marche du tonnerre en utilisant des Single à la place des Integers
Il est clair qu'avec mon système de boucle, c'est peut-être un peu lent et pas du tout optimisé, mais au moins ça fonctionne. J'essayerais au fur-et-à-mesure d'améliorer tout ça pour les performances.
Si quelqu'un est intéressé par le code final (je ne suis qu'un débutant hein), je le mettrais avec plaisir
0
Shadowbiwan Messages postés 5 Date d'inscription mardi 1 août 2006 Statut Membre Dernière intervention 30 août 2009
30 août 2009 à 15:24
Bizarre elle marche nickel ma boucle while chez moi... Enfin bon tant que t'arrive à y faire marcher !
Bonne continuation
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mioumiounorris Messages postés 57 Date d'inscription dimanche 24 février 2008 Statut Membre Dernière intervention 4 septembre 2011
31 août 2009 à 11:27
Oui je n'ai pas compris non plus...Mais bon j'avais sûrement fais quelque chose de pas bien.
En tous cas, ton aide m'a bien aidé ... pour le coup des Single. C'était pas grand chose, mais là ça marche du tonnerre (excepté si je zoom à plus d'une certaine valeur = exception louche, mais j'ai réglé la valeur maxi plus basse comme ça plus de problèmes )
Même si je pense que ça pourrait être beaucoup moins lourd dans le code. Du coup, j'ai exactement la même réaction que la règle de Photoshop, et ça, ça me fait bien plaisir .

Merci bien pour ton aide
0
Rejoignez-nous