Tk [canvas] - Création Courbes

Le
genomart
Bonjour,

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

Car la méthode classique consiste à utilise la méthode createLine ave=
c
l'otpion smooth à 1, mais celle ci crée une courbe de bézier.

Merci
Questions / Réponses high-tech
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Nicolas George
Le #19108551
wrote in message
Je voudrais savoir s'il y a un moyen de créer une courbe dans un
canvas sans que celle ci ne soit une courbe de bezier.

Car la méthode classique consiste à utilise la méthode createLine avec
l'otpion smooth à 1, mais celle ci crée une courbe de bézier.



Quel genre de courbes est-ce que tu voudrais ?
genomart
Le #19126521
On 13 avr, 17:23, Nicolas George
wrote in message


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

> Car la méthode classique consiste à utilise la méthode createLine avec
> l'otpion smooth à 1, mais celle ci crée une courbe de bézier.

Quel genre de courbes est-ce que tu voudrais ?



Une courbe basique.
Sachant que l'axe x est qualitatif et non quantitatif.

Ex : A(1, "x"), B(3,"y"), C(2,"z")

J'ai trois points. Mon axe y contient des valeurs numériques et mon
axe x des valeurs qualitatives (Donc dans ce cas d'exemple, elle est
sectionnée en 3 (x,y et z) ).

La méthode createLine crée une courbe de bézier, donc la courbe ne
touche pas tous les points, mais uniquement les 2 extrémités et se
rapproche des autres.

points (http://en.wikipedia.org/wiki/Bezier_cubic).

Une idée ? Merci
Nicolas George
Le #19126601
wrote in message
Une courbe basique.



Cette notion n'est pas bien définie.

La méthode createLine crée une courbe de bézier, donc la courbe ne
touche pas tous les points, mais uniquement les 2 extrémités et se
rapproche des autres.



Il est possible de faire passer la courbe par tous les points, il suffit de
bien choisir les points de contrôle. C'est même possible d'une infinité de
manières différentes, donc il faut préciser ce que tu veux exactement.
genomart
Le #19127791
Je ne vois pas comment je peux être plus clair.
Si j'ai 10 points, comment faire pour créer une courbe qui passe par
ces dix points. C'est tout ce que je demande.
Avez vous des exemples de codes ?

Il existe une infinité de manière => Je veux bien vous croire, mais
alors citez moi en quelques unes.

Merci
Nicolas George
Le #19127951
wrote in message
Si j'ai 10 points, comment faire pour créer une courbe qui passe par
ces dix points. C'est tout ce que je demande.



Il existe une infinité de manière => Je veux bien vous croire, mais
alors citez moi en quelques unes.



Tu as dix points, alors tu fais neuf arcs de courbe de Bézier : un
entre chaque paire de points consécutifs, avec des points de contrôle
aléatoire. Ça va être moche, mais tu as bien une courbe qui passe par tous
les points.
genomart
Le #19441931
On 16 avr, 19:12, Nicolas George
wrote in message


> Si j'ai 10 points, comment faire pour créer une courbe qui passe par
> ces dix points. C'est tout ce que je demande.
> Il existe une infinité de manière => Je veux bien vous croire, ma is
> alors citez moi en quelques unes.

Tu as dix points, alors tu fais neuf arcs de courbe de Bézier : un
entre chaque paire de points consécutifs, avec des points de contrôle
aléatoire. Ça va être moche, mais tu as bien une courbe qui passe p ar tous
les points.



J'ai testé ton idée, mais ça donne vraiment une courbe qui ne
ressemble à rien et complètement incohérente bien qu'elle passe par
les points. C'est comme si on passait par Brest et l'Espagne pour
faire le trajet Paris - Bordeaux - Marseille :-).

En tout cas, je sais pas si c'est faisable en Perl Tk. Dommage,
d'ailleurs, en Java, ou d'autre langage, est ce possible ?

NB: Sinon toute solution ou alternative en Perl Tk sont les bienvenues
Nicolas George
Le #19443021
wrote in message
J'ai testé ton idée, mais ça donne vraiment une courbe qui ne
ressemble à rien et complètement incohérente bien qu'elle passe par
les points.



