Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Tk [canvas] - Création Courbes

19 réponses
Avatar
genomart
Bonjour,

Je voudrais savoir s'il y a un moyen de cr=E9er une courbe dans un
canvas sans que celle ci ne soit une courbe de bezier.

Car la m=E9thode classique consiste =E0 utilise la m=E9thode createLine ave=
c
l'otpion smooth =E0 1, mais celle ci cr=E9e une courbe de b=E9zier.

Merci

9 réponses

1 2
Avatar
perlgenome
Personne n'a d'idées ?

Merci
Avatar
Paul Gaborit
À (at) Mon, 6 Jul 2009 14:40:03 -0700 (PDT),
perlgenome écrivait (wrote):
Personne n'a d'idées ?



Si, beaucoup ! ;-)

Reposons votre problème : construire une courbe passant par n points
(P1, P2, ..., Pn).

Il existe une infinité de solutions à ce problème.

Ajoutons comme contrainte que la courbe doit être une courbe de
Bézier. Là encore, il existe une infinité de solutions. Parce que
votre série de points initiale ne précise pas la tangente en chaque
point (c'est ce que définissent les points de contrôle d'une courbe de
Bézier). Il vous faut donc déterminer la tangente en chaque point
initiaux.

Pour la direction, vous pouvez choisir (par exemple) une droite
passant par Pi et parallèle à la droite Pi-1,Pi+1. Il ne reste plus
qu'à positionner vos points de contrôles sur cette droite. Par exemple
à 1/3 de la distance séparant Pi de Pi-1 et de celle séparant Pi de
Pi+1. Une fois ce travail effectué, vous avez tout vos points de
passage (les n points initiaux) et tous vos points de contrôles. Il ne
reste plus qu'à tracer les courbes de Bézier. Je laisse de côté le
choix des points de contrôle aux deux extrêmités.

C'est une possibilité...

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Avatar
perlgenome
On 7 juil, 00:38, Paul Gaborit wrote:
À (at) Mon, 6 Jul 2009 14:40:03 -0700 (PDT),
perlgenome écrivait (wrote):

> Personne n'a d'idées ?

Si, beaucoup ! ;-)

Reposons votre problème : construire une courbe passant par n points
(P1, P2, ..., Pn).

Il existe une infinité de solutions à ce problème.

Ajoutons comme contrainte que la courbe doit être une courbe de
Bézier. Là encore, il existe une infinité de solutions. Parce que
votre série de points initiale ne précise pas la tangente en chaque
point (c'est ce que définissent les points de contrôle d'une courbe d e
Bézier). Il vous faut donc déterminer la tangente en chaque point
initiaux.

Pour la direction, vous pouvez choisir (par exemple) une droite
passant par Pi et parallèle à la droite Pi-1,Pi+1. Il ne reste plus
qu'à positionner vos points de contrôles sur cette droite. Par exempl e
à 1/3 de la distance séparant Pi de Pi-1 et de celle séparant Pi de
Pi+1. Une fois ce travail effectué, vous avez tout vos points de
passage (les n points initiaux) et tous vos points de contrôles. Il ne
reste plus qu'à tracer les courbes de Bézier. Je laisse de côté l e
choix des points de contrôle aux deux extrêmités.

C'est une possibilité...

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>



Merci pour votre réponse.
J'ai du mal à me remettre dans les maths pour trouver mon algo.

Je vais essayer de reposer mon but.

J'ai 10 points : P1, P2, ..., P10
1- Je souhaite créer une courbe qui passe par ces 10 points.
2- Cette courbe doit être une courbe de bezier.

Pour ce faire, d'après votre solution, on a besoin de déterminer des
points de contrôle.
Donc il nous faut trouver la tangente en chaque point.
a) Comment déterminer la tangente d'un point (sans équation) ? Je ne
vois absolument pas comment déterminer une tangente par rapport à un
point.
b) Pour la direction, 'ai pas tout saisie, désolé

Merci
Avatar
Paul Gaborit
À (at) Tue, 7 Jul 2009 02:59:47 -0700 (PDT),
perlgenome écrivait (wrote):
Je vais essayer de reposer mon but.

J'ai 10 points : P1, P2, ..., P10
1- Je souhaite créer une courbe qui passe par ces 10 points.
2- Cette courbe doit être une courbe de bezier.

Pour ce faire, d'après votre solution, on a besoin de déterminer des
points de contrôle.



