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

Géométrie et distance

21 réponses
Avatar
Michael Grünewald
Salut,

j'ai implémenté quelques classes représentant des figures dans le plan
(des points, des lignes brisées, …) et j'ai besoin de calculer des
distances entre deux objets ou des intersections.

J'aimerais avoir quelques indications sur la façon de s'en tirer habilement.


La méthode malhabile que j'utilise jusqu'ici consiste à ajouter une
méthode distance_to_<figure> à chaque classe qui doit calculer sa
distance à une <figure>. Le moins qu'on puisse dire est que ce n'est ni
très joli, ni très maintenable!

Je pensais créer une classe singleton «PlanStrategy» en charge de
calculer les distances (et les intersections) qui apprend des cas
particuliers et qui sait les généraliser. Par exemple, chaque classe de
figure est capable de se présenter comme une réunion de figures simples
dont on sait calculer les distances mutuelles et les intersections, et
cette présentation est utilisée par «PlanStrategy» pour traiter les cas
qu'il ne connaît pas.

Quelles sont les suggestions des développeurs chevronnés dans ce cas …
de figure?


J'ai débuté Python il y a deux semaines, le langage est très facile à
prendre en main quand on a de l'expérience de la programmation. Je
trouve que le tutoriel a quelques graves lacunes (le mot clef «return»
n'y apparaît même pas, il me semble!) mais fournit une introductiuon
efficace.

J'ai cependant quelques problèmes avec la mise au point des programmes,
je fais partie des gens qui font beaucoup de petites fautes
d'inattention et j'ai l'habitude que le compilateur les détecte toutes
pour moi. Quelles sont les techniques de débogages plus avancées que le
saupoudrage de «print» du code? Saupoudrage qui du reste n'est pas très
recommandé s'il s'agit de traquer une erreur causée par une mauvaise
valeur envoyée vers le code d'une bibliothèque. Y-a'il des outils pour
«tracer» le code, qui notamment afficheraient les affectations de variables?


Merci pour vos conseils et votre aide!
--
Michael

10 réponses

1 2 3
Avatar
Paul Gaborit
À (at) Wed, 08 Feb 2012 11:51:50 +0100,
Alain Ketterlin écrivait (wrote):

Oui, mais pas avec deux arguments. Même pour C++ et Java.



Vous avez tort dans les deux cas. Java et C++ intègrent une signature à
chaque méthode (et fonction dans le cas de C++). Cette signature
contient le nom de la méthode (ou fonction) ainsi que l'ordre et le type
des arguments.

En CLOS on écrit des fonctions génériques [*] hors de toute classe, donc
aucun des paramètres ne prime sur les autres. On écrirait quelque chose
qui ressemble à :

(defmethod distance ((a A) (a A)) ...)
(defmethod distance ((a A) (b B)) ...)
(defmethod distance ((b B) (a A)) ...)
(defmethod distance ((b B) (b B)) ...)

Le dispatch se fait tout seul.



Ce ne sont pas des fonctions génériques (les fonctions génériques sont
ce que proposent par exemple les templates du C++). C'est juste une
fonction polymorphique. Et on procède exactement de la même manière en
C++ !

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Avatar
Alain Ketterlin
Paul Gaborit writes:

À (at) Wed, 08 Feb 2012 11:51:50 +0100,
Alain Ketterlin écrivait (wrote):

Oui, mais pas avec deux arguments. Même pour C++ et Java.



Vous avez tort dans les deux cas. Java et C++ intègrent une signatur e à
chaque méthode (et fonction dans le cas de C++). Cette signature
contient le nom de la méthode (ou fonction) ainsi que l'ordre et le type
des arguments.



Tu ne parles pas de la même chose que moi. (Peut-être parce que j 'ai
oublié de préciser que les deux classes A et B dérivent de l a même
classe.)

En CLOS on écrit des fonctions génériques [*] hors de tou te classe, donc
aucun des paramètres ne prime sur les autres. On écrirait quel que chose
qui ressemble à :

(defmethod distance ((a A) (a A)) ...)
(defmethod distance ((a A) (b B)) ...)
(defmethod distance ((b B) (a A)) ...)
(defmethod distance ((b B) (b B)) ...)

Le dispatch se fait tout seul.



Ce ne sont pas des fonctions génériques (les fonctions gén ériques sont
ce que proposent par exemple les templates du C++).



Tu as tort d'avoir supprimé la note (signalée avec [*]) que j'ava is pris
la précaution d'ajouter à mon message. En CLOS ça s'appelle des
fonctions génériques, définie avec defgeneric.

C'est juste une fonction polymorphique.



Tu sous-estimes le problème. Ajoute une sous-classe A1 de A, et tu
comprendras : la surcharge devient inopérante (puisqu'elle utilise le
type statique).

Et on procède exactement de la même manière en C++ !



Non, tu n'as pas compris le problème. Tu parles de résolution sta tique
de la surcharge alors que je parle de résolution dynamique sur plusieu rs
types. Lis http://en.wikipedia.org/wiki/Multiple_dispatch

-- Alain.
Avatar
Damien Wyart
* Alain Ketterlin in fr.comp.lang.python:
Non, tu n'as pas compris le problème. Tu parles de résolution statique
de la surcharge alors que je parle de résolution dynamique sur
plusieurs types. Lis http://en.wikipedia.org/wiki/Multiple_dispatch



Sur cette page, il y a justement plusieurs exemples en Python (certains
utilisant des modules spécifiques qui seraient peut-être un peu lourd
ici) qui pourraient peut-être être repris dans la cadre de la question
qui a initié ce fil de discussion.

--
DW
Avatar
Laurent Claessens
Il 07/02/2012 07:18, Michael Grünewald ha scritto:
Salut,

j'ai implémenté quelques classes représentant des figures dans le plan
(des points, des lignes brisées, …) et j'ai besoin de calculer des
distances entre deux objets ou des intersections.

J'aimerais avoir quelques indications sur la façon de s'en tirer habilement.



Si tu as vraiment besoin de math, tu peux utiliser Sage (qui est un
module de mathématique symbolique pour python[1])

www.sagemath.org

ça te permet de calculer des intersections de n'importe quoi dont tu
connais les équations (pourvu que ce ne soit pas trop compliqué)


Si tu n'as rien d'autre que des droites, c'est sans doute très lourd
pour pas grand chose, mais si tu as des objets compliqués (courbes
paramétriques), alors c'est vraiment ce qu'il te faut.
Ça se programme en python.


Si ça t'intéresse, j'ai écrit un truc qui définit toutes sortes de
figures dans le plan (cercles, droites, courbes paramétrées, champ de
vecteurs, vecteurs normaux, tangents, intersections, ...) et qui exporte
les dessins en pstricks pour LaTeX :

http://student.ulb.ac.be/~lclaesse/phystricks-documentation/_build/html/index.html

Les sources sont ici :
http://gitorious.org/phystricks


Bonne aprème
Laurent


[1] C'est pas tout à fait vrai, mais en gros c'est ce que c'est.
Avatar
Paul Gaborit
À (at) Wed, 08 Feb 2012 16:09:40 +0100,
Alain Ketterlin écrivait (wrote):

Paul Gaborit writes:

À (at) Wed, 08 Feb 2012 11:51:50 +0100,
Alain Ketterlin écrivait (wrote):

Oui, mais pas avec deux arguments. Même pour C++ et Java.



Vous avez tort dans les deux cas. Java et C++ intègrent une signature à
chaque méthode (et fonction dans le cas de C++). Cette signature
contient le nom de la méthode (ou fonction) ainsi que l'ordre et le type
des arguments.



Tu ne parles pas de la même chose que moi. (Peut-être parce que j'ai
oublié de préciser que les deux classes A et B dérivent de la même
classe.)



Et sans doute manque-t-il le fait que le choix se fait dynamiquement
(donc lors de l'exécution et non lors de la compilation). C'est l'aspect
qui m'avait échappé et que tu sous-entendais.

Ce ne sont pas des fonctions génériques (les fonctions génériques sont
ce que proposent par exemple les templates du C++).



Tu as tort d'avoir supprimé la note (signalée avec [*]) que j'avais pris
la précaution d'ajouter à mon message. En CLOS ça s'appelle des
fonctions génériques, définie avec defgeneric.



L'appelation « générique » adoptée par CLOS ne me semble pas du tout
adaptée... Mais ce n'est pas grave si on sait de quoi on parle.

C'est juste une fonction polymorphique.



Tu sous-estimes le problème. Ajoute une sous-classe A1 de A, et tu
comprendras : la surcharge devient inopérante (puisqu'elle utilise le
type statique).




C'est la comparaison avec C++ qui m'e enduit d'erreur ! C++ ne fait pas
(tout seul) de typage dynamique : pour qu'une méthode soit choisie
dynamiquement en fonction du type réel de l'objet pointé, il *faut* que
la méthode soit virtuelle. Et effectivement, pour aller plus loin (donc
en tenant compte des arguments), il faut écrire soi-même les tests
permettant de déterminer le type réel des arguments.

Et on procède exactement de la même manière en C++ !



Non, tu n'as pas compris le problème. Tu parles de résolution statique
de la surcharge alors que je parle de résolution dynamique sur plusieurs
types. Lis http://en.wikipedia.org/wiki/Multiple_dispatch



C'est donc bien l'aspect dynamique de la chose qui est en cause.

En CLOS, que se passe-t-il en cas d'héritage multiple ?

Exemple :

B C
/
D

(D hérite de B et C).

Si j'ai définie des fonctions "génériques" (au sens CLOS) pour calculer
la distance entre des objets de type B ou C et si j'appelle la fonction
'distance' avec deux objets d1 et d2 (de type D), quelle est la fonction
'distance' qui sera choisie ? J'imagine qu'il y a une sorte de priorité
dans l'ordre d'héritage (à moins que CLOS n'accepte pas l'héritage
multiple).



--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Avatar
Alain Ketterlin
Paul Gaborit writes:

[...] http://en.wikipedia.org/wiki/Multiple_dispatch



En CLOS, que se passe-t-il en cas d'héritage multiple ?

Exemple :

B C
/
D

(D hérite de B et C).

Si j'ai défini des fonctions "génériques" (au sens CLOS) p our calculer
la distance entre des objets de type B ou C et si j'appelle la fonction
'distance' avec deux objets d1 et d2 (de type D), quelle est la fonction
'distance' qui sera choisie ? J'imagine qu'il y a une sorte de priorità ©
dans l'ordre d'héritage (à moins que CLOS n'accepte pas l'hà ©ritage
multiple).



Oui, il y a de l'héritage multiple. Chaque classe définit une lis te
(ordonnée) de super-classes, et cet ordre local est maintenu dans le
parcours du graphe (qui doit être acyclique). Après, les classes sont
parcourues dans l'ordre d'un tri topologique (toutes les sous-classes
d'une classe A apparaissent avant A).

Dans l'exemple, si D est définie avec pour superclasses B puis C,
l'ordre de recherche est D B C pour chaque paramètre. Donc l'ordre des
méthodes est DD BD CD BD BB BC CD CB CC. La première qui existe e st
appliquée. Si on avait A superclasse de B et C, l'ordre par paramà ¨tre
serait D B C A.

Déjà ça, c'est assez sport pour garder le contrôle, mai s en plus CLOS
permet, dans une méthode, d'appeler la suivante (dans la liste des
méthodes possibles). Sans compter qu'on peut "garnir" des méthode s avec
des appels implicites "avant", "après" et "autour" de chaque méth ode. Et
bien sûr on peut changer tout cela (par exemple en définissant une
fonction qui va choisir la méthode à appliquer).

Bref, c'est Common Lisp...

-- Alain.
Avatar
Michael Grünewald
Bonjour Alain,

Alain Reymond wrote:

Un excellent IDE Python est PyScripter
http://code.google.com/p/pyscripter/ :
- bon IDE, complètement automatique de code
- débogage, points d'arrêts, suivi des variables, analyse rétrospective,
etc...



merci pour ta suggestion, je crois cependant comprendre que pyscripter
ne tourne que sous windows, et je ne peux donc pas l'utiliser sous mon
FreeBSD.
--
Michael
Avatar
Michael Grünewald
Bonjour Alain,

Alain Ketterlin wrote:
[…une réponse bien détaillée à laquelle j'ai mis beaucoup de temps à


répondre!…]

merci beaucoup pour ta réponse très complète! J'ai encore programmé
pendant deux semaines en Python, et je regrette chaque jour un peu plus
le typage statique de OCaml… celui qui trouve les erreurs quand on
change l'interface des fonctions et quand on change le nom d'un
paramètre au début d'une boucle.

Pour le débogage des programmes je reprends mes habitudes de programmeur
TeX: relire le code avant d'essayer de lire le message d'erreur! :-)
--
Michael
Avatar
Michael Grünewald
Bonjour Laurent,

Laurent Claessens wrote:
Il 07/02/2012 07:18, Michael Grünewald ha scritto:
j'ai implémenté quelques classes représentant des figures dans le plan
(des points, des lignes brisées, …) et j'ai besoin de calculer des
distances entre deux objets ou des intersections.

J'aimerais avoir quelques indications sur la façon de s'en tirer
habilement.



Si tu as vraiment besoin de math, tu peux utiliser Sage (qui est un
module de mathématique symbolique pour python[1])



merci pour ta réponse mais elle ne correspond pas du tout à ma question.
Mon problème n'est pas de résoudre l'exercice de 3ème qui consiste à
calculer l'intersection de deux droites dans un plan, mais de présenter
ces fonctions dans une interface agréable pour l'utilisateur et le
programmeur. C'est une question de génie logiciel, en quelque sorte.

ça te permet de calculer des intersections de n'importe quoi dont tu
connais les équations (pourvu que ce ne soit pas trop compliqué)



À mon avis «n'importe quoi» devient assez vite «trop compliqué». Quelle
représentation pour la réponse? S'il s'agit de donner des équations de
A inter B à partir des équations de A et de B, je peux le faire de tête! :)
--
Michael
Avatar
Laurent Claessens
merci pour ta réponse mais elle ne correspond pas du tout à ma question.
Mon problème n'est pas de résoudre l'exercice de 3ème qui consiste à
calculer l'intersection de deux droites dans un plan, mais de présenter
ces fonctions dans une interface agréable pour l'utilisateur et le
programmeur. C'est une question de génie logiciel, en quelque sorte.




