La bascule mathématique en AutoLISP, des 0 et des 1 bien utiles

C’est ce qu’on appelle le « Toggle (ou bascule) Mathématique ». C’est l’équivalent en code de faire un créneau en frein à main : c’est rapide, ça impressionne la galerie, et ça évite de tourner le volant (écrire des if) pendant des heures.

Voici le topo pour briller à la machine à café.

:nerd_face: La méthode « J’aime taper au clavier » (Le Junior)

Le débutant voit un interrupteur (0 ou 1). Il se dit : « Je vais faire une condition logique ! ».

Il écrit donc ce pavé :

;; C'est long, c'est lourd, ça prend 4 lignes...
(if (= ma-variable 1)
    (setq ma-variable 0)
    (setq ma-variable 1)
)

:smiling_face_with_sunglasses: La méthode « Ninja des Maths » (Le Senior)

Le vétéran sait que les ordinateurs aiment les chiffres, pas la philosophie. Il utilise la soustraction pour inverser la réalité.

La formule magique : 1 - x

;; Bam. Une ligne.
(setq ma-variable (- 1 ma-variable))

:brain: Pourquoi ça marche ? (La preuve par l’exemple)

C’est de l’arithmétique de base, mais c’est d’une beauté absolue :

  1. Si votre variable vaut 1 :

1 - 1 = 0 (La lumière s’éteint :new_moon:)

  1. Si votre variable vaut 0 :

1 - 0 = 1 (La lumière s’allume :light_bulb:)

:bullseye: Verdict

C’est l’astuce ultime pour gérer des bascules (visibilité, calque gelé/dégelé) sans polluer votre code avec des parenthèses conditionnelles.

Voici comment appliquer cette logique binaire au code DXF 70 (qui gère l’état Gelé/Dégelé) et une variante pour le code 62 (Actif/Inactif).

1. Le Cas du Gel/Dégel (Code DXF 70)

Le code 70 est un champ de bits (bitmask). Le premier bit (valeur 1) détermine si le calque est gelé.

  • 0 = Dégelé

  • 1 = Gelé

C’est le candidat parfait pour notre soustraction 1 - x.

(defun ToggleFreeze (layerName / ent flags status new_status)
  ;; 1. On récupère la liste DXF du calque
  (setq ent (entget (tblobjname "LAYER" layerName)))
  
  ;; 2. On isole le code 70 (les drapeaux)
  (setq flags (cdr (assoc 70 ent)))
  
  ;; 3. On extrait juste le bit de gel (0 ou 1) avec un ET logique
  (setq status (logand 1 flags))
  
  ;; 4. LA MAGIE NINJA : On inverse (0 devient 1, 1 devient 0)
  (setq new_status (- 1 status))
  
  ;; 5. On reconstruit le code 70
  ;; (On enlève l'ancien bit et on ajoute le nouveau)
  (setq ent (subst (cons 70 (+ (- flags status) new_status))
                   (assoc 70 ent)
                   ent))
  
  ;; 6. On valide la modification
  (entmod ent)
)

2. Le Cas Actif/Inactif (Code DXF 62) - Le Cousin « Négatif »

Pour la visibilité (l’ampoule), AutoCAD® n’utilise pas 0 et 1, mais le signe de la couleur (Code 62).

  • Positif (ex: 7) = Calque Actif

  • Négatif (ex: -7) = Calque Inactif

Ici, l’astuce du 1 - x ne marche pas, mais son cousin x * -1 prend le relais. C’est le même principe : une opération mathématique remplace la condition if.

(defun ToggleOnOFF (layerName / ent color)
  (setq ent (entget (tblobjname "LAYER" layerName)))
  
  ;; On récupère la couleur (ex: 7 ou -7)
  (setq color (cdr (assoc 62 ent)))
  
  ;; LA MAGIE : On multiplie par -1 pour inverser le signe
  ;; 7 devient -7 (OFF), -7 devient 7 (ON)
  (entmod (subst (cons 62 (* color -1)) (assoc 62 ent) ent))
)

Résumé pour briller en société

  • Si c’est 0 ou 1 (Gelé, Verrouillé) : Utilisez (- 1 x)

  • Si c’est + ou - (Actif, Inactif) : Utilisez (* x -1)

Pas un seul if à l’horizon. C’est propre, c’est net.

  • Malin
  • Pas mal
  • Ouais bof…
  • Ca sert à quoi?
0 votant

Bonjour,
Une petite remarque en passant, si c’est pour briller en société dans le cas de + ou (Actif, Inactif) utilisez l’opérateur
Ex :

  • si x est positif (- x) retourne un nombre négatif
  • si x est négatif (- x) retourne un nombre positif

Et si c’est un entier et que vous est considérez 0 comme un positif, il est possible de briller encore plus avec la fonction ~ (bitwise NOT)

1 « J'aime »

Pour faire suite à ma remarque précédente, je propose de bousculer un peu ce qui a été écrit précédemment, pour basculer d’une bascule à l’autre et rendre cela plus ludique et générique.

Avec l’introduction d’un argument supplémentaire il est possible de généraliser cela, pour préciser si l’on veut basculer le signe (+/-) de l’argument ou de la valeur pour une bascule binaire (0/1)

Pour cela suffit de fusionner les deux expressions (- 1 x) et (- x) avec l’argument supplémentaire que nous allons appeler mode (- mode x) qui aura pour valeur 1 ou 0 (soit une bascule pour rester dans le sujet).

  • mode=1, pour avoir une bascule binaire (0/1)
  • mode=0, pour réalisé une bascule sur le signe (+/-)

Code de la bascule générique

;; Bascule générique
;; mode = 1, pour basculer l’argument int de l’état 0 à 1 et vice-versa
;; mode = 0, pour basculer l’argument int de positif à négatif et vice-versa
    (defun Toggle (int mode) (- mode int))

Application en bascule binaire (mode 1)

Commande : (toggle 0 1)
1
Commande : (toggle 1 1)
0

Application en bascule positif/négatif (mode 0)

Commande : (toggle 7 0)
-7
Commande : (toggle -7 0)
7

Au besoin, on peut souhaiter augmenter la fonction pour modifier l’argument à basculer, à la condition de le renseigner sous forme de variable quoté:

;; Mémorisation de la Bascule dans son argument
;; var= variable ‘quoté à basculer et modifier
;; mode = 1, pour basculer l’argument var de l’état 0 à 1 et vice-versa
;; mode = 0, pour basculer l’argument var de positif à négatif et vice-versa
(defun SetToggle (var mode) (set var (- mode (eval var))))

Exemple:

Commande : (setq x 8)
8
Commande : (settoggle 'x 0)
-8
Commande : !x
-8

ou

Commande : (setq x 0)
0
Commande : (settoggle 'x 1)
1
Commande : (settoggle 'x 1)
0

Bon Lisp à tous