Ce n'est pas d'après ma solution. C'est la définition des courbes de
Bézier. Il faut deux points extrêmes (par lesquels la courbe passe) et
deux points de contrôles (qui définissent les tangentes aux points
extrêmes et par lesquels la courbe ne passe généralement pas).

Donc il nous faut trouver la tangente en chaque point.



On ne la trouve pas. On en choisit une arbitrairement parmi l'infinité
possible.

a) Comment déterminer la tangente d'un point (sans équation) ? Je ne
vois absolument pas comment déterminer une tangente par rapport à un
point.



Il faut la choisir.

b) Pour la direction, 'ai pas tout saisie, désolé



Ex: pour choisir la tangente au point P4, on prend une direction
parallèle à la droite joignant P3 à P5. C'est un choix arbitraire mais
qui donne généralement de bons résultats. Reste à positionner les
points de contrôles sur cette droite...

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Avatar
perlgenome
On 7 juil, 12:12, Paul Gaborit wrote:
À (at) Tue, 7 Jul 2009 02:59:47 -0700 (PDT),
perlgenome écrivait (wrote):

> Je vais essayer de reposer mon but.

> J'ai 10 points : P1, P2, ..., P10
> 1- Je souhaite créer une courbe qui passe par ces 10 points.
> 2- Cette courbe doit être une courbe de bezier.

> Pour ce faire, d'après votre solution, on a besoin de déterminer de s
> points de contrôle.

Ce n'est pas d'après ma solution. C'est la définition des courbes de
Bézier. Il faut deux points extrêmes (par lesquels la courbe passe) e t
deux points de contrôles (qui définissent les tangentes aux points
extrêmes et par lesquels la courbe ne passe généralement pas).

> Donc il nous faut trouver la tangente en chaque point.

On ne la trouve pas. On en choisit une arbitrairement parmi l'infinité
possible.

> a) Comment déterminer la tangente d'un point (sans équation) ? Je n e
> vois absolument pas comment déterminer une tangente par rapport à u n
> point.

Il faut la choisir.

> b) Pour la direction, 'ai pas tout saisie, désolé

Ex: pour choisir la tangente au point P4, on prend une direction
parallèle à la droite joignant P3 à P5. C'est un choix arbitraire m ais
qui donne généralement de bons résultats. Reste à positionner les
points de contrôles sur cette droite...

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>



En représentant 4 points et une courbe passant par ces 4 points sur
papier, je vois bien les tangentes
Ex : En P2, droite passant par P2 et parallèle à P1 et P3.
Mais mathématiquement, comment trouver l'équation de cette droite afin
de trdauire cela en Perl.

Merci
Avatar
perlgenome
J'ai une idée, pouvez vous me dire si elle est plausible ?

Si j'ai 10 points, je dois choisir 8 tangentes (les points P2 à P9)
Ex : Pour la tangente en P2 :
- Déterminer l'équation de la droite P1P3
- Déterminer l'équation de la tangente en P2 parallèle à P1P3 (ell e
aura le même coefficient directeur)
- Choisir 2 points de contrôle, c'est à dire 2 points sur cette
droite (un entre xP1 et xP2 et un entre xP2 et xP3)

=> Pour les 8 points, j'aurais 16 points de contrôle + les 2 points
extrême => 18 points

=> Tracer ma courbe de Béziers en donnant ces 18 points, c'est ça ?
Avatar
Paul Gaborit
À (at) Tue, 7 Jul 2009 03:36:57 -0700 (PDT),
perlgenome écrivait (wrote):
J'ai une idée, pouvez vous me dire si elle est plausible ?

Si j'ai 10 points, je dois choisir 8 tangentes (les points P2 à P9)
Ex : Pour la tangente en P2 :
- Déterminer l'équation de la droite P1P3
- Déterminer l'équation de la tangente en P2 parallèle à P1P3 (elle
aura le même coefficient directeur)



Oui.

- Choisir 2 points de contrôle, c'est à dire 2 points sur cette
droite (un entre xP1 et xP2 et un entre xP2 et xP3)



Oui. La distance de ces points de contrôle à P3 exprime la notion de
tension de votre courbe de Bézier de chaque côté de P3.

=> Pour les 8 points, j'aurais 16 points de contrôle + les 2 points
extrême => 18 points



Vous avez deux points de contrôle par point initiaux. Sauf pour les
deux points extrêmes ou il n'y a qu'une seule tangente. Pour ces deux
points, un choix possible est de les placer sur les droites P1P2 et
P9P10 avec un coefficient de tension...

