CXSUMMesure et polylignesVersion 1.0.0Testé dans AutoCAD
Totaliser longueur et surface par calque
Additionne la longueur et la surface des objets sélectionnés calque par calque et donne un total général, à recopier ou à placer sous forme de tableau.
Comment l'utiliser
- Saisissez CXSUM et sélectionnez les objets.
- Lisez le tableau sur la ligne de commande.
- Choisissez Yes puis cliquez pour le placer dans le dessin.
Bon à savoir
- La surface n'est comptée que pour les formes fermées.
Le charger dans AutoCAD
- Enregistrez le fichier où vous voulez.
- Tapez APPLOAD, choisissez le fichier et cliquez sur Charger.
- Tapez le nom de la commande : CXSUM.
Pour l'avoir à chaque démarrage, ajoutez-le à la Mallette de démarrage dans la même boîte de dialogue, ou chargez un dossier entier d'un coup avec le chargeur facultatif. À propos du chargeur facultatif
Testé dans AutoCAD (version complète). D'autres programmes qui exécutent AutoLISP peuvent fonctionner, mais ils n'ont pas été testés.
Le code
Du texte brut, rien de caché. Copiez-le dans un fichier nommé cxsum.lsp ou téléchargez-le.
;;; ============================================================================
;;; CXSUM - Total length and area by layer
;;; Version 1.0.0
;;; CADXChange LISP tools - https://cadxchange.net/resources/lisp/cxsum
;;; Tested in: AutoCAD (full version). Other programs that run AutoLISP may work but are not tested.
;;; Copyright (c) CADXChange. Free for personal and commercial use; do not resell or
;;; republish it as a collection. Terms: https://cadxchange.net/legal/lisp-terms
;;; ============================================================================
;; Total the lengths and areas of the objects in NAMES, layer by layer.
;; Lines, arcs, polylines, circles and ellipses have a length (a circle: its circumference); closed polylines,
;; circles and full ellipses also have an area. Returns ((layer count length area) ...) sorted by layer name.
(defun cx:sum-run (names / table ed layer len area row)
(foreach e names
(setq ed (entget e)
layer (cx:dxf 8 ed)
len (cx:ent-length ed)
area (cx:ent-area ed))
(if len
(progn
(setq row (assoc layer table))
(if row
(setq table (subst (list layer (1+ (nth 1 row)) (+ (nth 2 row) len) (+ (nth 3 row) (if area area 0.0))) row table))
(setq table (cons (list layer 1 len (if area area 0.0)) table))))))
(cx:sort table (function (lambda (a b) (< (strcase (car a)) (strcase (car b)))))))
(defun c:CXSUM ( / *error* cx:sv ss rows prec pt tc tl ta lines)
(setq *error* cx:err)
(if (setq ss (cx:pick "\nSelect lines, arcs, polylines, circles or ellipses: " '((0 . "LINE,ARC,LWPOLYLINE,CIRCLE,ELLIPSE"))))
(progn
(setq rows (cx:sum-run (cx:ss->list ss))
prec (getvar "LUPREC")
tc 0 tl 0.0 ta 0.0)
(princ "\nLayer / count / length / area")
(foreach r rows
(princ (strcat "\n" (car r) " " (itoa (nth 1 r)) " " (cx:num (nth 2 r) prec) " " (cx:num (nth 3 r) prec)))
(setq tc (+ tc (nth 1 r)) tl (+ tl (nth 2 r)) ta (+ ta (nth 3 r))))
(princ (strcat "\nTotal " (itoa tc) " " (cx:num tl prec) " " (cx:num ta prec)))
(if (and rows (= (cx:ask-kw "Place the table in the drawing" "Yes No" "No") "Yes")
(setq pt (getpoint "\nTop-left corner of the table: ")))
(progn
(cx:start '(("CMDECHO" . 0)))
(setq lines (mapcar (function (lambda (r) (strcat (car r) " : " (itoa (nth 1 r)) " pcs, length " (cx:num (nth 2 r) prec) ", area " (cx:num (nth 3 r) prec)))) rows))
(entmakex (list '(0 . "MTEXT") '(100 . "AcDbEntity") '(100 . "AcDbMText") (cons 10 pt)
(cons 40 (getvar "TEXTSIZE")) '(41 . 0.0) '(71 . 1) '(72 . 5)
(cons 1 (cx:join (append lines (list (strcat "Total : " (itoa tc) " pcs, length " (cx:num tl prec) ", area " (cx:num ta prec)))) "\\P"))
(cons 7 (getvar "TEXTSTYLE"))))
(cx:end)))))
(princ))
;;; ---- Shared helpers (used by the command above; identical in every CADXChange tool) ----
(defun cx:dxf (code ed)
(cdr (assoc code ed)))
;; The vertices of an LWPOLYLINE entity list as ((x y bulge start-width end-width) ...).
(defun cx:lw-verts (ed / out cur)
(foreach g ed
(cond
((= (car g) 10)
(if cur (setq out (cons cur out)))
(setq cur (list (cadr g) (caddr g) 0.0 0.0 0.0)))
((and cur (= (car g) 40)) (setq cur (list (nth 0 cur) (nth 1 cur) (nth 2 cur) (cdr g) (nth 4 cur))))
((and cur (= (car g) 41)) (setq cur (list (nth 0 cur) (nth 1 cur) (nth 2 cur) (nth 3 cur) (cdr g))))
((and cur (= (car g) 42)) (setq cur (list (nth 0 cur) (nth 1 cur) (cdr g) (nth 3 cur) (nth 4 cur))))))
(if cur (setq out (cons cur out)))
(reverse out))
;; The arc a bulge makes between P1 and P2 as (center-x center-y radius start-angle sweep), or nil for a straight segment.
;; The sweep is signed: positive turns counter-clockwise.
(defun cx:bulge-arc (p1 p2 b / theta dx dy len nx ny d ccx ccy)
(if (< (abs b) 1e-9)
nil
(progn
(setq theta (* 4.0 (atan b))
dx (- (car p2) (car p1))
dy (- (cadr p2) (cadr p1))
len (sqrt (+ (* dx dx) (* dy dy))))
(if (< len 1e-12)
nil
(progn
(setq nx (/ (- dy) len)
ny (/ dx len)
d (/ (/ len 2.0) (/ (sin (/ theta 2.0)) (cos (/ theta 2.0))))
ccx (+ (/ (+ (car p1) (car p2)) 2.0) (* nx d))
ccy (+ (/ (+ (cadr p1) (cadr p2)) 2.0) (* ny d)))
(list ccx ccy (/ len (* 2.0 (sin (/ (abs theta) 2.0))))
(atan (- (cadr p1) ccy) (- (car p1) ccx)) theta))))))
;; The number of segments of a polyline with N vertices.
(defun cx:seg-count (n closed)
(if closed n (1- n)))
;; A polyline as a list of (x y) points; arcs are cut into short straight pieces.
(defun cx:lw-points (verts closed / out i n a v1 v2 k steps ang)
(setq i 0 n (length verts))
(repeat (cx:seg-count n closed)
(setq v1 (nth i verts)
v2 (nth (rem (1+ i) n) verts)
a (cx:bulge-arc v1 v2 (nth 2 v1))
out (cons (list (car v1) (cadr v1)) out))
(if a
(progn
(setq steps (max 4 (fix (/ (abs (nth 4 a)) 0.15))) k 1)
(while (< k steps)
(setq ang (+ (nth 3 a) (* (nth 4 a) (/ (float k) steps)))
out (cons (list (+ (car a) (* (nth 2 a) (cos ang))) (+ (cadr a) (* (nth 2 a) (sin ang)))) out)
k (1+ k)))))
(setq i (1+ i)))
(if (not closed)
(setq out (cons (list (car (last verts)) (cadr (last verts))) out)))
(reverse out))
;; An object as a list of (x y) points; circles and ellipses are cut into 120 pieces, arcs into short pieces.
;; Returns nil for an object it does not know.
(defun cx:ent-points (ed / type ctr r a1 a2 k pts ratio ang maj steps)
(setq type (cx:dxf 0 ed))
(cond
((= type "LWPOLYLINE") (cx:lw-points (cx:lw-verts ed) (= 1 (logand 1 (cx:dxf 70 ed)))))
((= type "LINE")
(list (list (car (cx:dxf 10 ed)) (cadr (cx:dxf 10 ed))) (list (car (cx:dxf 11 ed)) (cadr (cx:dxf 11 ed)))))
((= type "CIRCLE")
(setq ctr (cx:dxf 10 ed) r (cx:dxf 40 ed) k 0)
(repeat 120
(setq ang (* 2.0 pi (/ k 120.0))
pts (cons (list (+ (car ctr) (* r (cos ang))) (+ (cadr ctr) (* r (sin ang)))) pts)
k (1+ k)))
(reverse pts))
((= type "ARC")
(setq ctr (cx:dxf 10 ed) r (cx:dxf 40 ed) a1 (cx:dxf 50 ed) a2 (cx:dxf 51 ed))
(if (<= a2 a1) (setq a2 (+ a2 (* 2.0 pi))))
(setq steps (max 8 (fix (/ (- a2 a1) 0.05))) k 0)
(repeat (1+ steps)
(setq ang (+ a1 (* (- a2 a1) (/ (float k) steps)))
pts (cons (list (+ (car ctr) (* r (cos ang))) (+ (cadr ctr) (* r (sin ang)))) pts)
k (1+ k)))
(reverse pts))
((= type "ELLIPSE")
(setq ctr (cx:dxf 10 ed) maj (cx:dxf 11 ed) ratio (cx:dxf 40 ed) a1 (cx:dxf 41 ed) a2 (cx:dxf 42 ed))
(if (<= a2 a1) (setq a2 (+ a2 (* 2.0 pi))))
(setq k 0)
(repeat 121
(setq ang (+ a1 (* (- a2 a1) (/ k 120.0)))
pts (cons (list (+ (car ctr) (* (car maj) (cos ang)) (* (- (cadr maj)) ratio (sin ang)))
(+ (cadr ctr) (* (cadr maj) (cos ang)) (* (car maj) ratio (sin ang))))
pts)
k (1+ k)))
(reverse pts))))
(defun cx:lw-length (verts closed / total i n a v1 v2)
(setq total 0.0 i 0 n (length verts))
(repeat (cx:seg-count n closed)
(setq v1 (nth i verts)
v2 (nth (rem (1+ i) n) verts)
a (cx:bulge-arc v1 v2 (nth 2 v1))
total (+ total (if a
(* (nth 2 a) (abs (nth 4 a)))
(distance (list (car v1) (cadr v1)) (list (car v2) (cadr v2))))))
(setq i (1+ i)))
total)
;; True for a closed polyline, a circle and a full ellipse.
(defun cx:ent-closed (ed / type)
(setq type (cx:dxf 0 ed))
(cond
((= type "LWPOLYLINE") (= 1 (logand 1 (cx:dxf 70 ed))))
((= type "CIRCLE") T)
((= type "ELLIPSE") (< (abs (- (- (cx:dxf 42 ed) (cx:dxf 41 ed)) (* 2.0 pi))) 1e-6))))
;; The length of a line, arc, polyline, circle (its circumference) or ellipse; nil for other objects.
(defun cx:ent-length (ed / type pts total i s)
(setq type (cx:dxf 0 ed))
(cond
((= type "LINE") (distance (cx:dxf 10 ed) (cx:dxf 11 ed)))
((= type "CIRCLE") (* 2.0 pi (cx:dxf 40 ed)))
((= type "ARC")
(setq s (- (cx:dxf 51 ed) (cx:dxf 50 ed)))
(if (<= s 0.0) (setq s (+ s (* 2.0 pi))))
(* (cx:dxf 40 ed) s))
((= type "LWPOLYLINE") (cx:lw-length (cx:lw-verts ed) (cx:ent-closed ed)))
((= type "ELLIPSE")
(setq pts (cx:ent-points ed) total 0.0 i 0)
(repeat (1- (length pts))
(setq total (+ total (distance (nth i pts) (nth (1+ i) pts))) i (1+ i)))
total)))
;; The area of a closed polyline with its arc segments.
(defun cx:lw-area (verts / sum i n a v1 v2)
(setq sum 0.0 i 0 n (length verts))
(repeat n
(setq v1 (nth i verts)
v2 (nth (rem (1+ i) n) verts)
sum (+ sum (/ (- (* (car v1) (cadr v2)) (* (car v2) (cadr v1))) 2.0))
a (cx:bulge-arc v1 v2 (nth 2 v1)))
(if a
(setq sum (+ sum (* 0.5 (nth 2 a) (nth 2 a) (- (nth 4 a) (sin (nth 4 a)))))))
(setq i (1+ i)))
(abs sum))
;; The area of a closed polyline, a circle or a full ellipse; nil for other objects.
(defun cx:ent-area (ed / type a)
(setq type (cx:dxf 0 ed))
(cond
((not (cx:ent-closed ed)) nil)
((= type "LWPOLYLINE") (cx:lw-area (cx:lw-verts ed)))
((= type "CIRCLE") (* pi (cx:dxf 40 ed) (cx:dxf 40 ed)))
((= type "ELLIPSE")
(setq a (distance '(0.0 0.0 0.0) (cx:dxf 11 ed)))
(* pi a a (cx:dxf 40 ed)))))
;; Merge sort of LST with PRED (a function of two items that is true when the first goes first).
(defun cx:sort (lst pred / half a b out)
(cond
((or (null lst) (null (cdr lst))) lst)
(T
(setq half (/ (length lst) 2) a nil b lst)
(repeat half (setq a (cons (car b) a) b (cdr b)))
(setq a (cx:sort (reverse a) pred) b (cx:sort b pred) out nil)
(while (and a b)
(if (apply pred (list (car b) (car a)))
(setq out (cons (car b) out) b (cdr b))
(setq out (cons (car a) out) a (cdr a))))
(append (reverse out) a b))))
;; Close the undo step and put the system variables back.
(defun cx:end ()
(foreach v cx:sv (setvar (car v) (cdr v)))
(command "_.UNDO" "_End")
(setq cx:sv nil)
(princ))
;; Error handler: restores everything, stays quiet on Esc.
(defun cx:err (msg)
(if (> (getvar "CMDACTIVE") 0) (command))
(cx:end)
(if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")))
(princ (strcat "\nError: " msg)))
(princ))
;; Use the objects already selected, or ask the user to select; FILTER is an ssget filter list or nil.
(defun cx:pick (msg filter / ss)
(setq ss (if filter (ssget "_I" filter) (ssget "_I")))
(if (null ss)
(progn
(princ msg)
(setq ss (if filter (ssget filter) (ssget)))))
ss)
;; Selection set to a list of entity names.
(defun cx:ss->list (ss / i out)
(setq i 0)
(if ss
(repeat (sslength ss)
(setq out (cons (ssname ss i) out)
i (1+ i))))
(reverse out))
;; Real X as text with at most PREC decimals and no trailing zeros ("2.50" -> "2.5", "3.00" -> "3").
(defun cx:num (x prec / s)
(setq s (rtos x 2 prec))
(if (wcmatch s "*.*")
(progn
(while (= (substr s (strlen s)) "0") (setq s (substr s 1 (1- (strlen s)))))
(if (= (substr s (strlen s)) ".") (setq s (substr s 1 (1- (strlen s)))))))
(if (or (= s "-0") (= s "")) "0" s))
;; Replace every OLD in STR by NEW (case sensitive).
(defun cx:replace (str old new / n out pos)
(setq n (strlen old) out "" pos 1)
(if (= n 0)
str
(progn
(while (<= pos (1+ (- (strlen str) n)))
(if (= (substr str pos n) old)
(setq out (strcat out new) pos (+ pos n))
(setq out (strcat out (substr str pos 1)) pos (1+ pos))))
(strcat out (substr str pos)))))
;; Ask for one of the keywords in BITS ("Yes No"), default DEF; returns the keyword.
(defun cx:ask-kw (msg bits def / v)
(initget 0 bits)
(setq v (getkword (strcat "\n" msg " [" (cx:replace bits " " "/") "] <" def ">: ")))
(if v v def))
;; Save the system variables in VARS ((name . value) ...), set them, and open one undo step.
;; The caller declares cx:sv as a local so the saved values live exactly as long as the command.
(defun cx:start (vars)
(setq cx:sv (mapcar (function (lambda (v) (cons (car v) (getvar (car v))))) vars))
(command "_.UNDO" "_Begin")
(foreach v vars (setvar (car v) (cdr v)))
(princ))
(defun cx:join (lst delim / out)
(setq out "")
(foreach s lst
(setq out (if (= out "") s (strcat out delim s))))
(if lst out ""))
(princ "\nCXSUM loaded. Type CXSUM to start.")
(princ)
Historique des versions
Version 1.0.0 · 27 octobre 2026
Première version.
Autres commandes : Mesure et polylignes
CXAREAÉcrire la surface à l'intérieur des formes ferméesCXLENÉcrire la longueur le long des lignes, arcs et polylignesCXCENTROIDTrouver et marquer le centre des formes ferméesCXDISTMesurer un parcours point par pointCXPLCLOSEFermer les polylignes dont les extrémités se touchent presqueCXPLREVInverser le sens des lignes et polylignesCXPLCLEANSupprimer les sommets en double et alignésCXPLWIDTHDonner une même largeur à de nombreuses polylignesCXJOINJoindre lignes et arcs en polylignes, avec tolérance d'écart