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 :

Regression linéaire multiple


Sujet :

Langage Delphi

  1. #1
    Membre régulier
    Inscrit en
    Juin 2004
    Messages
    153
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 153
    Points : 73
    Points
    73
    Par défaut Regression linéaire multiple
    Bonjour à tous,

    je soumets la problématique suivante qui se situe à l'intersection des domaines Delphi/analyse numérique.

    j'ai une fonction Y=f(X) définie sur un très grand nombre de points (27000) lorsque je représente cette fonction en Delphi (mais également en
    Excel : plus facile à fournir en illustration) j'obtiens une ligne brisée de quelques segments (entre 5 et 10). Mais ça c'est ce que je constate
    sur mon graphe mais je ne connais pas d'algorithme/fonction en Delphi qui me permettrait de récupérer, à partir de tous ces points, la suite
    des segments décrits par leurs extrémités (Xdébut, Ydébut) --> (Xfin, Yfin).

    Connaissez-vous un code Delphi (pascal objet), ou simplement un algorithme qui me permettrait de faire cela ?

    Merci d'avance
    Fichiers attachés Fichiers attachés

  2. #2
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    Je me doute que tu as du y penser : prendre 3 points et regarder s'ils sont alignés, puis 3 points suivants. Mais le traitement risque d'être long ...

    A+
    Charly

  3. #3
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    tes points ne sont pas alignés ? il ne s'agit pas de segments ? Il faudrait trouver autre chose : peut être un changement de pente important ?

    A+
    Charly

  4. #4
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    méthode très approximative, non scientifique et qui ne s'applique qu'à ton style de nuage de points (en zigzag) :

    En chaque point tu calcules la somme des pentes des 3 vecteurs suivants.

    Les points que tu cherches sont situés aux endroits ou cette somme change de valeur (à 2 décimales près). Si la somme change très rapidement 2 ou 3 points après, il faut éliminer ce point qui duplique l'extrémité du segment)

    Pas terrible, mais je ne trouve rien d'autre de plus satisfaisant après de nombreux tests sur les variations de pente ...

    Il faudrait faire appel à un super matheux !!

    A+
    Charly

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

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Une piste, peut-être :
    1) déterminer la pente sur quelques points successifs (pour vérifier, car si droite parfaite, 2 points suffisent)
    2) chercher de façon aléatoire si des points à plus ou moins grande distance se trouvent sur le même segment (calcul de leur ordonnée grâce à leur abscisse et cette pente)
    3) si oui, chercher plus loin ; si non, chercher l'extrémité du segment par une méthode où on divise l'intervalle à tester en 2
    4) une fois l'extrémité trouvée, on repart de là pour chercher celle du segment suivant

    Le risque est de ne pas trouver deux (ou plus) courts segments intermédiaires si 2 segments distants sont alignés sur une même droite

    Si les points sont obtenus par mesure, reste à espérer que les segments soient réellement droits.
    S'ils le sont par calcul, les points qui annulent la dérivée seconde sont les points d'inflexion cherchés.
    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 !

  6. #6
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Les points ne sont pas alignés. chaque segment est en fait une ligne composée de petits zigzag. C'est là la difficulté.

    Ma solution fonctionne à peu près mais cela dépend si tous les jeux de données suivent ce principe !

    je vais simplifier mon programme (en enlevant les essais infructueux) et le poster.

    A+
    Charly

  7. #7
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,
    voilà en PJ ma solution approximative qui fonctionne sur le jeu de données fourni. Cela donne les extrémités des segments. ensuite, il suffit de faire une régression linéaire pour chaque segment afin d'avoir l'équation des droites qui les portent.

    Segments.zip

    Autre possibilité : supprimer deux points sur trois pour essayer d'avoir de vrais segments. A voir si c'est plus précis ...
    A+
    Charly

  8. #8
    Membre régulier
    Inscrit en
    Juin 2004
    Messages
    153
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 153
    Points : 73
    Points
    73
    Par défaut Méthode essayée...
    J'ai essayé la méthode suivante :

    Pour chaque point je fais moyenne avec le suivant

    Pour i=1 à N-1

    X[i]=(X[i]+X[i+1])/2

    Y[i]=(Y[i]+Y[i+1])/2

    Fin Pour



    Ensuite je parcours la liste en considérant que chaque changement de sens correspond à une fin de segment.



    Sur le deuxième jeu de points j’arrive à isoler 4 segments (voir image jointe)




    Par contre sur mon premier exemple (joint lors du lancement de la discussion) je reste avec 782 segments alors que visuellement on en voit 5 seulement
    Images attachées Images attachées  
    Fichiers attachés Fichiers attachés

  9. #9
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    nouveau test assez concluant avec les jeux de données 1 et 2 :

    on élimine un points sur 2 ou un point sur 3 pour avoir quasiment de vrais segments puis on cherche les variations de pente.

    Essaye le bouton "Traitement 2" de mon appli

    Segments2.zip

    A+
    Charly

  10. #10
    Membre régulier
    Inscrit en
    Juin 2004
    Messages
    153
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 153
    Points : 73
    Points
    73
    Par défaut Version en langage Pascal d'un algorithme de regréssion linéaire par morceaux
    Je n'ai pas encore pu tester le modèle "segment2" fourni par Charly910.
    En revanche j'ai trouvé l'algorithme de "Douglas Peucker" qui fournit de très bons résultats avec
    mes jeux de données.

    J'ai porté une version itérative du code correspondant en Pascal/Delphi que je souhaite partager avec la communauté.


    L’algorithme de Douglas-Peucker donne de très bons résultats, la version itérative du programme associé est très efficace.
    Le choix du bon seuil (« epsilonLocal » dans le code ci-dessous) est bien entendu crucial.


    Exemple 1, résultat obtenu : 27687 points (graphe de gauche) synthétisé en à 6 points (graphe de droite)

    Nom : image001.png