Donc au bilan :

- 8 points intermédiaires,
- 2*8 points de contrôle pour les points intermédiaires,
- 2 points extrêmes (P1 et P10),
- 1*2 points de contrôle pour les points extrêmes.

Total : 28 points.

=> Tracer ma courbe de Béziers en donnant ces 18 points, c'est ça ?



Tracer la courbe avec ces 28 points.

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Avatar
perlgenome
On 7 juil, 14:00, Paul Gaborit wrote:
À (at) Tue, 7 Jul 2009 03:36:57 -0700 (PDT),
perlgenome écrivait (wrote):

> J'ai une idée, pouvez vous me dire si elle est plausible ?

> Si j'ai 10 points, je dois choisir 8 tangentes (les points P2 à P9)
> Ex : Pour la tangente en P2 :
>  - Déterminer l'équation de la droite P1P3
>  - Déterminer l'équation de la tangente en P2 parallèle à P1P 3 (elle
> aura le même coefficient directeur)

Oui.

>  - Choisir 2 points de contrôle, c'est à dire 2 points sur cette
> droite (un entre xP1 et xP2 et un entre xP2 et xP3)

Oui. La distance de ces points de contrôle à P3 exprime la notion de
tension de votre courbe de Bézier de chaque côté de P3.

> => Pour les 8 points, j'aurais 16 points de contrôle + les 2 points
> extrême => 18 points

Vous avez deux points de contrôle par point initiaux. Sauf pour les
deux points extrêmes ou il n'y a qu'une seule tangente. Pour ces deux
points, un choix possible est de les placer sur les droites P1P2 et
P9P10 avec un coefficient de tension...

Donc au bilan :

     - 8 points intermédiaires,
     - 2*8 points de contrôle pour les points intermédiaires,
     - 2 points extrêmes (P1 et P10),
     - 1*2 points de contrôle pour les points extrêmes.

Total : 28 points.

> => Tracer ma courbe de Béziers en donnant ces 18 points, c'est ça ?

Tracer la courbe avec ces 28 points.

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>



Merci,

Je vais essayer de traduire cela en langage Perl. Je vous tiens au
courant dès que c'est résolu.
Avatar
perlgenome
Bonjour,

Après traduction en Perl, voici ce que ça donne. Vous pouvez tester le
code ci-dessous :
la fonction GetControlPoints() prend en argument un tableau de points
et retourne un tableau contenant les points de contrôles, les points
intermédiaires et les points extrêmes. Je n'ai pas mis de points de
contrôle pour les points extrêmes, car je n'ai pas trouvé l'intér êt.
Le Code ci-dessous affiche une courbes de bézier normal (en noir), une
spline bezier (rouge) passant par tous les points, des lignes (verte)
passant par tous les points, et une courbe qui passe par tous les
points (bleu) calculée via les barycentres (d'après le code de Jean-
louis). Comme distance entre les points de controle et les points
intermédiaire, je n'ai pas pris 1/3 car c'est trop grand et déforme la
courbe. J'ai utilisé 0.95.

Testez et dites moi ce que vous en pensez ? Si c'est OK, je mets à
jours mon module CPAN.
l'option -bezier permettra de créer une courbe de Béziers, l'option -
spline permettra de forcer la courbe à passer par tous les points.
D'ailleurs comme noms d'option, ça vous parait logique ?

Merci


#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Tk::Pane;
use Tk::Photo;
use Tk::PNG;

my $mw = MainWindow->new;

#Définition de la taille min de la fenêtre
$mw->minsize( 600, 600 );

my $pane = $mw->Scrolled( 'Pane', -scrollbars => 'osoe', )
->pack(qw / -expand 1 -fill both /);

my $c = $pane->Canvas(
-background => 'white',
-height => 800,
-width => 800,
)->pack(qw / -side left -expand 1 -fill both /);

# liste des coordonnées des points (il faut trois points minimum)
my @points
= qw / 50 200 75 10 100 100 150 200 200 100 250 200 350 190 400
300 435 50/;
my $RefPointsControle = GetControlPoints( @points );

# tracé du polygone en rouge
$c->createLine( @points, -fill => 'red' );

# premier point de contrôle
my $k = 2;
my $xg = ( $points[0] + ( ( $k * $points[2] ) - $points[4] ) ) / $k;
my $yg = ( $points[1] + ( ( $k * $points[3] ) - $points[5] ) ) / $k;