Ah ok. J'avais compris que tu cherchais à résoudre les équations.
J'avais pas bien compris que tu demandais essentiellement quelle
structure donner au logiciel. mea cupla.

ça te permet de calculer des intersections de n'importe quoi dont tu
connais les équations (pourvu que ce ne soit pas trop compliqué)



À mon avis «n'importe quoi» devient assez vite «trop compliqué». Quelle
représentation pour la réponse?



Juste pour l'exemple : l'intersection entre un cercle et un 1/x en
utilisant Sage en mode interactif :

sage: f(x,y)=x**2+y**2-4
sage: g(x)=1/x
sage: solve( [f(x,y)==0,y==g(x)],[x,y] )
[[x == -sqrt(sqrt(3) + 2), y == -1/sqrt(sqrt(3) + 2)], [x ==
sqrt(sqrt(3) + 2), y == 1/sqrt(sqrt(3) + 2)], [x == -sqrt(-sqrt(3) + 2),
y == -1/sqrt(-sqrt(3) + 2)], [x == sqrt(-sqrt(3) + 2), y ==
1/sqrt(-sqrt(3) + 2)]]

Sage donne donc la réponse sous forme de liste de liste. Chaque élément
est une liste [x==A,y==B]

Pour avoir la coordonnée x de la première intersection :
sage: S=solve( [f(x,y)==0,y==g(x)],[x,y] )
sage: S[0][0].rhs() #rhs=Right Hand Side
-sqrt(sqrt(3) + 2)


Bon, évidemment si le but est de faire un truc agréable à utiliser pour
l'utilisateur, il faut ajouter quelque couches pour cacher l'utilisation
de Sage ;)

Bonne aprème
Laurent
1 2 3