CadXP: Premier LISP : Rayon de l'arc reliant trois points - CadXP

Aller au contenu

Page 1 sur 1
  • Vous ne pouvez pas commencer un sujet
  • Vous ne pouvez pas répondre à ce sujet

Premier LISP : Rayon de l'arc reliant trois points

#1 L'utilisateur est hors-ligne   crashray 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 145
  • Inscrit(e) : 25-novembre 11

Posté 15 septembre 2020 - 16:11

Bonjour,
Je vais essayer de me mettre au LISP pour pouvoir faire des routines qui me seront utiles. Le but final est de pouvoir cliquer sur une polyligne qui passe par différents points topographiques et sortir une variation des rayons de courbures. Je vais le faire en plusieurs étapes :
  • fonction où je sélectionne 3 pts et qui me sort le rayon
  • fonction où je sélectionne une polyligne à 3 sommets et qui me sort le rayon
  • fonction où je sélectionne X points et qui me sort les X-2 rayons. Premier rayon avec les points 1-2-3, deuxième rayon avec les points 2-3-4, etc.
  • fonction où je sélectionne une polyligne et me sort pareil que la fonction précédente

Vaste programme :P

J'ai commencé à lire le PDF de Gilles qui est très complet. J'ai fait les formules de calcul sous excel qui fonctionne bien.
Je voudrais essayer de rentrer dans le vif du sujet avec un premier lisp. Pour l'instant, j'en suis là (j'ai utiliser les formules de cette page):
(defun c:rayon(/ pt1 pt2 pt3)
	(setq pt1 (getpoint "\nPremier point : "))
  	(setq pt2 (getpoint "\nDeuxième point : "))
  	(setq pt3 (getpoint "\nTroisième point : "))
;; Calcul des coordonnées (xc,yc) du centre du cercle passant par les 3 points
  (setq xc (/
 (-
 (/
  (+
    (-
      (* (car pt3) (car pt3))
      (* (car pt2) (car pt2))
    )
    (-
      (* (cadr pt3) (cadr pt3))
      (* (cadr pt2) (cadr pt2))
    )
  )
  (*
    2
    (-
      (cadr pt3)
      (cadr pt2)
    )
   )
 )

 (/
  (+
    (-
      (* (car pt2) (car pt2))
      (* (car pt1) (car pt1))
     )
    (-
      (* (cadr pt2) (cadr pt2))
      (* (cadr pt1) (cadr pt1))
    )
   )
  (*
    2
    (-
      (cadr pt2)
      (cadr pt1)
    )
   )
 )
 )
 (-
 (/ (- (car pt2) (car pt1)) (- (cadr pt2) (cadr pt1)))
 (/ (- (car pt3) (car pt2)) (- (cadr pt3) (cadr pt2)))
 )
)
)

(setq yc 
(+  
(*
  (*
   (/
    (- (car pt2) (car pt1))
    (- (cadr pt2) (cadr pt1))
   )
   xc
   )
 -1)
 (/
  (+
    (-
      (* (car pt2) (car pt2))
      (* (car pt1) (car pt1))
    )
    (-
      (* (cadr pt2) (cadr pt2))
      (* (cadr pt1) (cadr pt1))
    )
   )
  (*
    2
    (-
      (cadr pt2)
      (cadr pt1)
    )
   )
 )
)
)

(setq rc
       	(sqrt (+
	      (* (- (car pt1)  xc)
	         (- (car pt1)  xc)
	      )
       	      (* (- (cadr pt1) yc)
	         (- (cadr pt1) yc)
	      )
	      )
	)
)
	   
  
  (princ xc)
  (princ yc)
  (princ rc)
)

Le Xc est bon, par contre j'ai un problème sur Yc. Je suis pas sûre pour mettre le - au début de la formule, j'ai multiplié par -1. Pas sûre de la syntaxe.
L'impression final ne fait pas non plus ce que je voudrais. Est-ce que je peux utiliser xc qui vient juste d'être défini ?
Voyez-vous l'erreur sur le Yc ?


J'ai vu que la librairie gc_MathGeom faisait cela. gc_MathGeom.lsp avec la fonction :
;; gc:Circumscribe
;; Retourne le centre, le rayon et la normale du cercle circonscrit au le triangle p1 p2 p3
;;
;; Arguments
;; p1, p3, p3 : 3 points décrivant un triangle dans l'espace
(defun gc:Circumscribe (p1 p2 p3 / v1 v2 n m1 m2 c)
  (setq	v1 (mapcar '- p2 p1)
	v2 (mapcar '- p3 p1)
	n  (gc:CrossProduct v1 v2)
	m1 (gc:MidPoint p1 p2)
	m2 (gc:MidPoint p1 p3)
  )
  (list
    (setq c (inters
	      m1
	      (mapcar '+ m1 (gc:CrossProduct v1 n))
	      m2
	      (mapcar '+ m2 (gc:CrossProduct v2 n))
	      nil
	    )
    )
    (distance c p1)
    (gc:GetNormal n)
  )
)

qui utilise les sous-fonctions gc:CrossProduct,gc:MidPoint, gc:GetNormal.
;; gc:CrossProduct
;; Retourne le produit vectoriel (vecteur) de deux vecteurs
;; Arguments
;; v1, v2 : deux vecteurs
(defun gc:CrossProduct (v1 v2)
  (list	(- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
	(- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
	(- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
  )
)

;; gc:GetNormal
;; Retourne le vecteur unitaire d'un vecteur
;;
;; Argument
;; v : un vecteur
(defun gc:GetNormal (v)
  ((lambda (l)
     (if (/= 0 l)
       (mapcar (function (lambda (x) (/ x l))) v)
     )
   )
    (distance '(0. 0. 0.) v)
  )
)

;; gc:MidPoint
;; Retourne le milieu de p1 p2
;;
;; Arguments
;; p1 : un point
;; p2 : un point
(defun gc:MidPoint (p1 p2)
  (mapcar (function (lambda (x1 x2) (/ (+ x1 x2) 2.))) p1 p2)
)

Je pense l'utiliser au final mais j'essaye de faire le programme de 0.
Si je voulais appeler cette fonction dans mon programme et récupérer le rayon. Comment je peux faire ça ?

Merci
Autodesk - SP2 - Autodesk 2015
Géomedia - Version 17.0f - Covadis
Microsoft - SP1 - Windows 7
Leica - Version - LEICA TS06+
0

#2 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 15 septembre 2020 - 17:04

Salut,

Si tu voulais appeler la fonction gc:Circumbscribe, tu ferais simplement :
(cadr (gc:Circumscribe pt1 pt2 pt3))
puisque la fonction retourne une liste dont le premier élément (car) est le centre, le second (cadr) le rayon et le troisième (caddr) le vecteur normal du cercle.

Mais si tu veux le faire par toi même en partant de 0 (ce qui est une excellente chose si tu veux apprendre), je te recommanderais de faire une fonction qui prend 3 points comme arguments plutôt qu'une commande (defun c:...) comme ça tu pourras utiliser cette fonction à toutes les étapes de ton programme.

Comme tu semble travailler en 2D, on peut simplifier les choses par rapport à la fonction gc:Circumscribe et utiliser les fonction géométriques fournie avec AutoLISP.
Le centre d'un cercle défini par 3 points (pt1, pt2, pt3) est à l'intersection des médiatrices des segments [pt1 pt2] et [pt2 pt3]. La fonction inters renvoie le point d'intersection de deux droites, chacune étant définie par 2 points. Il faut donc deux points sur chaque médiatrice. Un premier sur le milieu de chaque segment qu'on peut obtenir facilement en faisant la moyenne de chaque coordonnée (ou avec gc:Midpoint). Et un second point ailleurs sur la perpendiculaire au segment passant par son milieu qu'on peut obtenir avec les fonctions polar et angle.

Une ébauche de code que je te laisse le soin de compléter entre les commentaires.
(defun rayon3points (pt1 pt2 pt3 / )
  ;; calcul du point au milieu de pt1 pt2

  ;; calcul d'un autre point sur la médiatrice de pt1 pt2

  ;; calcul du point au milieu de pt2 pt3

  ;; calcul d'un autre point sur la médiatrice de pt2 pt3

  ;; calcul du centre (intersection des deux médiatrices)

  ;; calcul du rayon

)

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
Image IPB
0

#3 L'utilisateur est en ligne   VDH-Bruno 

  • ceinture noire 1er dan
  • Groupe : Membres
  • Messages : 971
  • Inscrit(e) : 29-avril 10

Posté 16 septembre 2020 - 10:38

Bonjour crashray

Félicitation pour la qualité de ton post, poser les objectifs et les problématiques clairement, c’est 80% de la résolution du problème en programmation.

Depuis hier je me fait violence (visiblement j’ai échoué :P ) pour ne pas parasiter ce post, car pour ce qui me concerne il n’y a pas meilleur pédagogue que (gile) sur ce forum pour t’aider dans l’apprentissage du lisp.
Mais à titre d’exercice quand tu en auras fini avec le cheminement proposé précédemment et s’il suffit juste d’obtenir le rayon d’un cercle passant par 3 points, sans se préoccuper de son origine.
Il est alors possible de passer par le rapport des Aires entre un triangle quelconque et un cercle circonscrit.

Pour rappel si tu as 3 points tu connais :


(defun	rayon3points (pt1 pt2 pt3 / a b c p S)

   ;; calcul des cotés a b c d'un triangle formé  par 3 pts 
  
   ;; calcul de la surface d'un triangle quelconque en fonction des cotés (formule de Héron) 
  
   ;; calcul du rayon du cercle par la relation R= (a b c)/ 4S

)


Bon courage et bonne continuation dans ton apprentissage du lisp
Bruno

(Ps : Cette variante est plus directe car elle n’utilise que des opérateurs arithmétiques, mais moins formateur car elle n’introduit pas les éléments de langage supplémentaire que sont inters, polar, angle qui te seront essentiel pour la suite de ton apprentissage…)

Ce message a été modifié par VDH-Bruno - 16 septembre 2020 - 11:24 .

Apprendre => Prendre => Rendre
0

#4 L'utilisateur est en ligne   VDH-Bruno 

  • ceinture noire 1er dan
  • Groupe : Membres
  • Messages : 971
  • Inscrit(e) : 29-avril 10

Posté 16 septembre 2020 - 14:17

Re,

Voir le messageVDH-Bruno, le 16 septembre 2020 - 10:38 , dit :

[*]Donc sa surface (S) avec les formules de Héron d’Alexandrie.

Petite précision, pour une mise en œuvre numérique​ de la solution précédente il est préférable d'utilisé la formule de Kahan donné plus bas dans la page, voir l'article de Wikipédia...

Je me souviens maintenant pourquoi j'ai toujours préféré d'Al-Kashi à Héron et la loi des sinus sur ce genre d'exercices, ce qui permet d'avoir directement le résultat par la relation suivante:
R= a / 2 sin alpha, ou l'angle alpha est formé par le sommet opposé au coté a ce qui donne:
(defun rayon3points (pt1 pt2 pt3)
  (/ (distance pt2 pt3)
     (*	2
	(sin (abs (- (angle pt1 pt2)
		     (angle pt1 pt3)
		  )
	     )
	)
     )
  )
)

Ci-dessous le lien si tu es éventuellement intéressé par la démonstration:
Loi des sinus

Ce message a été modifié par VDH-Bruno - 16 septembre 2020 - 14:47 .

Apprendre => Prendre => Rendre
0

#5 L'utilisateur est hors-ligne   crashray 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 145
  • Inscrit(e) : 25-novembre 11

Posté 16 septembre 2020 - 16:31

Voir le message(gile), le 15 septembre 2020 - 17:04 , dit :

Salut,

Si tu voulais appeler la fonction gc:Circumbscribe, tu ferais simplement :
(cadr (gc:Circumscribe pt1 pt2 pt3))
puisque la fonction retourne une liste dont le premier élément (car) est le centre, le second (cadr) le rayon et le troisième (caddr) le vecteur normal du cercle.

Mais si tu veux le faire par toi même en partant de 0 (ce qui est une excellente chose si tu veux apprendre), je te recommanderais de faire une fonction qui prend 3 points comme arguments plutôt qu'une commande (defun c:...) comme ça tu pourras utiliser cette fonction à toutes les étapes de ton programme.

Comme tu semble travailler en 2D, on peut simplifier les choses par rapport à la fonction gc:Circumscribe et utiliser les fonction géométriques fournie avec AutoLISP.
Le centre d'un cercle défini par 3 points (pt1, pt2, pt3) est à l'intersection des médiatrices des segments [pt1 pt2] et [pt2 pt3]. La fonction inters renvoie le point d'intersection de deux droites, chacune étant définie par 2 points. Il faut donc deux points sur chaque médiatrice. Un premier sur le milieu de chaque segment qu'on peut obtenir facilement en faisant la moyenne de chaque coordonnée (ou avec gc:Midpoint). Et un second point ailleurs sur la perpendiculaire au segment passant par son milieu qu'on peut obtenir avec les fonctions polar et angle.

Une ébauche de code que je te laisse le soin de compléter entre les commentaires.
(defun rayon3points (pt1 pt2 pt3 / )
  ;; calcul du point au milieu de pt1 pt2

  ;; calcul d'un autre point sur la médiatrice de pt1 pt2

  ;; calcul du point au milieu de pt2 pt3

  ;; calcul d'un autre point sur la médiatrice de pt2 pt3

  ;; calcul du centre (intersection des deux médiatrices)

  ;; calcul du rayon

)


Merci pour ton aide.
Alors après avoir tout programmé à l'exception du rayon et un plantage d'AutoCad sans sauvergarde, je reprogramme tout, ça me donne :
(defun c:rayon3points (/ pt1 pt2 pt3)
	(setq pt1 (getpoint "\nPremier point : "))
  	(setq pt2 (getpoint "\nDeuxième point : "))
  	(setq pt3 (getpoint "\nTroisième point : "))
  ;; calcul du point au milieu de pt1 pt2
(setq milieu1 (list
		(/ (+(car pt1)(car pt2)) 2)
		(/ (+(cadr pt1)(cadr pt2)) 2)
		)
      )
	 
  ;; calcul d'un autre point sur la médiatrice de pt1 pt2
(setq autre1 (list 0
   (/
  (+
    (-
      (* (car pt2) (car pt2))
      (* (car pt1) (car pt1))
    )
    (-
      (* (cadr pt2) (cadr pt1))
      (* (cadr pt2) (cadr pt1))
    )
  )
  (*
    2
    (-
      (cadr pt2)
      (cadr pt1)
    )
   )
 )
)
      )
  ;; calcul du point au milieu de pt2 pt3
(setq milieu2 (list
		(/ (+(car pt2)(car pt3)) 2)
		(/ (+(cadr pt2)(cadr pt3)) 2)
		)
      )
	 
  

  ;; calcul d'un autre point sur la médiatrice de pt2 pt3
(setq autre2 (list 0
   (/
  (+
    (-
      (* (car pt3) (car pt3))
      (* (car pt2) (car pt2))
    )
    (-
      (* (cadr pt3) (cadr pt2))
      (* (cadr pt3) (cadr pt2))
    )
  )
  (*
    2
    (-
      (cadr pt3)
      (cadr pt2)
    )
   )
 )
)
      )

  ;; calcul du centre (intersection des deux médiatrices)
(setq centre
  (inters milieu1 autre1 milieu2 autre2))

  ;; calcul du rayon
(setq rayon
       	(sqrt (+
	      (* (- (car pt1)  (car centre))
	         (- (car pt1)  (car centre))
	      )
       	      (* (- (cadr pt1) (cadr centre))
	         (- (cadr pt1) (cadr centre))
	      )
	      )
	)
)
(princ rayon)  
)

J'ai remis c: pour tester mon programme et les getpoints pour entrer les points. Pour l'instant, j'ai l'erreur :
Commande: RAYON3POINTS

Premier point : _nod de
Deuxième point : _nod de
Troisième point : _nod de ; erreur: type d'argument incorrect: numberp: nil

Je ne dois pas bien définir mes listes pour ma création de points. J'ai pris la solution en x=0 pour le deuxième point de la médiane. Je n'ai pas utiliser les fonctions polar et angle.

J'ai tenté la deuxième solution de VDH-Bruno (merci également ;) )
(defun  c:r3points (/pt1 pt2 pt3)
(setq pt1 (getpoint "\nPremier point : "))
  	(setq pt2 (getpoint "\nDeuxième point : "))
  	(setq pt3 (getpoint "\nTroisième point : "))
   ;; calcul des cotés a b c d'un triangle formé  par 3 pts 
(setq a (sqrt (+ (* (- (car pt2) (car pt1)) (- (car pt2) (car pt1)))
		 (* (- (cadr pt2) (cadr pt1)) (- (cadr pt2) (cadr pt1)))
		 )
	      )
      )
(setq b (sqrt (+ (* (- (car pt2) (car pt3)) (- (car pt2) (car pt3)))
		 (* (- (cadr pt2) (cadr pt3)) (- (cadr pt2) (cadr pt3)))
		 )
	      )
      )
(setq c (sqrt (+ (* (- (car pt1) (car pt3)) (- (car pt1) (car pt3)))
		 (* (- (cadr pt1) (cadr pt3)) (- (cadr pt1) (cadr pt3)))
		 )
	      )
      )  
   ;; calcul de la surface d'un triangle quelconque en fonction des cotés (formule de Héron)
(setq p (/ (+ (+ a B) c) 2))
(set s (sqrt (* (* (* p (- p a)) (- p B)) (-p c))))
  
   ;; calcul du rayon du cercle par la relation R= (a b c)/ 4S
(setq r (/ (* (* a B) c) (* 4 s)))
  (princ r)

)

J'ai un problème de définition je pense dans ma fonction. J'ai pas bien compris, si je mets pas c: comment je teste ma fonction ? Et si je mets c:, je dois avoir un moyen de pointer mes points. J'avais trouvé getpoint qui a l'air de bien fonctionner. Mais normalement ce sont des arguments ils devraient être avant le /.
c:rayon(pt1 pt2 pt3/a b c p s r)
Mais ça a pas l'air de fonctionner.
Pas eu trop le temps aujourd'hui (6h de route, aller retour sur un chantier). Je revois ça demain.
Bonne soirée.
Autodesk - SP2 - Autodesk 2015
Géomedia - Version 17.0f - Covadis
Microsoft - SP1 - Windows 7
Leica - Version - LEICA TS06+
0

#6 L'utilisateur est en ligne   Luna 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 110
  • Inscrit(e) : 27-février 20

Posté 16 septembre 2020 - 16:44

Coucou,

Juste pour info, le "c:" permet de définir une commande AutoCAD personnalisée, donc comme pour une commande normale, elle ne prend pas en compte les arguments (il faut donc pour cela prévoir la définition des arguments au sein de l'expression de la commande). En revanche, pour tester un programme séparé en plusieurs fonctions, il est plus simple de conserver l'écriture en fonction (donc ne pas mettre de "c:" devant le nom de la fonction), tu auras ainsi accès aux arguments.

Pour tester une commande dans une fenêtre AutoCAD, il suffit d'écrire directement le nom de la commande, pour une fonction, il faut ajouter des parenthèses (comme si tu étais dans l'éditeur Visual Lisp) :

(defun c:TEST (/ pt1)
    (setq pt1 (getpoint "\nPoint : "))
)
>
Commande: TEST
Point : 
(0.0 0.0 0.0)

(defun TEST (pt1)
    (princ pt1)
)
>
Commande: (TEST (getpoint "\nPoint : "))
Point :
(0.0 0.0 0.0)


Cette différence doit sûrement être expliquée plus clairement sur le site de (gile) Introduction à AutoLISP :3
Aller bon courage ! Chat fait plaisir de voir des personnes qui préfèrent apprendre au lieu de copier-coller :)

Bisous,
Luna
0

#7 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 16 septembre 2020 - 17:17

Voir le messagecrashray, le 16 septembre 2020 - 16:31 , dit :

J'ai remis c: pour tester mon programme et les getpoints pour entrer les points. Pour l'instant, j'ai l'erreur :
Commande: RAYON3POINTS

Premier point : _nod de
Deuxième point : _nod de
Troisième point : _nod de ; erreur: type d'argument incorrect: numberp: nil


Le message veut dire que l'interpréteur attend un nombre comme argument mais reçoit nil. C'est la variable centre qui est nil parce que tu n'as pas spécifié le dernier argument de inters comme nil pour que l'intersection soit celle de deux droites infinies (sans cet argument, le point d'intersection doit être sur les deux segments).

Voir le messagecrashray, le 16 septembre 2020 - 16:31 , dit :

J'ai pris la solution en x=0 pour le deuxième point de la médiane. Je n'ai pas utiliser les fonctions polar et angle.

Le centre que tu trouves n'est pas juste. Tu peux placer un (command "_point" "_non" centre) dans le code pour vérifier.
Pour tracer les médiatrices les fonctions polar et angle t'aideront. La fonction polar renvoie le point calculé depuis le point d'origine à la distance donnée suivant l'angle donné. Le point d'origine est le milieu du segment. L'angle doit être perpendiculaire à celui du segment que tu obtiens facilement avec la fonction angle auquel il faut rajouter 90° soit PI/2 radians (les calculs se font toujours en radians). La distance peut être 1.0 ou n'importe quoi d'autre différent de 0.
Tu peux aussi utiliser la fonction distance pour calculer le rayon.
Relis le chapitre 10 de Introduction à AutoLISP.

Voir le messagecrashray, le 16 septembre 2020 - 16:31 , dit :

J'ai un problème de définition je pense dans ma fonction. J'ai pas bien compris, si je mets pas c: comment je teste ma fonction ? Et si je mets c:, je dois avoir un moyen de pointer mes points. J'avais trouvé getpoint qui a l'air de bien fonctionner. Mais normalement ce sont des arguments ils devraient être avant le /.

On utilise (defun c:...) pour définir des commandes. Pour des fonctions AutoLISP qui prennent des arguments, on ne met pas le préfixe c:.
Pour tester ton code, tu peux faire une commande dans laquelle tu récupères les données utilisateurs avec getpoint et tu passes les points récupérés une fonction dont tu récupère la valeur de retour comme tu le fais avec les fonctions natives.
Par exemple, tu crée une fonction milieu2points que tu appelles depuis ta commande :
(defun milieu2points (pt1 pt2)
  (list
    (/ (+ (car pt1) (car pt2)) 2.0)
    (/ (+ (cadr pt1) (cadr pt2)) 2.0)
  )
)

Une commande pour tester la fonction milieu2points :
(defun c:test (/ pt1 pt2 pt3)
  (setq pt1 (getpoint "\nPremier point: "))
  (setq pt2 (getpoint "\nSecond point: "))
  (setq pt3 (milieu2points pt1 pt2))
  (command "_point" "_non" pt3)
  (princ)
)

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
Image IPB
0

#8 L'utilisateur est hors-ligne   (gile) 

  • ceinture rouge et blanche 8em dan
  • Groupe : Moderateurs
  • Messages : 11 424
  • Inscrit(e) : 02-septembre 05

Posté 16 septembre 2020 - 17:42

@VDH-Bruno, merci pour ces méthodes plus "mathématiques".
Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
Image IPB
0

#9 L'utilisateur est en ligne   VDH-Bruno 

  • ceinture noire 1er dan
  • Groupe : Membres
  • Messages : 971
  • Inscrit(e) : 29-avril 10

Posté 16 septembre 2020 - 21:56

@(gile)

Voir le message(gile), le 16 septembre 2020 - 17:42 , dit :

@VDH-Bruno, merci pour ces méthodes plus "mathématiques".

Les méthodes font suite à cet ancien sujet ou nous avions échangés deux approches: pour les matheux
Je m'explique pour crashray lorsqu'il sagit en géométrie de trouvez une mesure (distance), j'ai tendance à privilégier la méthode des sinus, la trigonométrie, les relations entre le cercle unitaire et résolutions des trigones, les rapports de surface ect... Disons les outils de résolutions de la "géométrie classique", c'est très facilement calculable et démontrable avec un petit dessin, les ressources sont nombreuses et facile d'accès.
Ces relations reposent sur des proportions, cela fonctionne en 2D et généralement plutôt bien en 3D, sans avoir besoin de ce soucier des paramètres que sont les systèmes de coordonnées (SCO, SCG, SCU) ni des orientations et directions dans les calculs.
Par contre si il faut renvoyer des points (coordonnées), j'utiliserais plus naturellement les outils des "mathématiques modernes" et je vais aller sur du calcul vectoriel et les outils de calcul matriciel comme proposé par (gile).

C'est pourquoi j'avais félicité crashray sur la clarté de son message en disant qu'un énoncé bien posé c'est 80% du travail, le choix de la méthode de résolution est propre à chacun et c'est les 20% restant ;) .


@crashray

Voir le messagecrashray, le 16 septembre 2020 - 16:31 , dit :

J'ai tenté la deuxième solution de VDH-Bruno (merci également ;) )

Pour la correction à comparer avec ce à quoi tu étais arrivé:
(defun rayon3points (pt1 pt2 pt3 / a b c p S)
   ;; calcul des cotés a b c d'un triangle formé  par 3 pts
  (setq a (distance pt1 pt2)
	b (distance pt2 pt3)
	c (distance pt3 pt1))
  
   ;; calcul de la surface d'un triangle quelconque en fonction des cotés (formule de Héron)
  (setq p (/ (+ a b c) 2)
	S (sqrt (* p (- p a) (- p B) (- p c))))
  
   ;; calcul du rayon du cercle par la relation R= (a b c)/ 4S
  (/ (* a b c) (* 4 S))
)

Voir le messagecrashray, le 16 septembre 2020 - 16:31 , dit :

J'ai un problème de définition je pense dans ma fonction. J'ai pas bien compris, si je mets pas c: comment je teste ma fonction ? Et si je mets c:, je dois avoir un moyen de pointer mes points. J'avais trouvé getpoint qui a l'air de bien fonctionner. Mais normalement ce sont des arguments ils devraient être avant le /.
c:rayon(pt1 pt2 pt3/a b c p s r)
Mais ça a pas l'air de fonctionner.
Pas eu trop le temps aujourd'hui (6h de route, aller retour sur un chantier). Je revois ça demain.
Bonne soirée.

Pour tester:
_$ (rayon3points (getpoint) (getpoint) (getpoint))
473.719

En général en lisp on aime bien avoir dans un programme les fonctions d'entrée (saisie utilisateurs), les fonctions de traitements de donnée (calculs), les fonctions de sortie (restitution des résultats) dans des fonctions spécifiques. Le tout appelé et articulé dans une fonction principal en C:MaCommande exécuté sur la ligne de commande. Cela permet de pouvoir tester et déboguer les différentes fonctions (ou partie de programme) séparément, au fil du temps cela te permettra de te créer une bibliothèque de fonctions réutilisable et éprouvé (comme la librairie gc_MathGeom.lsp de gile) adapté à ton domaine d'activité, ce qui te permettra d'être beaucoup plus efficace dans tes développements futur un peu comme tu le ferais avec une bibliothèque de blocs sous AutoCAD.

A+ Bruno
Apprendre => Prendre => Rendre
0

#10 L'utilisateur est en ligne   VDH-Bruno 

  • ceinture noire 1er dan
  • Groupe : Membres
  • Messages : 971
  • Inscrit(e) : 29-avril 10

Posté 16 septembre 2020 - 22:31

Re,
Ce qui est très gratifiant en lisp, c'est que l'on a pas forcement besoin d'être agrégé de mathématiques pour résoudre la plupart des problèmes, si des fois on est pris par le temps, ses propres lacunes ou pour faire du prototypage rapide de son code, il est toujours possible de déléguer le calcul aux outils de dessins d'AutoCAD.
L'énoncé précédent aurait très bien pu être traiter de la façon suivante:
(defun rayon3points  (pt1 pt2 pt3 / ent rayon)
  ;; dessine un cercle par 3 points
  (command "_circle" "3P" pt1 pt2 pt3)
  ;; récupère le nom d'entité et extrait le rayon de la base de donné
  (setq	ent   (entlast)
	rayon (cdr (assoc 40 (entget ent)))
  )
  ;; supprime le cercle dessiné
  (entdel ent)
  ;; retourne le rayon à la fonction appelante
  rayon
)

Avec un peu d'habitude ça ne prend pas plus de 2mn à faire et ça fonctionne très bien aussi, il y a de nombreux exemple de programme lisp écrit comme cela qui rendent de grand service.
Bonne soirée
Apprendre => Prendre => Rendre
0

#11 L'utilisateur est hors-ligne   crashray 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 145
  • Inscrit(e) : 25-novembre 11

Posté 17 septembre 2020 - 14:54

Merci pour les conseils. Je tourne un peu en rond alors je post pour comprendre là où ça va pas :
(defun rayon3points (pt1 pt2 pt3 / rayon)

  ;; calcul du point au milieu de pt1 pt2
(setq milieu1 (list
		(/ (+(car pt1)(car pt2)) 2)
		(/ (+(cadr pt1)(cadr pt2)) 2)
		)
      )
	 
  ;; calcul d'un autre point sur la médiatrice de pt1 pt2
(setq autre1
(polar pt1 (+ (angle pt1 pt2) (/ Pi 2)) 1)
      )

Edit : merci  VDH-Bruno, ça marche bien. En fait je "panique" sur mon affichage mais je vois que si tu ne mets pas de setq et que tu fais un calcul. La fonction le renvoi automatiquement.


  ;; calcul du point au milieu de pt2 pt3
(setq milieu2 (list
		(/ (+(car pt2)(car pt3)) 2)
		(/ (+(cadr pt2)(cadr pt3)) 2)
		)
      )
	 
  

  ;; calcul d'un autre point sur la médiatrice de pt2 pt3
(setq autre2
(polar pt2 (+ (angle pt2 pt3) (/ Pi 2)) 1)
      )

  ;; calcul du centre (intersection des deux médiatrices)
(setq centre
  (inters milieu1 autre1 milieu2 autre2 nil))

  ;; calcul du rayon
(setq rayon (distance centre pt1)     
)
)


(defun c:test (/ pt1 pt2 pt3)
  (setq pt1 (getpoint "\nPremier point: "))
  (setq pt2 (getpoint "\nSecond point: "))
  (setq pt3 (getpoint "\nTroisème point: "))
  (setq r (rayon3points pt1 pt2 pt3))
  (princ r)
)

Faut-il que je mette après le \ toutes les variables que j'utilise dans la fonction ? milieu1 autre1... Ou je mets ce que je veux que la fonction renvoie ?
Autodesk - SP2 - Autodesk 2015
Géomedia - Version 17.0f - Covadis
Microsoft - SP1 - Windows 7
Leica - Version - LEICA TS06+
0

#12 L'utilisateur est en ligne   Luna 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 110
  • Inscrit(e) : 27-février 20

Posté 17 septembre 2020 - 15:45

Coucou,

Je pense que tu devrais relire le chapitre sur la fonction (defun) ^^"
Ce qui se situe avant le "/" son appelé "Arguments", ils sont fréquemment utilisé pour les fonctions afin de spécifier des données d'entrées pour le bon fonctionnement de la fonction. S'ils sont présent dans la définition de la fonction, il doivent obligatoirement être définie lors de l'appel de la fonction, en clair même si on considère un argument comme inutile pour le fonctionnement de la fonction, il faudra tout de même préciser nil pour l'argument en question.

Ce qui se situe après le "/" correspond aux "variables locales", en clair à chaque fois que l'appel de la fonction est terminé (soit la fonction est arrivée au bout de son développement, soit elle a été annulée, ...), l'ensemble des variables déclarées après le "/" sont redéfinie à leur état initial (généralement nil).

Une variable présente dans un programme mais non déclarée comme variable locale est alors une "variable globale", donc même après la fin de l'exécution de la commande/fonction, elle conservera sa valeur finale jusqu'à la fermeture du fichier (ou AutoCAD).
Ne pas déclarer ses variables comme locales entraîne de nombreux problèmes lorsque plusieurs fonctions font appel à une variable de même nom et sans remise à zéro de ces variables (essentiellement les listes construites par la fonction cons)

Ex :
(defun test (i)
    (repeat i
        (setq lst (cons (setq i (1- i)) lst))
    )
)
; Premier lancement de la fonction :
(test 3)
(0 1 2)
; Second lancement de la fonction :
(test 5)
(0 1 2 3 4 0 1 2)
; etc...

Ici, la variables lst n'est pas déclarée comme variable locale, donc à chaque lancement de la fonction, elle ajoute les valeurs de la fonction appelée à sa valeur actuelle, créant ainsi une erreur. Car le résultat attendu de (test 5) doit être (0 1 2 3 4), or ici c'est le résultat de (append (test 5) (test 3)) dans le cas ou les variables seraient déclarées comme variables locales.

Je ne sais pas si c'est assez clair, mais tu devrais retrouver tout ça dans les cours de (gile) ou de didier je pense :3
Bisous,
Luna
0

#13 L'utilisateur est hors-ligne   crashray 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 145
  • Inscrit(e) : 25-novembre 11

Posté 17 septembre 2020 - 15:50

Voir le messageLuna, le 17 septembre 2020 - 15:45 , dit :

Coucou,

Je pense que tu devrais relire le chapitre sur la fonction (defun) ^^"
Ce qui se situe avant le "/" son appelé "Arguments", ils sont fréquemment utilisé pour les fonctions afin de spécifier des données d'entrées pour le bon fonctionnement de la fonction. S'ils sont présent dans la définition de la fonction, il doivent obligatoirement être définie lors de l'appel de la fonction, en clair même si on considère un argument comme inutile pour le fonctionnement de la fonction, il faudra tout de même préciser nil pour l'argument en question.

Ce qui se situe après le "/" correspond aux "variables locales", en clair à chaque fois que l'appel de la fonction est terminé (soit la fonction est arrivée au bout de son développement, soit elle a été annulée, ...), l'ensemble des variables déclarées après le "/" sont redéfinie à leur état initial (généralement nil).

Une variable présente dans un programme mais non déclarée comme variable locale est alors une "variable globale", donc même après la fin de l'exécution de la commande/fonction, elle conservera sa valeur finale jusqu'à la fermeture du fichier (ou AutoCAD).
Ne pas déclarer ses variables comme locales entraîne de nombreux problèmes lorsque plusieurs fonctions font appel à une variable de même nom et sans remise à zéro de ces variables (essentiellement les listes construites par la fonction cons)
Très clair. Merci.
Ex :
(defun test (i)
    (repeat i
        (setq lst (cons (setq i (1- i)) lst))
    )
)
; Premier lancement de la fonction :
(test 3)
(0 1 2)
; Second lancement de la fonction :
(test 5)
(0 1 2 3 4 0 1 2)
; etc...

Ici, la variables lst n'est pas déclarée comme variable locale, donc à chaque lancement de la fonction, elle ajoute les valeurs de la fonction appelée à sa valeur actuelle, créant ainsi une erreur. Car le résultat attendu de (test 5) doit être (0 1 2 3 4), or ici c'est le résultat de (append (test 5) (test 3)) dans le cas ou les variables seraient déclarées comme variables locales.

Je ne sais pas si c'est assez clair, mais tu devrais retrouver tout ça dans les cours de (gile) ou de didier je pense :3
Bisous,
Luna

Merci. Très clair.
Autodesk - SP2 - Autodesk 2015
Géomedia - Version 17.0f - Covadis
Microsoft - SP1 - Windows 7
Leica - Version - LEICA TS06+
0

#14 L'utilisateur est hors-ligne   Olivier Eckmann 

  • ceinture noire 2em dan
  • Groupe : Membres
  • Messages : 1 435
  • Inscrit(e) : 29-décembre 11
  • LocationLongjumeau (91)

Posté 17 septembre 2020 - 21:43

Bonsoir,

Je pense que si tu veux calculer un second point sur ta médiatrice, il est important que le point à partir duquel tu construis ton "polar" soit aussi sur la médiatrice.
Or tu utilises le point pt1 qui n'est pas sur ta médiatrice, car c'est l'extrémité de ton segment.

Dès que tu attaques de la géométrie, un papier, un crayon et un joli croquis évite bien des erreurs.

Olivier
0

#15 L'utilisateur est hors-ligne   crashray 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 145
  • Inscrit(e) : 25-novembre 11

Posté 22 septembre 2020 - 07:08

La première étape est maintenant terminée :
  • fonction où je sélectionne 3 pts et qui me sort le rayon
  • fonction où je sélectionne une polyligne à 3 sommets et qui me sort le rayon
  • fonction où je sélectionne X points et qui me sort les X-2 rayons. Premier rayon avec les points 1-2-3, deuxième rayon avec les points 2-3-4, etc.
  • fonction où je sélectionne une polyligne et me sort pareil que la fonction précédente

Je passe à la deuxième. Donc j'ai un arc ou une polyligne qui relie mes trois points et je voudrais pouvoir appliquer le LISP suivant dessus :
(defun r3points (pt1 pt2 pt3 / a b c p S)
   ;; calcul des cotés a b c d'un triangle formé  par 3 pts
  (setq a (distance pt1 pt2)
        b (distance pt2 pt3)
        c (distance pt3 pt1))
  
   ;; calcul de la surface d'un triangle quelconque en fonction des cotés (formule de Héron)
  (setq p (/ (+ a b c) 2)
        S (sqrt (* p (- p a) (- p B) (- p c))))
  
   ;; calcul du rayon du cercle par la relation R= (a b c)/ 4S
  (/ (* a b c) (* 4 S))
)

J'imagine qu'il faut faire une commande qui appelle la fonction et qui demande à cliquer sur une polyligne à 3 sommets. On teste si bien 3 sommets :
- si non, message "Veuillez sélectionner une polyligne à 3 sommets"
- si oui, on appelle la fonction en "sortant" les coordonnées des 3 sommets de la polyligne.

Je crois qu'il faut que j'utilise le Chapitre 16 (Accès aux objets du dessin).

Edit :
Je vois quelques choses comme :
(princ "\nSélectionnez une polyligne à 3 sommets: ")
 (setq poly1 (entsel))
 (r3points (sortirpremierpoint poly1) (sortirdeuxiemepoint poly1) (sortirtroisièmepoint poly1)))

Edit 2 Dans un autre lisp, j'ai trouvé ça :
;; Liste des sommets d'une polyligne 3D
(defun 3dpoly_pts (ent / pt pts)
(while (setq pt (val_dxf 10 (entnext ent)))
(setq ent (entnext ent)
pts (cons pt pts)
)
)
pts
)

Autodesk - SP2 - Autodesk 2015
Géomedia - Version 17.0f - Covadis
Microsoft - SP1 - Windows 7
Leica - Version - LEICA TS06+
0

#16 L'utilisateur est en ligne   Luna 

  • ceinture bleue
  • Groupe : Membres
  • Messages : 110
  • Inscrit(e) : 27-février 20

Posté 22 septembre 2020 - 08:31

Coucou,

Citation

(princ "\nSélectionnez une polyligne à 3 sommets: ")
 (setq poly1 (entsel))
 (r3points (sortirpremierpoint poly1) (sortirdeuxiemepoint poly1) (sortirtroisièmepoint poly1)))

Attention à la fonction (entsel), elle ne retourne pas uniquement le nom de l'entité sélectionnée. Elle retourne une liste dont le premier élément correspond au nom de l'entité sélectionnée et dont le second élément correspond au point (dans le SCU courant) que l'on a spécifié. Donc la plupart du temps on utilise (car (entsel)) sans se soucier du point.

Citation

;; Liste des sommets d'une polyligne 3D
(defun 3dpoly_pts (ent / pt pts)
(while (setq pt (val_dxf 10 (entnext ent)))
(setq ent (entnext ent)
pts (cons pt pts)
)
)
pts
)

Tout dépend du type d'objet que tu utilises habituellement. Cette méthode est propre à une polyligne 3D, mais ne fonctionnera pas pour les objets "LWPOLYLINE" (les plus courantes) par exemple.
La récupération des sommets peut s'effectuer directement à partir de la liste obtenue avec (entget) pour une "LWPOLYLINE". Etant donné que tu cherches à apprendre par toi-même, je te conseille de regarder la composition d'une liste (entget) pour l'objet que tu sélectionnes pour ton programme. S'il s'agit bien de polyligne 3D, alors la méthode ci-dessus devrait t'aider, autrement je te suggère de regarder du côté des fonctions (member), (assoc), (cdr) qui permettent déjà de manipuler correctement les listes comme on le souhaite.
Il n'existe pas une seule méthode pour parvenir à un résultat, donc le plus simple est que tu trouves ta méthode qui te correspond, et tu l'amélioreras au fur et à mesure :3

PS : je te suggère également ce lien (un peu vieu mais complet) et celui ci pour une meilleure compréhension des codes DXF et il ne faut surtout pas hésiter à consulter l'aide AutoCAD sur les types d'objets que tu rencontres (par exemple l'aide sur les "LWPOLYLINE (DXF)" va beaucoup t'aider à progresser sur les listes DXF).

Bisous,
Luna
0

Partager ce sujet :


Page 1 sur 1
  • Vous ne pouvez pas commencer un sujet
  • Vous ne pouvez pas répondre à ce sujet

1 utilisateur(s) en train de lire ce sujet
0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)