Affichages : 449
Taille : 3,4 Ko Nom : image002.jpg
Affichages : 515
Taille : 11,6 Ko

    Exemple 2, résultat obtenu : 13128 points (graphe de gauche) synthétisé en à 7 points (graphe de droite)

    Nom : image003.png
Affichages : 443
Taille : 3,6 Ko Nom : image004.jpg
Affichages : 465
Taille : 14,5 Ko

    Le codage en pascal de l’algorithme de Douglas-Peucker dans sa version itérative (Ramer)

    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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
     
    {
     
    Algorithme de  Ramer-Douglas-Peucker
    À chaque étape on parcourt tous les nœuds entre les bornes et on sélectionne
    le nœud le plus éloigné du segment formé par les bornes :
     
    1.     s'il n'y a aucun nœud entre les bornes l'algorithme se termine,
    2.     si cette distance est inférieure à un certain seuil on supprime tous les nœuds entre les bornes,
    3.     si elle est supérieure la polyligne n'est pas directement simplifiable.
      On appelle de manière récursive l'algorithme sur deux sous-parties de la
      polyligne : de la première borne au nœud distant, et du nœud distant à la borne finale.
     
     
    Iterative version of Ramer-Douglas-Peucker line-simplification algorithm
     
    }
     
     
     
    unit uAlgoDouglasPucker;
     
    interface
     
    uses system.generics.collections, system.types, system.Math.vectors,
      system.classes;
     
    type
     
      TListePoints = array of TpointF;
     
     
    procedure DouglasPeucker(const points: TListePoints; epsilonLocal: double;
      var res: TListePoints);
     
     
    implementation
     
    type
     
      TKeyValuePair = record
        key, value: integer;
        constructor create(aun, adeux: integer);
      end;
     
     
     
    function DouglasPeuckerInterne(const points: TListePoints;
      startIndex, lastIndex: integer; epsilonLocal: double)
      : TBooleanDynArray; forward;
     
    function pointLineDistance(point, start, fin: TpointF): double; forward;
     
     
     
    procedure DouglasPeucker(const points: TListePoints; epsilonLocal: double;
      var res: TListePoints);
     
    var
      bitArray: TBooleanDynArray;
      i, hg: integer;
     
    begin
      bitArray := DouglasPeuckerInterne(points, 0, high(points), epsilonLocal);
      res := nil;
      hg := high(res);
      for i := Low(points) to High(points) do
      begin
        if bitArray[i] then
        begin
          hg := hg + 1;
          setLength(res, hg + 1);
          res[hg] := points[i];
        end;
      end;
    end;
     
     
     
    function DouglasPeuckerInterne(const points: TListePoints;
      startIndex, lastIndex: integer; epsilonLocal: double): TBooleanDynArray;
    var
      pile: TStack<TKeyValuePair>;
      bitArray: TBooleanDynArray;
      dmax, d: double;
      index, i, globalStartIndex: integer;
    begin
      globalStartIndex := startIndex;
      setLength(bitArray, lastIndex - startIndex + 1);
      for i := Low(bitArray) to High(bitArray) do
        bitArray[i] := TRUE;
     
      pile := TStack<TKeyValuePair>.create();
      pile.Push(TKeyValuePair.create(startIndex, lastIndex));
      while (pile.Count > 0) do
      begin
        startIndex := pile.Peek.key;
        lastIndex := pile.Peek.value;
        pile.Pop;
        dmax := 0.0;
        index := startIndex;
        for i := index + 1 to lastIndex - 1 do
        begin
          if bitArray[i - globalStartIndex] then
          begin
            d := pointLineDistance(points[i], points[startIndex],
              points[lastIndex]);
            if d > dmax then
            begin
              index := i;
              dmax := d;
            end;
          end;
        end;
     
        if dmax > epsilonLocal then
        begin
          pile.Push(TKeyValuePair.create(startIndex, index));
          pile.Push(TKeyValuePair.create(Index, lastIndex));
        end
        else
        begin
          for i := startIndex + 1 to lastIndex - 1 do
            bitArray[i - globalStartIndex] := FALSE;
        end;
      end;
     
      result := bitArray;
     
    end;
     
     
     
    function pointLineDistance(point, start, fin: TpointF): double;
    var
      n, d: double;
    begin
      if (start.X = fin.X) and (start.Y = fin.Y) then
        result := point.Distance(start)
      else
      begin
        n := Abs((fin.X - start.X) * (start.Y - point.Y) - (start.X - point.X) *
          (fin.Y - start.Y));
        d := Sqrt((fin.X - start.X) * (fin.X - start.X) + (fin.Y - start.Y) *
          (fin.Y - start.Y));
        result := n / d;
      end;
    end;
     
     
     
    { TKeyValuePair }
     
    constructor TKeyValuePair.create(aun, adeux: integer);
    begin
      key := aun;
      value := adeux;
    end;
     
    end.

  11. #11
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    j'ai testé l'algorithme de "Douglas Peucker" en réécrivant le code pour mon D7. C'est la meilleure méthode. Elle est générale alors que mon 'traitement 2' ne peut s'applique qu'à des semis de points de ton type (composés d'une succession de petites vaguelettes).

    Le seul point délicat est de trouver la bonne tolérance qui doit dépendre de l'amplitude des grands segments. Si on fait varier cette tolérance pour tes jeu de données, on peut avoir des résultats différents.

    A+
    Charly

  12. #12
    Membre régulier
    Inscrit en
    Juin 2004
    Messages
    153
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 153
    Points : 73
    Points
    73
    Par défaut Douglas Peucker itératif : Code DXE7
    Oui ma traduction en Delphi XE7 utilise des capacités du langage qui n'étaient pas dans le Delphi 7 (par exemple la généricité pour la pile) mais l'utilisation
    de ces nouveaux paradigmes n'est due qu'au passage à l'itératif de cet algorithme originellement récursif. Après il est effectivement aisé
    de se faire sa propre pile "ad-hoc" en Delphi 7.

  13. #13
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    Est ce que dans ta fonction pointLineDistance(point, start, fin: TpointF), tu n'oublie pas 2 cas ?

    tu traites le cas ou la projection de point se trouve entre start et fin. Dans ce cas, c'est bien la distance de point à la ligne qui porte le segment Star fin qu'il faut prendre.

    Mais si cette projection est avant Start ou après fin, la distance à prendre en compte est soit dist(point ; start) soit dist (point , fin) ?

    Dans ton cas cela fonctionne car tous les points de tes jeux de données sont en projection entre le début et la fin de la polyligne.

    A+
    Charly

  14. #14
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    Bonjour,

    pour info, voici ma fonction avec D7.

    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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    unit DouglasPeuckers ;
    { Implementation de l'algorithme de Douglas-Peucker qui sert à simplifier
      une polyligne ou un polygone (élimination des points presque alignés à
      une tolérance prêt).
      References:
      David Douglas & Thomas Peucker, "Algorithms for the reduction of the number of
      points required to represent a digitized line or its caricature", The Canadian
      Cartographer 10(2), 112-122  (1973)
      Code original de Nils Haeck
     
      Utilisation :
     
        PolySimplify(Tol: TFloat; const Orig: array of TPointFloat; var Simple: TPointFloatAr): integer;
        Orig[]   : Polyligne de départ
        Simple[] : Polyligne résultante
        Tol      : tolérance d'alignement (en distance) pour les points à supprimer
        Renvoie le nombre de points de Simple[]
    }
     
    interface
     
    uses
      Windows ;
     
    type
     
      // Type Float
      TFloat = double ;
     
      // Point de coordonnées de type double
      TPointFloat = packed record
        X: TFloat ;
        Y: TFloat ;
      end;
     
      TPointFloatAr = array of TPointFloat ;
     
      { PolySimplify:
        La polyligne stockée dans Orig est simplifiée et retournée dans Simple.
        La distance maximum des points à supprimer est donnée dans Tol
        Entrée:  Tol      = approximation tolerance
        Orig[]   = Tableau de points de la polyligne initiale
        Sortie: Simple[] = Tableau de points de la polyligne simplifiée
                           (de longueur initiale à celle de Orig[]
        Retour: Nombre de points de Simple[]
      }
    function PolySimplify(Tol: TFloat; const Orig: array of TPointFloat; var Simple: TPointFloatAr): integer;
     
    implementation
     
    uses Math ;
     
    { ========================================================================= }
    function Vecteur(const A, B: TPointFloat): TPointFloat;
    // Resultat Vecteur AB
    begin
      Result.X := B.X - A.X ;
      Result.Y := B.Y - A.Y ;
    end;
    { ========================================================================= }
    function ProdScal(const A, B: TPointFloat): TFloat;
    // Produit scalaire = A . B
    begin
      Result := A.X * B.X + A.Y * B.Y ;
    end;
    { ========================================================================= }
    function Norme2(const A: TPointFloat): TFloat;
    // Carré de la norme |A|
    begin
      Result := A.X * A.X + A.Y * A.Y ;
    end;
    { ========================================================================= }
    function Distance2(const A, B: TPointFloat): TFloat;
    // Carré de la distance entre A et B
    begin
      Result := Norme2(Vecteur(A, B)) ;
    end;
    { ========================================================================= }
    procedure Simplify(var Tol2: TFloat; const Orig: array of TPointFloat; var Marqueur: array of boolean; j, k: integer);
    // Simplifie la  polyligne Orig entre j et k en marquant les points a true pour les conserver
    // par Marquer[i]
    // Tol2 = carré de la tolérance pour les points à supprimer
    //
    var
      i, MaxI: integer ;  // Index maximum
      MaxD2: TFloat ;     // Maxi de la distance au carré du point au segment
      CU, CW, B: TFloat ;
      DV2: TFloat ;      //  Distance au carré
      P0, P1, PB, U, W: TPointFloat ;
    begin
      // Polyligne composée de + de 2 points ==> on sort
      if k <= j + 1 then
        exit ;
      // Traitement du segment j k
      P0 := Orig[j] ;
      P1 := Orig[k] ;
      U := Vecteur(P0, P1) ; // Segment j k  ou PO P1
      CU := ProdScal(U, U) ; // Carré de la longueur du segment P0 P1
      MaxD2 := 0 ;
      MaxI  := 0 ;
     
      // Recherche du point le plus éloigné du segment
      for i := j + 1 to k - 1 do
      begin
        W := Vecteur(P0, Orig[i]) ;
        CW := ProdScal(W, U) ;
     
        // Distance de ce point au segment
        if CW <= 0 then
        begin
          // Projection avant le segment
          DV2 := Distance2(Orig[i], P0)
        end
        else
        begin
          if CW > CU then
          begin
            // Projection après le segment
            DV2 := Distance2(Orig[i], P1) ;
          end
          else
          begin
            // Projection sur le segment
            if CU=0 then
              B := 0
            else
              B := CW / CU ;
            PB.X := P0.X + B * U.X;
            PB.Y := P0.Y + B * U.Y ;
            DV2 := Distance2(Orig[i], PB);
          end ;
        end ;
     
        // test par rapport à la distance max
        if DV2 > MaxD2 then
        begin
          // Orig[i] est un sommet à conserver
          MaxI := i ;
          MaxD2 := DV2 ;
        end;
      end;
     
      // si le point le plus loin est hors tolérance, on découpe
      if MaxD2 > Tol2 then
      begin
        // découpage de la polyligne
        Marqueur[MaxI] := True ; // marquer Orig[maxi] pour la polyligne simplifiée
     
        // simplification récursive des 2 polylignes découpées
        Simplify(Tol2, Orig, Marqueur, j, MaxI) ; // polyligne Orig[j] à Orig[maxi]
        Simplify(Tol2, Orig, Marqueur, MaxI, k) ; // polyligne Orig[maxi] à Orig[k]
      end;
    end;
    { ========================================================================= }
    function PolySimplify(Tol: TFloat; const Orig: array of TPointFloat; var Simple: TPointFloatAr): integer;
    // Simplifie la  polyligne Orig[] entre 0 et N en supprimant les points presque alignés à Tol près
    // Résultats dans Simple[]
    // Tol = tolérance pour la distance des points à supprimer
    // Renvoie le nombre de points de Simple[]
    var
      i : integer;
      N: integer;                      // Taille de la polyligne initiale
      Marqueur1: array of boolean;    // à True si on doit conserver le point
      Tol2: TFloat;                    // Tolérance pour éliminer les points
    begin
      Result := 0;
      if length(Orig) < 2 then
        exit;
      Tol2 := sqr(Tol);   // Car Simplify utilise le carré de la distance
      // Création et initialisation du marqueur booléen des points à conserver
      N := length(Orig);
      SetLength(Marqueur1, N);
      // les points début et fin font partie de la polyligne simplifiée
      Marqueur1[0] := True;
      Marqueur1[N - 1] := True;
      // Exclusion des autres points de la polyligne
      for i := 1 to N - 2 do Marqueur1[i] := False;
     
      // Simplification de la polyligne
      Simplify(Tol2, Orig, Marqueur1, 0, N - 1);
     
      // remplissage de la liste des points résultats
      SetLength(Simple, N);
      for i := 0 to N - 1 do
      begin
        if Marqueur1[i] then
        begin
          Simple[Result] := Orig[i];
          inc(Result);
        end;
      end;
      // redimension de la liste des points résultats
      SetLength(Simple, Result);
    end;
    { ========================================================================= }
     
     
    end.
    Avec une tolérance de 100, j'obtiens les résultats suivants :

    Jeu1 :
    Nombre de points conservés : 6

    Y X
    0 0
    1778 -1515,31
    4112 -2634,507
    13341 768,748
    24490 -12555,632
    27684 -7867,991
    Fin des points de la polyligne ---------------------

    Jeu2 :

    Nombre de points conservés : 5

    Y X
    0 0
    667 -175,618
    6806 2728,784
    9577 -368,698
    13125 406,645
    Fin des points de la polyligne ---------------------

    A+
    Charly

  15. #15
    Membre régulier
    Inscrit en
    Juin 2004
    Messages
    153
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 153
    Points : 73
    Points
    73
    Par défaut
    .oui il faut que je modifie ma fonction "distance" qui n'est pas correcte dans tous les cas.
    .les résultats obtenus sont pratiquement les même, j'ai appliqué une tolérance de 10

    Je crois que pour les jeux de données que je dois traiter cette méthode est bien adaptée.

  16. #16
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 345
    Points : 3 123
    Points
    3 123
    Par défaut
    pour le jeu 2, ma tolérance de 100 est trop forte. Tu as raison il faut prendre de l'ordre de 10 afin d'avoir tous les points (il y a un tout petit segment supplémentaire avec 10)

    A+
    Charly

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Regression linéaire multiple
    Par Newenda dans le forum Bibliothèques d'apprentissage automatique
    Réponses: 0
    Dernier message: 12/05/2017, 18h11
  2. Scoring avec une regression linéaire
    Par n3mrod dans le forum SAS STAT
    Réponses: 7
    Dernier message: 10/06/2015, 15h48
  3. régression linéaire multiple
    Par azertyuio dans le forum Méthodes prédictives
    Réponses: 14
    Dernier message: 18/04/2010, 21h53
  4. régression linéaire multiple et contrainte
    Par arthy dans le forum Méthodes prédictives
    Réponses: 21
    Dernier message: 20/02/2010, 11h27
  5. Réponses: 0
    Dernier message: 21/03/2008, 13h51

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