Ça dépend comment tu choisis tes points de contrôle. Tel que tu le décris,
tu as juste pris des tangentes trop grandes.
jl_morel
Le #19444461
Dans l'article <650f876a-406f-49c5-8c67-
, a dit...

J'ai testé ton idée, mais ça donne vraiment une courbe qui ne
ressemble à rien et complètement incohérente bien qu'elle passe par
les points. C'est comme si on passait par Brest et l'Espagne pour
faire le trajet Paris - Bordeaux - Marseille :-).

En tout cas, je sais pas si c'est faisable en Perl Tk. Dommage,
d'ailleurs, en Java, ou d'autre langage, est ce possible ?

NB: Sinon toute solution ou alternative en Perl Tk sont les bienvenues




Je propose la solution suivante.
On intercale un point de contrôle entre chaque couple de points.

Si A, B, C sont les trois premiers points, le premier point de contrôle (qui
sera placé entre A et B) est le barycentre G de (A,1), (B, $k) (C, -1).
Ici j'ai pris $k=2; on peut changer.

Les points de contrôle suivants sont obtenus par symétrie. Par exemple, le
deuxième point de contrôle (placé entre B et C) est le symétrique de G par
rapport à B. Et ainsi de suite. On obtient ainsi une courbe lisse qui passe
par tous les points, mais rien ne garantit qu'elle ne déborde pas du canvas !

#!/usr/bin/perl
use strict;
use warnings;
use Tk;

my $mw = MainWindow->new;
my $c = $mw->Canvas->pack();

# liste des coordonnées des points (il faut trois points minimum)
my @p = ( 50, 75, 100, 50, 150, 200, 250, 250, 300, 150, 200, 150 );

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

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

# tracé des courbes de Bézier
for my $i ( 0 .. @p / 2 - 2 ) {
$c->createLine($p[ 2 * $i ], $p[ 2 * $i + 1 ],
$xg, $yg,
$p[ 2 * $i + 2 ], $p[ 2 * $i + 3 ],
-smooth => 1,
-fill => 'blue'
);
$xg = 2 * $p[ 2 * $i + 2 ] - $xg; # point de contrôle suivant
$yg = 2 * $p[ 2 * $i + 3 ] - $yg;
}

MainLoop();

__END__

--
J-L.M.
http://www.bribes.org/perl
Paul Gaborit
Le #19451571
À (at) Fri, 29 May 2009 03:26:43 -0700 (PDT),
écrivait (wrote):
J'ai testé ton idée, mais ça donne vraiment une courbe qui ne
ressemble à rien[...]



Pourtant, c'est une courbe parfaite, continue et dérivable (deux fois).

et complètement incohérente bien qu'elle passe par
les points.



'Incohérente' ? Par rapport à quels critères ?

C'est comme si on passait par Brest et l'Espagne pour
faire le trajet Paris - Bordeaux - Marseille :-).



Quel est le problème ? Si c'est las distance, alors la meilleure
solution c'est la suite de segments de droite...

En tout cas, je sais pas si c'est faisable en Perl Tk.



Tout est faisable (sur cette partie-là) mais encore faut-il spécifier
le besoin...

Dommage, d'ailleurs, en Java, ou d'autre langage, est ce possible ?



Ce n'est pas un problème lié au langage ! C'est un peu si vous
demandiez si une recette de cuisine est énoncable en français et pas
en espagnol...

--
Paul Gaborit - Perl en français -
genomart
Le #19462081
On 30 mai, 19:36, Paul Gaborit
À (at) Fri, 29 May 2009 03:26:43 -0700 (PDT),
écrivait (wrote):

> J'ai testé ton idée, mais ça donne vraiment une courbe qui ne
> ressemble à rien[...]

Pourtant, c'est une courbe parfaite, continue et dérivable (deux fois).

> et complètement incohérente bien qu'elle passe par
> les points.

'Incohérente' ? Par rapport à quels critères ?

> C'est comme si on passait par Brest et l'Espagne pour
> faire le trajet Paris - Bordeaux - Marseille :-).