#======================== ===
# Courbe de bezier selon morel
for my $i ( 0 .. @points / 2 - 2 ) {
$c->createLine(
$points[ 2 * $i ], $points[ 2 * $i + 1 ],
$xg, $yg,
$points[ 2 * $i + 2 ], $points[ 2 * $i + 3 ],
-smooth => 1,
-fill => 'blue'
);
$xg = 2 * $points[ 2 * $i + 2 ] - $xg; # point de contrôle
suivant
$yg = 2 * $points[ 2 * $i + 3 ] - $yg;
}

#======================== ===
# Creation de point d'ancrage
for ( my $i = 0; $i <= $#points; $i = $i + 2 ) {
$c->createText( $points[$i], $points[ $i + 1 ],
-width => 2,
-text => 'X'
);
}

#======================== ===
# Creation de point d'ancrage de controle
for ( my $i = 0; $i <= $#{$RefPointsControle}; $i = $i + 2 ) {
$c->createText(
$RefPointsControle->[$i], $RefPointsControle->[ $i + 1 ],
-fill => '#9F6F00',
-width => 3,
-text => 'x'
);
}

#======================== ===
# Courbe de Bezier normal
$c->createLine( @points, -smooth => 1, -width => 2, );

#======================== ===
# Courbe de Bezier normal Rearrangé
$c->createLine(
@{$RefPointsControle},
-smooth => 1,
-width => 2,
-fill => 'red',
);

#======================== ===
# Courbe normal => LINE
for ( my $i = 0; $i <= $#points; $i = $i + 2 ) {
last unless ( defined $points[ $i + 3 ] );
$c->createLine(
$points[$i], $points[ $i + 1 ], $points[ $i + 2 ], $points[ $i +
3 ],
-smooth => 1,
-width => 2,
-fill => 'green',
);

}

MainLoop;

sub GetControlPoints {
my ($RefArray) = @_;

my $NbrElt = scalar @{$RefArray};

unless ( $NbrElt > 4 ) {
return $RefArray;
}

# First element
my @AllControlPoints = ( $RefArray->[0], $RefArray->[1] );

for ( my $i = 0; $i <= $NbrElt; $i = $i + 2 ) {
my @PointA = ( $RefArray->[$i], $RefArray->[ $i + 1 ] );
my @PointB = ( $RefArray->[ $i + 2 ], $RefArray->[ $i + 3 ] );
my @PointC = ( $RefArray->[ $i + 4 ], $RefArray->[ $i + 5 ] );

last unless ( defined $RefArray->[ $i + 5 ] );

# Equation between PointA and PointC
# Coef = (yc -ya) / (xc -xa)
# D1 : Y = Coef * X + (ya - (Coef * xa))
my $coef = ( $PointC[1] - $PointA[1] ) / ( $PointC[0] - $PointA
[0] );

# Equation for D2 ligne paralelle to [AC] with PointB
# D2 : Y = (Coef * X) + yb - (coef * xb)
# The 2 control points
my $D2line = sub {
my ($x) = @_;

my $y = ( $coef * $x ) + $PointB[1] - ( $coef * $PointB[0] );
return $y;
};

# distance
my $distance = 0.95;

# xc1 = ( (xb - xa ) / 2 ) + xa
# yc1 = via D2
my @ControlPoint1;
$ControlPoint1[0] = ( $distance * ( $PointB[0] - $PointA[0] ) ) +
$PointA[0];
$ControlPoint1[1] = $D2line->( $ControlPoint1[0] );
push( @AllControlPoints, ( $ControlPoint1[0], $ControlPoint1
[1] ) );

# point intermediaire
push( @AllControlPoints, ( $PointB[0], $PointB[1] ) );

# xc2 = ( (xc - xb ) / 2 ) + xb
# yc2 = via D2
my @ControlPoint2;
$ControlPoint2[0] = ( (1 - $distance) * ( $PointC[0] - $PointB
[0] ) ) + $PointB[0];
$ControlPoint2[1] = $D2line->( $ControlPoint2[0] );

push( @AllControlPoints, ( $ControlPoint2[0], $ControlPoint2
[1] ) );
}

push( @AllControlPoints,
$RefArray->[ $NbrElt - 2 ],
$RefArray->[ $NbrElt - 1 ] );

return @AllControlPoints;
}
1 2