Quel est le problème ? Si c'est las distance, alors la meilleure
solution c'est la suite de segments de droite...

> En tout cas, je sais pas si c'est faisable en Perl Tk.

Tout est faisable (sur cette partie-là) mais encore faut-il spécifier
le besoin...

> Dommage, d'ailleurs, en Java, ou d'autre langage, est ce possible ?

Ce n'est pas un problème lié au langage ! C'est un peu si vous
demandiez si une recette de cuisine est énoncable en français et pas
en espagnol...

--
Paul Gaborit - Perl en français -


Bon, désolé de m'être mal exprimé.

Si on peut tout faire en Perl, c'est très bien. Je suis fan de Perl et
donc je pense Perl avant tout :-).

Pour Jean-Louis, merci pour ton exemple.

Bon, en faite, j'ai créé créer un module sur le CPAN qui a pour but d e
créer des graphes : lignes, bars, courbes, etc, le module se nomme
Tk::ForDummies::Graph.
D'ailleurs si vous avez le temps de le tester, toute remarque serait
la bienvenue pour l'améliorer.
A ce jour, il peut créer des bars, lignes, boxplots, camemberts,
aires, courbes et points. En ce qui concerne les courbes, vous l'avez
évidemment bien compris, c'est une courbe de bezier.
Donc mon idée était de permettre aux utilisateurs qui le souhaitent de
pouvoir créer une courbe normale.

Donc si l'utilisateur donne des datas, il serait bien que la courbe
passe par tous les points (ou non s'il choisit bezier), d'où mes
questions précédentes.

Donc comme exemple pour résoudre mon souci, j'ai fais le premier
script suivant, j'avais pris les points suivants :

#!/usr/bin/perl
use Tk;
use strict;
use warnings;

#Création de la fenêtre principale
my $fen = MainWindow->new();

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


my $canvas = $fen->Canvas(
-background => 'white',
-width => 500,
-height => 500,
)->pack;

my @points = qw / 50 60 100 150 150 50 350 400 425 200/;
# Creation de point d'ancrage
for (my $i = 0; $i <= $#points; $i = $i+2) {
$canvas->createText($points[$i],$points[$i+1], -text => 'X');
}
# Creation d'une coube avec 5 points - Courbe de Bezier
$canvas->createLine(@points,
-smooth => 1,
);

# Creation d'une coube avec 5 points - Courbe normal => LINE
for (my $i = 0; $i <= $#points; $i = $i+2) {
last unless ( defined $points[$i+3] );
$canvas->createLine($points[$i],$points[$i+1],$points[$i+2],$points
[$i+3],
-smooth => 1,
-fill => 'red',
);
}

MainLoop;

c'est une courbe de bezier classique.

Maintenant, j'ai essayé de me baser sur l'exemple de Jean-Louis? Voici
un script qui montre droite bezier ou non :

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

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 => 1000,
-width => 1000,
)->pack( qw / -expand 1 -fill both / );

# liste des coordonnées des points (il faut trois points minimum)
#my @p = qw / 30 300 80 100 130 0 180 100 230 300/;
my @p = qw / 50 60 100 150 150 50 350 400 425 200/;
#( 50, 75, 100, 50, 150, 200, 250, 250, 300, 150, 200, 150 );

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

# premier point de contrôle
my $k = 2;
my $xg = ( $p[0] + ( ($k * $p[2]) - $p[4] ) ) / $k;
my $yg = ( $p[1] + ( ($k * $p[3]) - $p[5] ) ) / $k;
print "$xg , $yg";
$c->createText($xg, $yg, -text => 'G');

# tracé des courbes de Bézier
for my $i ( 0 .. @p / 2 - 2 ) {
# point de control
$c->createText($xg, $yg, -text => 'G');

$c->createLine($p[ 2 * $i ], $p[ 2 * $i + 1 ],
$xg, $yg,
$p[ 2 * $i + 2 ], $p[ 2 * $i + 3 ],
-smooth => 1,
-fill => 'blue'
);
$xg = 2 * $p[ 2 * $i + 2 ] - $xg; # point de contrôle suivant
$yg = 2 * $p[ 2 * $i + 3 ] - $yg;

}

# BEZIER
# Creation de point d'ancrage
for (my $i = 0; $i <= $#p; $i = $i+2) {
$c->createText($p[$i],$p[$i+1], -text => 'X');
}
# Creation d'une coube avec 5 p - Courbe de Bezier
$c->createLine(@p,
-smooth => 1,
);

# Creation d'une coube avec 5 p - Courbe normal => LINE
for (my $i = 0; $i <= $#p; $i = $i+2) {
last unless ( defined $p[$i+3] );
$c->createLine($p[$i],$p[$i+1],$p[$i+2],$p[$i+3],
-smooth => 1,
-fill => 'green',
);
}

MainLoop;



La courbe passe bien par tous les points, mais l'allure de la courbe
est un peu trompeuse pour l'utilisateur. Je suppute que l'utilisateur
qui souhaite faire une courbe avec ces points ne s'attend pas à voir
une courbe qui va au delà du point le plus haut ou le plus bas. Je
sais que c'est un peu tordu et qu'il n'est pas évident de gérer tous
les cas, mais bon.
Le but ultime serait d'être capable de tracer une courbe la plus lisse
possible qui aurait une allure la plus proche que ce qu'on pourrait
dessiner à la main.
Qu'elle soit la plus représentative possible.

Prenez pour exemple ce code, dans lequel je compare la courbe avec
celle créer par GD::Graph::splined.

#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Tk::Pane;
use GD::Graph::splined;
use Tk::Photo;
use Tk::PNG;
use File::Temp;

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 @p = qw / 30 300 80 100 130 0 180 100 230 300/;
my @p = qw / 50 60 100 150 150 50 350 400 425 200/;
my @PointGd = (
["1st","2nd","3rd","4th","5th",],
[ 60, -30, 70, -280, -80],
);


#( 50, 75, 100, 50, 150, 200, 250, 250, 300, 150, 200, 150 );

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

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

$c->createText($xg, $yg, -text => 'G');

# tracé des courbes de Bézier
for my $i ( 0 .. @p / 2 - 2 ) {
# point de control
$c->createText($xg, $yg, -text => 'G');

$c->createLine($p[ 2 * $i ], $p[ 2 * $i + 1 ],
$xg, $yg,
$p[ 2 * $i + 2 ], $p[ 2 * $i + 3 ],
-smooth => 1,
-fill => 'blue'
);
$xg = 2 * $p[ 2 * $i + 2 ] - $xg; # point de contrôle suivant
$yg = 2 * $p[ 2 * $i + 3 ] - $yg;

}

# BEZIER
# Creation de point d'ancrage
for (my $i = 0; $i <= $#p; $i = $i+2) {
$c->createText($p[$i],$p[$i+1], -text => 'X');
}
# Creation d'une coube avec 5 p - Courbe de Bezier
$c->createLine(@p,
-smooth => 1,
);

# Creation d'une coube avec 5 p - Courbe normal => LINE
for (my $i = 0; $i <= $#p; $i = $i+2) {
last unless ( defined $p[$i+3] );
$c->createLine($p[$i],$p[$i+1],$p[$i+2],$p[$i+3],
-smooth => 1,
-fill => 'green',
);
}

# GDGRAPH SPLINED
my $graph = GD::Graph::splined->new( 700, 400 );
$graph->set(
y_label => 'y',
x_label => 'x',
line_width => 2,
title => 'splined',
);
$graph->plot(@PointGd);
my ( $FhTemp, $FileTemp ) = File::Temp::tempfile(
UNLINK => 1,
SUFFIX => ".png",
);
binmode $FhTemp;
print {$FhTemp} $graph->gd->png;
close($FhTemp);

$pane->Label(
-image => $pane->Photo(-file => $FileTemp),
)->pack( qw / -side left/);

MainLoop;



Comparez les 4 courbes (bezier, jean-louis, line et gdgraph),
j'aimerais réaliser celle de gd::graph, qui est représentative et qui
passe par tous les points.

J'arrive pas à trouver l'algo adequat.

Merci
Publicité
Poster une réponse
Anonyme