Jump to content

Leaderboard

  1. BIGAL

    BIGAL

    Trusted Member


    • Points

      38

    • Posts

      20,200


  2. Danielm103

    Danielm103

    Community Member


    • Points

      29

    • Posts

      342


  3. SLW210

    SLW210

    Moderator


    • Points

      11

    • Posts

      11,707


  4. Steven P

    Steven P

    Trusted Member


    • Points

      7

    • Posts

      3,025


Popular Content

Showing content with the highest reputation since 07/26/2026 in all areas

  1. Hello. I'm happy to share this routine I created with the help of Copilot, which I believe works acceptably for distributing elements (sprinklers, detectors, etc.) based on user input. I would be very grateful if any member of this forum could improve the code or offer any advice. I'm a big fan of @Lee Mac's programs, whom I consider a master. The routine will ask the user to define the measurements that define minimum and maximum values and then, by selecting a block, from which it acquires the layer and scale properties, by selecting an area, with or without "islands", it will generate a mesh pattern, which for a preliminary design is acceptable or approximate in many cases. I am Spanish and the routine is coded in Castilian Spanish (Spain). PCI_PRO (PFP).lsp
    5 points
  2. @troggarf yep took the plunge and installed Python, the install is easy With @Danielm103 help also installed a couple of extra modules that where needed for his code. Then it's simple like lisp using Pyload instead of Appload. Or you can load python scripts using a lisp call. ; lisp start python (setq python "C:/Users/xxxxxx/AppData/Local/Python/Python-3.14-64/python.exe" pyscript "D:\\alan\\lisp\\ctb table.py" ) (startapp python pyscript)
    3 points
  3. I thought I might write some samples to help guide lisp users that are interested in trying out Python. Long time lisp users will feel right at home using result buffers (DXF Lists). In PyRx, it’s wrappers around the old school C ADS functions, I.e. ads_entget, yay, like driving an F-150 with a toilet bowl plunger as the gear shift. In Python, most of these old functions reside in Db.Core The resbuf* linked lists are wrapped into a list of tuples.. does this output look familiar? from pyrx import Ap, Db, Ed, Ge @Ap.Command() def doit0() -> None: #entsel with a filter ps, id, _ = Ed.Editor.entSel("\nPick it: ", Db.Line.desc()) if ps != Ed.PromptStatus.eOk: raise RuntimeError("oof {}:".format(ps)) #get the result buffer rb = Db.Core.entGet(id) print(rb) # [ # (-1, PyDb.ObjectId(1de8bf954d0)), # (0, 'LINE'), # (330, PyDb.ObjectId(1de8bf9a1f0)), # (5, '265'), # (100, 'AcDbEntity'), # (67, 0), # (410, 'Model'), # (8, '0'), # (100, 'AcDbLine'), # (10, PyGe.Point3d(0.00000000000000,0.00000000000000,0.00000000000000)), # (11, PyGe.Point3d(100.00000000000000,100.00000000000000,0.00000000000000)), # (210, PyGe.Point3d(0.00000000000000,0.00000000000000,1.00000000000000)) # ]
    2 points
  4. As previously stated, used an install lisp, only a few minutes.
    2 points
  5. Nice work. I built the same kind of wheel for Revit a while back, so it was good to see someone doing it on the AutoCAD side. I could not see it running from the thread either, so a short screen recording would probably get you more replies here than anything else. Everything below is from my side, on Revit, so translate it however it fits. These are the ones that cost me the most time. Aim by the pointer angle, not by which shape is under the pointer. Point in a direction and that wedge lights up, whether you are near the middle or way out past the rim. That one change is what made mine feel like a game wheel instead of a menu. Number keys 1 to 9 pick a slot directly. Once you know your own layout you stop looking at the wheel at all, and that is where the real speed comes from. Grey out a slot that cannot run right now, and work all of them out in one pass before the wheel opens. Mine has to check the current selection to answer that. Doing it slot by slot meant a 50,000 element selection got walked once for every slot on the wheel. Once for the whole wheel fixed it. Check the command will really be accepted before you fire it. When mine was refused, nothing ran but the wheel still closed as if it had worked. That is the worst kind of failure because it looks like an answer. Smaller things I would not have guessed: Test the wedge maths outside CAD. I rebuilt mine as a standalone renderer and produced every slot count at every wheel size as images. Far quicker than restarting the host for each attempt, and it found a label collision at my highest slot count that I would never have caught by eye. Store the command name in the slot, not the button text. Rename a button later and the layout survives. Slot 1 at the top, the rest clockwise, always. The muscle memory is the whole point, so that order can never move. Drop any glow or fade. Mine had a soft shadow on the hovered wedge and a fade across the whole ring, and both were being recomputed every time the pointer crossed a boundary. A brighter fill and a thicker outline read exactly the same and cost nothing. Only redraw the wedge that changed, never the whole ring. Let the config file be missing or corrupt without complaining. Mine falls back to the defaults instead of throwing a message at me, and I have never once wanted the message. Do not let dead keys close it. Enter, space and a number higher than my slot count all used to dismiss the wheel doing nothing, which just felt broken. Open the settings from the wheel itself, and let people set it up by dragging onto a real wheel instead of filling in a list. Drag a tool onto a slot to fill it, drag one slot onto another to swap them. Mine draws the same ring at a smaller size for that, so what you arrange is what opens. Two things I am curious about, since you draw with real entities in model space rather than a window over the top. Does the wheel stay the same size on screen at any zoom, or does it scale with the drawing? Mine sits in a window above everything so I never had to deal with that, but it looks like the harder half of your approach. And the double click. In AutoCAD a double click on an object opens its editor, so what happens when the pointer is over an entity instead of empty space? I went with a keyboard shortcut and dodged the question, but yours is the nicer gesture if it works.
    2 points
  6. If you use Etransmit it will add extra files to what is exported, in particular say custom fonts and xrefs.
    2 points
  7. @HypnoS if your using title blocks then it is possible to detect the name of the title block and use the correct plot settings, for example a A4 in landscape or portrait mode. Just using say layout extents can return wrong answers as even where I worked there was occasional junk in a layout outside of the title block.
    2 points
  8. Based on my practice of networking LISP, I am going to make an online game platform that executes in the CAD model space. However, the game category is different from the products I developed before. It requires a certain timeliness, which is a challenge to the network infrastructure. In short, I have developed a local battle version of Gomoku. You can copy the following code or download the lsp file to run it locally. Gomoku V0.3.lsp After the problem of the network infrastructure part is solved, the plug-in will be iterated quickly to achieve online instant challenges. I have provided another updateable installation method to avoid duplicate copying or downloading. If I update it, you will know: [Gomoku CadCade] VCID: 1G8VY1 @ VedaCAD I hope to hear your opinions on UI and interaction. ;;; AutoCAD Gomoku v0.3 ;;; Author: Vico (CadCade) ;;; Description: Standalone 15x15 Gomoku in ModelSpace (vl-load-com) ;;; --- Globals & States --- (setq *gmk-size* 15 *gmk-cell* 10.0 *gmk-radius* (* *gmk-cell* 0.333) *gmk-layer* "CADCADE_CANVAS" *gmk-p1-color* 10 ; Soft Pastel Red *gmk-p2-color* 140 ; Bright Light Blue *gmk-win-color* 3 ; Bright Green *gmk-idle-color* 8) ; Dark Gray (setq *gmk-board* nil *gmk-hover-ent* nil *gmk-active* nil *gmk-ui-x* 0.0 *gmk-ui-y* 0.0 *gmk-p1-total* 0.0 *gmk-p2-total* 0.0 *gmk-history* nil) (setq *gmk-ui-p1-time-ent* nil *gmk-ui-p1-tot-ent* nil *gmk-ui-p2-time-ent* nil *gmk-ui-p2-tot-ent* nil *gmk-ui-p1-icon-ent* nil *gmk-ui-p1-name-ent* nil *gmk-ui-p2-icon-ent* nil *gmk-ui-p2-name-ent* nil *gmk-ui-hist-1* nil *gmk-ui-hist-2* nil *gmk-ui-hist-3* nil *gmk-ui-hist-4* nil *gmk-ui-hist-5* nil *gmk-ui-hist-6* nil) ;;; --- Data Structure --- (defun gmk:get-index (x y) (+ (* y *gmk-size*) x)) (defun gmk:get-cell (x y) (if (and (>= x 0) (< x *gmk-size*) (>= y 0) (< y *gmk-size*)) (nth (gmk:get-index x y) *gmk-board*) -1 ) ) (defun gmk:set-cell (x y val / idx i nb) (setq idx (gmk:get-index x y) i 0 nb nil) (foreach item *gmk-board* (setq nb (cons (if (= i idx) val item) nb) i (1+ i)) ) (setq *gmk-board* (reverse nb)) ) ;;; --- Graphics & Layer --- (defun gmk:ensure-layer () (if (not (tblsearch "LAYER" *gmk-layer*)) (entmakex (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord") (cons 2 *gmk-layer*) '(70 . 0))) ) ) (defun gmk:purge-board (/ ss i e) (if (setq ss (ssget "_X" (list (cons 8 *gmk-layer*)))) (progn (setq i -1) (while (setq e (ssname ss (setq i (1+ i)))) (vl-catch-all-apply 'entdel (list e)) ) ) ) ) (defun gmk:draw-line (pt1 pt2 col) (entmakex (list '(0 . "LINE") (cons 8 *gmk-layer*) (cons 10 pt1) (cons 11 pt2) (cons 62 col))) ) (defun gmk:draw-thick-line (pt1 pt2 col wid) (entmakex (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") (cons 8 *gmk-layer*) '(100 . "AcDbPolyline") '(90 . 2) '(70 . 0) (cons 43 wid) (cons 62 col) (cons 10 (list (car pt1) (cadr pt1))) (cons 10 (list (car pt2) (cadr pt2))))) ) (defun gmk:draw-text (pt str hgt col) (entmakex (list '(0 . "TEXT") (cons 8 *gmk-layer*) (cons 10 pt) (cons 40 hgt) (cons 1 str) (cons 62 col))) ) (defun gmk:draw-centered-text (pt str hgt col) (entmakex (list '(0 . "TEXT") (cons 8 *gmk-layer*) (cons 10 pt) (cons 11 pt) (cons 40 hgt) (cons 1 str) (cons 62 col) '(72 . 1) '(73 . 2))) ) (defun gmk:update-dynamic-text (sym pt str hgt col / el) (if (and (eval sym) (setq el (entget (eval sym)))) (entmod (subst (cons 62 col) (assoc 62 el) (subst (cons 1 str) (assoc 1 el) el))) (set sym (gmk:draw-text pt str hgt col)) ) ) (defun gmk:update-color (ent col / el) (if (and ent (setq el (entget ent))) (entmod (subst (cons 62 col) (assoc 62 el) el)) ) ) (defun gmk:set-turn (p / c1 c2) (if (= p 1) (setq c1 *gmk-p1-color* c2 *gmk-idle-color*) (setq c1 *gmk-idle-color* c2 *gmk-p2-color*) ) (gmk:update-color *gmk-ui-p1-icon-ent* c1) (gmk:update-color *gmk-ui-p1-name-ent* c1) (gmk:update-color *gmk-ui-p2-icon-ent* c2) (gmk:update-color *gmk-ui-p2-name-ent* c2) (redraw) ) (defun gmk:draw-solid-circle (pt rad col / r2 p1 p2) (setq r2 (/ rad 2.0) p1 (list (- (car pt) r2) (cadr pt)) p2 (list (+ (car pt) r2) (cadr pt))) (entmakex (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") (cons 8 *gmk-layer*) '(100 . "AcDbPolyline") '(90 . 2) '(70 . 1) (cons 62 col) (cons 43 rad) (cons 10 p1) '(42 . 1.0) (cons 10 p2) '(42 . 1.0))) ) (defun gmk:draw-rounded-rect (xmin ymin xmax ymax r col wid / b) (setq b 0.41421356) ; tan(pi/8) (entmakex (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") (cons 8 *gmk-layer*) '(100 . "AcDbPolyline") '(90 . 8) '(70 . 1) (cons 43 wid) (cons 62 col) (cons 10 (list (+ xmin r) ymin)) (cons 42 0.0) (cons 10 (list (- xmax r) ymin)) (cons 42 b) (cons 10 (list xmax (+ ymin r))) (cons 42 0.0) (cons 10 (list xmax (- ymax r))) (cons 42 b) (cons 10 (list (- xmax r) ymax)) (cons 42 0.0) (cons 10 (list (+ xmin r) ymax)) (cons 42 b) (cons 10 (list xmin (- ymax r))) (cons 42 0.0) (cons 10 (list xmin (+ ymin r))) (cons 42 b))) ) (defun gmk:draw-board (/ i mdim cx ux-l ux-r) (setq mdim (* (1- *gmk-size*) *gmk-cell*)) (setq i 1) (while (< i (1- *gmk-size*)) (gmk:draw-line (list (* i *gmk-cell*) 0.0 0.0) (list (* i *gmk-cell*) mdim 0.0) 8) (gmk:draw-line (list 0.0 (* i *gmk-cell*) 0.0) (list mdim (* i *gmk-cell*) 0.0) 8) (setq i (1+ i)) ) (setq i 0) (while (< i *gmk-size*) (gmk:draw-text (list (- (* i *gmk-cell*) (* *gmk-cell* 0.2)) (* -0.8 *gmk-cell*) 0.0) (chr (+ 65 i)) (* *gmk-cell* 0.4) 8) (gmk:draw-text (list (* -1.4 *gmk-cell*) (- (* i *gmk-cell*) (* *gmk-cell* 0.2)) 0.0) (itoa (1+ i)) (* *gmk-cell* 0.4) 8) (setq i (1+ i)) ) (entmakex (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 8 *gmk-layer*) '(90 . 4) '(70 . 1) (cons 43 (* *gmk-cell* 0.08)) '(62 . 8) (cons 10 '(0.0 0.0)) (cons 10 (list mdim 0.0)) (cons 10 (list mdim mdim)) (cons 10 (list 0.0 mdim)))) (gmk:draw-solid-circle (list (* 7 *gmk-cell*) (* 7 *gmk-cell*) 0.0) (* *gmk-cell* 0.15) 8) (setq ux-l (+ mdim (* *gmk-cell* 2.5)) ux-r (+ ux-l (* *gmk-cell* 7.5)) cx (+ ux-l (* *gmk-cell* 3.75))) (gmk:draw-rounded-rect ux-l 0.0 ux-r mdim (* *gmk-cell* 0.5) 8 (* *gmk-cell* 0.05)) (gmk:draw-centered-text (list cx (- mdim (* *gmk-cell* 0.7)) 0.0) "GOMOKU" (* *gmk-cell* 0.55) 8) (gmk:draw-centered-text (list cx (- mdim (* *gmk-cell* 1.4)) 0.0) "CadCade.com" (* *gmk-cell* 0.25) 8) (gmk:draw-line (list (+ ux-l (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 1.9)) 0.0) (list (- ux-r (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 1.9)) 0.0) 8) (setq *gmk-ui-p1-icon-ent* (gmk:draw-solid-circle (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 2.7)) 0.0) *gmk-radius* *gmk-p1-color*)) (setq *gmk-ui-p1-name-ent* (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.8)) (- mdim (* *gmk-cell* 2.85)) 0.0) "Player 1" (* *gmk-cell* 0.4) *gmk-p1-color*)) (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 3.6)) 0.0) "Think Time:" (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p1-time-ent* (list (+ ux-l (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 3.6)) 0.0) "0.00s" (* *gmk-cell* 0.3) 8) (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 4.1)) 0.0) "Total Time:" (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p1-tot-ent* (list (+ ux-l (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 4.1)) 0.0) "0.00s" (* *gmk-cell* 0.3) 8) (gmk:draw-line (list (+ ux-l (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 4.7)) 0.0) (list (- ux-r (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 4.7)) 0.0) 8) (setq *gmk-ui-p2-icon-ent* (gmk:draw-solid-circle (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 5.5)) 0.0) *gmk-radius* *gmk-p2-color*)) (setq *gmk-ui-p2-name-ent* (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.8)) (- mdim (* *gmk-cell* 5.65)) 0.0) "Local AI" (* *gmk-cell* 0.4) *gmk-p2-color*)) (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 6.4)) 0.0) "Think Time:" (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p2-time-ent* (list (+ ux-l (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 6.4)) 0.0) "0.00s" (* *gmk-cell* 0.3) 8) (gmk:draw-text (list (+ ux-l (* *gmk-cell* 1.0)) (- mdim (* *gmk-cell* 6.9)) 0.0) "Total Time:" (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p2-tot-ent* (list (+ ux-l (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 6.9)) 0.0) "0.00s" (* *gmk-cell* 0.3) 8) (gmk:draw-line (list (+ ux-l (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 7.5)) 0.0) (list (- ux-r (* *gmk-cell* 0.4)) (- mdim (* *gmk-cell* 7.5)) 0.0) 8) (gmk:draw-text (list (+ ux-l (* *gmk-cell* 0.8)) (- mdim (* *gmk-cell* 8.2)) 0.0) "RECENT MOVES:" (* *gmk-cell* 0.35) 8) (setq *gmk-history* nil) (gmk:draw-line (list (+ ux-l (* *gmk-cell* 0.4)) (* *gmk-cell* 1.4) 0.0) (list (- ux-r (* *gmk-cell* 0.4)) (* *gmk-cell* 1.4) 0.0) 8) (gmk:draw-centered-text (list cx (* *gmk-cell* 0.8) 0.0) "Powered by CadCade.com" (* *gmk-cell* 0.2) 8) (gmk:draw-centered-text (list cx (* *gmk-cell* 0.3) 0.0) "Code by Vico" (* *gmk-cell* 0.2) 8) ) (defun gmk:format-move (x y) (strcat (chr (+ 65 x)) (itoa (1+ y)))) (defun gmk:add-history (p mstr / c pt i mdim ux-l) (setq *gmk-history* (cons (list p mstr) *gmk-history*)) (if (> (length *gmk-history*) 6) (setq *gmk-history* (reverse (cdr (reverse *gmk-history*)))) ) (setq mdim (* (1- *gmk-size*) *gmk-cell*) ux-l (+ mdim (* *gmk-cell* 2.5)) i 0) (foreach item *gmk-history* (setq c (if (= (car item) 1) *gmk-p1-color* *gmk-p2-color*) pt (list (+ ux-l (* *gmk-cell* 1.2)) (- mdim (* *gmk-cell* (+ 8.8 (* i 0.55)))) 0.0)) (gmk:update-dynamic-text (read (strcat "*gmk-ui-hist-" (itoa (1+ i)) "*")) pt (cadr item) (* *gmk-cell* 0.3) c) (setq i (1+ i)) ) ) (defun gmk:update-hover (x y / pt el) (if (and (>= x 0) (< x *gmk-size*) (>= y 0) (< y *gmk-size*) (zerop (gmk:get-cell x y))) (progn (setq pt (list (* x *gmk-cell*) (* y *gmk-cell*) 0.0)) (if (or (not *gmk-hover-ent*) (not (entget *gmk-hover-ent*))) (setq *gmk-hover-ent* (entmakex (list '(0 . "CIRCLE") (cons 8 *gmk-layer*) (cons 10 pt) (cons 40 *gmk-radius*) (cons 62 *gmk-p1-color*)))) (progn (setq el (entget *gmk-hover-ent*)) (entmod (subst (cons 10 pt) (assoc 10 el) el)) ) ) ) (gmk:clear-hover) ) ) (defun gmk:clear-hover () (if *gmk-hover-ent* (progn (vl-catch-all-apply 'entdel (list *gmk-hover-ent*)) (setq *gmk-hover-ent* nil) ) ) ) (defun gmk:cleanup () (gmk:clear-hover) (setq *gmk-entities* nil *gmk-hover-ent* nil *gmk-board* nil *gmk-ui-p1-time-ent* nil *gmk-ui-p1-tot-ent* nil *gmk-ui-p2-time-ent* nil *gmk-ui-p2-tot-ent* nil *gmk-ui-p1-icon-ent* nil *gmk-ui-p1-name-ent* nil *gmk-ui-p2-icon-ent* nil *gmk-ui-p2-name-ent* nil *gmk-ui-hist-1* nil *gmk-ui-hist-2* nil *gmk-ui-hist-3* nil *gmk-ui-hist-4* nil *gmk-ui-hist-5* nil *gmk-ui-hist-6* nil) ) ;;; --- DCL UI --- (defun gmk:show-lobby-dialog (/ fn f id res) (setq fn (vl-filename-mktemp "gmk_lobby.dcl") f (open fn "w")) (foreach str '( "gmk_lobby : dialog { label=\"CadCade.com Lobby\"; width=40;" " : spacer { height=0.5; }" " : text { label=\"Select Game Mode:\"; alignment=centered; font=\"bold\"; }" " : spacer { height=1; }" " : column { alignment=centered; fixed_width=true;" " : button { key=\"btn_match\"; label=\"Online Matchmaking\"; width=28; fixed_width=true; is_enabled=false; }" " : spacer { height=0.2; }" " : button { key=\"btn_watch\"; label=\"Spectate Mode\"; width=28; fixed_width=true; is_enabled=false; }" " : spacer { height=0.2; }" " : button { key=\"btn_local\"; label=\"Local PvE (vs AI)\"; width=28; fixed_width=true; is_default=true; }" " }" " : spacer { height=1; }" " : button { key=\"btn_quit\"; label=\"Exit Game\"; is_cancel=true; width=12; alignment=centered; }" "}") (write-line str f) ) (close f) (setq id (load_dialog fn)) (if (new_dialog "gmk_lobby" id) (progn (action_tile "btn_local" "(done_dialog 1)") (action_tile "btn_match" "(done_dialog 2)") (action_tile "btn_watch" "(done_dialog 3)") (action_tile "btn_quit" "(done_dialog 0)") (setq res (start_dialog)) ) (setq res 0) ) (unload_dialog id) (vl-file-delete fn) res ) (defun gmk:show-gameover-dialog (msg / fn f id res) (gmk:clear-hover) (setq fn (vl-filename-mktemp "gmk_go.dcl") f (open fn "w")) (foreach str (list "gmk_go : dialog { label=\"Match Complete\";" " : spacer { height=0.5; }" (strcat " : text { label=\"" msg "\"; alignment=centered; font=\"bold\"; }") " : spacer { height=1; }" " : row { alignment=centered; fixed_width=true;" " : button { key=\"btn_next\"; label=\"Play Again\"; is_default=true; width=16; fixed_width=true; }" " : button { key=\"btn_quit\"; label=\"End Match\"; is_cancel=true; width=16; fixed_width=true; }" " }" "}") (write-line str f) ) (close f) (setq id (load_dialog fn)) (if (new_dialog "gmk_go" id) (progn (action_tile "btn_next" "(done_dialog 1)") (action_tile "btn_quit" "(done_dialog 0)") (setq res (start_dialog)) ) ) (unload_dialog id) (vl-file-delete fn) res ) (defun gmk:show-cleanup-dialog (/ fn f id res) (gmk:clear-hover) (setq fn (vl-filename-mktemp "gmk_cl.dcl") f (open fn "w")) (foreach str '( "gmk_cl : dialog { label=\"Exit Game\";" " : spacer { height=0.5; }" " : text { label=\"Do you want to keep the board on the screen?\"; alignment=centered; }" " : text { label=\"(Kept entities will become standard CAD objects)\"; alignment=centered; color=8; }" " : spacer { height=1; }" " : row { alignment=centered; fixed_width=true;" " : button { key=\"btn_keep\"; label=\"Keep Board\"; is_default=true; width=14; fixed_width=true; }" " : button { key=\"btn_clean\"; label=\"Clean Up\"; is_cancel=true; width=14; fixed_width=true; }" " }" "}") (write-line str f) ) (close f) (setq id (load_dialog fn)) (if (new_dialog "gmk_cl" id) (progn (action_tile "btn_keep" "(done_dialog 1)") (action_tile "btn_clean" "(done_dialog 0)") (setq res (start_dialog)) ) ) (unload_dialog id) (vl-file-delete fn) res ) ;;; --- Core Math & AI --- (defun gmk:get-time-seconds () (* 86400.0 (getvar "DATE"))) (defun gmk:count-continuous (x y dx dy p / cnt blk cx cy px py) (setq cnt 0 blk 0 cx (+ x dx) cy (+ y dy) px x py y) (while (and (>= cx 0) (< cx *gmk-size*) (>= cy 0) (< cy *gmk-size*) (= (gmk:get-cell cx cy) p)) (setq px cx py cy cnt (1+ cnt) cx (+ cx dx) cy (+ cy dy)) ) (if (or (< cx 0) (>= cx *gmk-size*) (< cy 0) (>= cy *gmk-size*) (/= (gmk:get-cell cx cy) 0)) (setq blk 1) ) (list cnt blk px py) ) (defun gmk:check-win (x y p / dirs d r1 r2 tot win) (setq dirs '((1 0) (0 1) (1 1) (1 -1)) win nil) (foreach d dirs (setq r1 (gmk:count-continuous x y (car d) (cadr d) p) r2 (gmk:count-continuous x y (- (car d)) (- (cadr d)) p) tot (+ 1 (car r1) (car r2))) (if (>= tot 5) (setq win (list (nth 2 r2) (nth 3 r2) (nth 2 r1) (nth 3 r1))) ) ) win ) (defun gmk:eval-dir (x y dx dy p / r1 r2 cnt blk) (setq r1 (gmk:count-continuous x y dx dy p) r2 (gmk:count-continuous x y (- dx) (- dy) p) cnt (+ 1 (car r1) (car r2)) blk (+ (cadr r1) (cadr r2))) (cond ((>= cnt 5) 1000000) ; Win ((and (= cnt 4) (= blk 0)) 100000) ; Open 4 ((and (= cnt 4) (= blk 1)) 10000) ; Closed 4 ((and (= cnt 3) (= blk 0)) 5000) ; Open 3 ((and (= cnt 3) (= blk 1)) 50) ; Closed 3 ((and (= cnt 2) (= blk 0)) 100) ; Open 2 ((and (= cnt 2) (= blk 1)) 5) ; Closed 2 (t 1) ) ) (defun gmk:eval-point (x y p / dirs tot d) (setq dirs '((1 0) (0 1) (1 1) (1 -1)) tot 0) (foreach d dirs (setq tot (+ tot (gmk:eval-dir x y (car d) (cadr d) p))) ) tot ) (defun gmk:ai-move (/ bx by max-s x y s1 s2 cbias tot) (setq max-s -1 bx 7 by 7 x 0) (while (< x *gmk-size*) (setq y 0) (while (< y *gmk-size*) (if (zerop (gmk:get-cell x y)) (progn (setq s1 (gmk:eval-point x y 1) s2 (gmk:eval-point x y 2) ;; Center bias using inverse Manhattan distance to (7,7). Max value ~14, Min 0. cbias (- 14.0 (+ (abs (- x 7)) (abs (- y 7)))) tot (+ s2 (* s1 1.2) (* cbias 0.5))) (if (> tot max-s) (setq max-s tot bx x by y)) ) ) (setq y (1+ y)) ) (setq x (1+ x)) ) (list bx by) ) ;;; --- Main App Loop --- (defun c:GOMOKU (/ *error* o-cmd o-osm run md pa gr pt spt cx cy am win r st dt uxl mdim ccode) (defun *error* (msg) (gmk:purge-board) (gmk:cleanup) (if o-cmd (setvar "CMDECHO" o-cmd)) (if o-osm (setvar "OSMODE" o-osm)) (if (not (wcmatch (strcase msg) "*QUIT*,*CANCEL*,*BREAK*")) (princ (strcat "\n[Gomoku] Error: " msg)) (princ "\n[Gomoku] Match aborted by user.") ) (princ) ) (setq o-cmd (getvar "CMDECHO") o-osm (getvar "OSMODE")) (setvar "CMDECHO" 0) (setvar "OSMODE" 32) (setq mdim (* (1- *gmk-size*) *gmk-cell*) uxl (+ mdim (* *gmk-cell* 2.5)) run T) (while run (setq md (gmk:show-lobby-dialog)) (cond ((= md 0) (setq run nil)) ((= md 1) (setq pa T) (while pa (princ "\n[Gomoku] Initializing Sandbox Board...") (gmk:ensure-layer) (gmk:purge-board) (gmk:cleanup) (setq *gmk-board* '()) (repeat (* *gmk-size* *gmk-size*) (setq *gmk-board* (cons 0 *gmk-board*))) (setq *gmk-p1-total* 0.0 *gmk-p2-total* 0.0) (gmk:draw-board) (command "_.ZOOM" "_W" (list (* -2 *gmk-cell*) (* -2 *gmk-cell*)) (list (+ uxl (* *gmk-cell* 9.5)) (+ mdim (* *gmk-cell* 2.0)))) (princ "\n[Gomoku] Game Start! You are Red. Click to place your piece. Press ESC or Right-Click to exit.") (setq *gmk-active* T st (gmk:get-time-seconds)) (gmk:set-turn 1) (while *gmk-active* (setq gr (grread T 15 0) ccode (car gr) pt (cadr gr)) (cond ;; Hover ((= ccode 5) (if (setq spt (osnap pt "_int")) (setq pt spt)) (setq cx (fix (+ (/ (car pt) *gmk-cell*) 0.5)) cy (fix (+ (/ (cadr pt) *gmk-cell*) 0.5))) (gmk:update-hover cx cy) (setq dt (- (gmk:get-time-seconds) st)) (gmk:update-dynamic-text '*gmk-ui-p1-time-ent* (list (+ uxl (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 3.6)) 0.0) (strcat (rtos dt 2 2) "s") (* *gmk-cell* 0.3) 8) ) ;; Click ((= ccode 3) (if (setq spt (osnap pt "_int")) (setq pt spt)) (setq cx (fix (+ (/ (car pt) *gmk-cell*) 0.5)) cy (fix (+ (/ (cadr pt) *gmk-cell*) 0.5))) (if (and (>= cx 0) (< cx *gmk-size*) (>= cy 0) (< cy *gmk-size*) (zerop (gmk:get-cell cx cy))) (progn (setq dt (- (gmk:get-time-seconds) st) *gmk-p1-total* (+ *gmk-p1-total* dt)) (gmk:update-dynamic-text '*gmk-ui-p1-time-ent* (list (+ uxl (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 3.6)) 0.0) (strcat (rtos dt 2 2) "s") (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p1-tot-ent* (list (+ uxl (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 4.1)) 0.0) (strcat (rtos *gmk-p1-total* 2 2) "s") (* *gmk-cell* 0.3) 8) (gmk:set-cell cx cy 1) (gmk:draw-solid-circle (list (* cx *gmk-cell*) (* cy *gmk-cell*)) *gmk-radius* *gmk-p1-color*) (gmk:clear-hover) (gmk:add-history 1 (strcat "Red: " (gmk:format-move cx cy))) (if (setq win (gmk:check-win cx cy 1)) (progn (gmk:add-history 1 "Red: MATCH WIN!") (gmk:draw-thick-line (list (* (car win) *gmk-cell*) (* (cadr win) *gmk-cell*)) (list (* (nth 2 win) *gmk-cell*) (* (nth 3 win) *gmk-cell*)) *gmk-win-color* (* *gmk-cell* 0.4)) (redraw) (setq r (gmk:show-gameover-dialog "Victory! You defeated the Local AI.") *gmk-active* nil pa (= r 1)) ) (if (not (member 0 *gmk-board*)) (progn (gmk:add-history 1 "SYS: DRAW MATCH") (redraw) (setq r (gmk:show-gameover-dialog "Stalemate! The board is full.") *gmk-active* nil pa (= r 1)) ) (progn (gmk:set-turn 2) (princ "\n[Gomoku] AI is thinking...") (setq st (gmk:get-time-seconds) am (gmk:ai-move) dt (- (gmk:get-time-seconds) st) *gmk-p2-total* (+ *gmk-p2-total* dt)) (gmk:update-dynamic-text '*gmk-ui-p2-time-ent* (list (+ uxl (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 6.4)) 0.0) (strcat (rtos dt 2 3) "s") (* *gmk-cell* 0.3) 8) (gmk:update-dynamic-text '*gmk-ui-p2-tot-ent* (list (+ uxl (* *gmk-cell* 4.1)) (- mdim (* *gmk-cell* 6.9)) 0.0) (strcat (rtos *gmk-p2-total* 2 2) "s") (* *gmk-cell* 0.3) 8) (gmk:set-cell (car am) (cadr am) 2) (gmk:draw-solid-circle (list (* (car am) *gmk-cell*) (* (cadr am) *gmk-cell*)) *gmk-radius* *gmk-p2-color*) (gmk:add-history 2 (strcat "Blue: " (gmk:format-move (car am) (cadr am)))) (if (setq win (gmk:check-win (car am) (cadr am) 2)) (progn (gmk:add-history 2 "Blue: MATCH WIN!") (gmk:draw-thick-line (list (* (car win) *gmk-cell*) (* (cadr win) *gmk-cell*)) (list (* (nth 2 win) *gmk-cell*) (* (nth 3 win) *gmk-cell*)) *gmk-win-color* (* *gmk-cell* 0.4)) (redraw) (setq r (gmk:show-gameover-dialog "Defeat! The Local AI claims victory.") *gmk-active* nil pa (= r 1)) ) (if (not (member 0 *gmk-board*)) (progn (gmk:add-history 2 "SYS: DRAW MATCH") (redraw) (setq r (gmk:show-gameover-dialog "Stalemate! The board is full.") *gmk-active* nil pa (= r 1)) ) (progn (gmk:set-turn 1) (setq st (gmk:get-time-seconds)) (princ "\n[Gomoku] Your turn.") ) ) ) ) ) ) ) ) ) ;; Exit (Right Click or Enter/Space) ((member ccode '(11 2 25)) (gmk:clear-hover) (setq *gmk-active* nil pa nil) ) ;; Catch-all for robust input handling (e.g. middle mouse pan) (t nil) ) ) ) ) ) ) (princ "\n[Gomoku] Game session ended.") (setq r (gmk:show-cleanup-dialog)) (if (= r 1) (progn (princ " Board entities kept as standard CAD objects.") (gmk:cleanup)) (progn (princ " Cleaning up board...") (gmk:purge-board) (gmk:cleanup)) ) (setvar "CMDECHO" o-cmd) (setvar "OSMODE" o-osm) (princ "\n[Gomoku] Type GOMOKU to enter Lobby.") (princ) ) (princ "\n[CadCade] Gomoku Engine (Local PvE Edition) v0.3 loaded. Type GOMOKU to play.") (princ)
    2 points
  9. I think your overlooking the AUTOLOAD function, yes in my Autoload.lsp loads on startup there are 37 defuns, most are very small like DTR, RTD, then there are 38 Autoload's the way Autoload works is you type a command and a lisp program is loaded, so you limit how many lisps are loaded on startup, In the pop there is (load "myprogram") "nowrunit" so again only loaded when you need the program. (autoload "COPY0" '("COPY0")) (autoload "COPYCOMMAND" '("ZZZ")) (autoload "COVER" '("COVER"))
    2 points
  10. Whatever store there is on the internet will suffer similarly from Al generated code, a store where code is uploaded quickly will just become very large, lose its value when there are too many resources to choose all doing something very similar. I think I prefer the forum format (probably always will do), that in creating an answer to the problems asked there is some peer review going on, explanation as what does what and the ability to ask for explanations or how to modify a code supplied to a more unique solution - which is all in itself a great learnign tool
    2 points
  11. @indiancad @Javier Longa there may be a way of using Array if a new UCS OB is used to orient the grid. In the changed rotation need to rotate the block as well. A question @Javier Longa " since I have no programming knowledge whatsoever" then how did you come by the code ? It is considered good manners to acknowledge who wrote the code, if known, or mention Author unknown.
    2 points
  12. There is also PyInstaller to create an executable. PyInstaller Manual — PyInstaller 6.21.0 documentation pip install -U pyinstaller pyinstaller your_program.py
    2 points
  13. The Ax Space. Ax is the wrapper for ActiveX as described here https://help.autodesk.com/view/OARX/2025/ENU/?guid=GUID-A809CD71-4655-44E2-B674-1FE200B9FE30 It’s going to look familiar if you’ve done any VBA or Visual Lisp. The big difference is that all Points, Vectors, Matrices, use AcGe classes instead of variants. from pyrx import Ap, Ax, Db, Ed, Ge, Rx @Ap.Command() def doitx1(): # get the application, document, and modelspace using ActiveX automation axApp = Ap.Application.acadApplication() axDoc = axApp.activeDocument() axModel = axDoc.modelSpace() # add a lines to modelspace, then access it properties # use Ge.Point3d class instead of a variant axLine1 = axModel.addLine(Ge.Point3d(0, 0, 0), Ge.Point3d(100, 100, 0)) axLine2 = axModel.addLine(Ge.Point3d(0, 100, 0), Ge.Point3d(100, 0, 0)) interdata = axLine1.intersectWith(axLine2, Ax.AcExtendOption.acExtendNone) if len(interdata) == 0: print("\nDoes not intersect:") return axCircle = axModel.addCircle(interdata[0], 10) axCircle.setColor(Ax.AcColor.acCyan) #scale and rotate xform = Ge.Matrix3d.scaling(2,axCircle.center()) xform *= Ge.Matrix3d.rotation(0.7854, Ge.Vector3d.kZAxis, axCircle.center()) axLine1.transformBy(xform) axLine2.transformBy(xform)
    2 points
  14. Casting objects. Every database object has a static cast method, it is your responsibility to check the type from pyrx import Ap, Ax, Db, Ed, Ge, Rx import traceback @Ap.Command() def doitx3(): try: # Get ActiveX application instance axApp = Ap.Application.acadApplication() axDoc = axApp.activeDocument() axUtil = axDoc.utility() # Prompt user to pick an entity axEnt, pnt = axUtil.getEntity("\nPick a line") # Verify that the picked entity is a LINE if axEnt.objectName() != "AcDbLine": raise RuntimeError("oops!: ") # Cast to AcadLine axLine = Ax.AcadLine.cast(axEnt) # change color to green (RGB: 0, 255, 0) axLine.setTrueColor(Ax.AcadAcCmColor(0, 255, 0)) # Print information about the selected entity print(axEnt.objectName(), pnt) except Exception as err: traceback.print_exception(err)
    2 points
  15. here's an example of creating a table and selecting a sub region from pyrx import Ap, Ax, Db, Ed, Ge, Rx import traceback @Ap.Command() def doitx2(): try: axApp = Ap.Application.acadApplication() axDoc = axApp.activeDocument() axModel = axDoc.modelSpace() ps , point = Ed.Editor.getPoint("\nPick table location: ") if ps != Ed.PromptStatus.eOk: raise RuntimeError("oof {}:".format(ps)) # Creates a table with 7 rows and 5 columns axTable = axModel.addTable(point, 7, 5, 1, 5) #fill up the table for col in range(axTable.columns()): for row in range(2, axTable.rows()): axTable.setText(row, col, "{},{}".format(row, col)) #get the cell extents, is a list of 3d points cex11 = axTable.cellExtents(1, 1, False) cex43 = axTable.cellExtents(4, 3, False) # Create a selection region using ActiveX selection methods sssub = axTable.selectSubRegion( cex11[0], cex43[3], Ge.Vector3d.kZAxis, Ge.Vector3d.kXAxis, Ax.AcSelectType.acTableSelectCrossing, False, ) # Apply the selection to the table using ActiveX selection methods axTable.setSubSelection(*sssub) # Perform hit testing and geometric calculations using ActiveX services # Ge space makes it easier to do math pnt = cex11[0] + (cex43[3] - cex11[0]) * 0.5 bhit, row, col = axTable.hitTest(pnt, Ge.Vector3d.kZAxis) if(bhit): # Modify cell properties using ActiveX methods axTable.setCellTextHeight(row, col, 0.8) axTable.setText(row, col, "Bingo") # since were open source we can add stuff like suppost html colors axTable.setCellBackgroundColor(row, col, Ax.AcadAcCmColor("#228B22")) except Exception: print(traceback.format_exc())
    2 points
  16. Start here https://github.com/CEXT-Dan/PyRx#python-for-autocad 1, watch the short YouTube video and download Python 3.14 from the link provided 2, download in install VS Code, install python extension pack 3, try out some of the samples, https://github.com/CEXT-Dan/PyRx/tree/main/PySamples
    2 points
  17. There are some items in the database, where the only option is to use entGet, I.e. ACAD_FIELDLIST is not exposed to ARX See: https://www.cadtutor.net/forum/topic/99220-python-change-precision-of-all-fields-in-a-drawing/
    2 points
  18. And top it off with entMake from pyrx import Ap, Db, Ed, Ge @Ap.Command() def doit5() -> None: Db.Core.entMake([(0 , "LINE"),(10, Ge.Point3d(0, 0, 0)),(11, Ge.Point3d(100, 100, 0))])
    2 points
  19. This might be better example, maybe similar to the COND expression? from pyrx import Ap, Db, Ed, Ge @Ap.Command() def doit4() -> None: ps, id, _ = Ed.Editor.entSel("\nPick it: ", Db.Line.desc()) if ps != Ed.PromptStatus.eOk: raise RuntimeError("oof {}:".format(ps)) #get the result buffer rb = Db.Core.entGet(id) # Process the result buffer using structural pattern matching updated_rb = [] for item in rb: match item: case (10, _): updated_rb.append((10, Ge.Point3d(0, 0, 0))) case (11, _): updated_rb.append((11, Ge.Point3d(100, 100, 0))) case _: updated_rb.append(item) # Apply changes back to the AutoCAD database Db.Core.entMod(updated_rb)
    2 points
  20. In Python, tuples are immutable, so if we want to modify the list, you have to replace it. In this sample we modify the start and end of a line from pyrx import Ap, Db, Ed, Ge @Ap.Command() def doit3() -> None: #entsel with a filter ps, id, _ = Ed.Editor.entSel("\nPick it: ", Db.Line.desc()) if ps != Ed.PromptStatus.eOk: raise RuntimeError("oof {}:".format(ps)) #get the result buffer rb = Db.Core.entGet(id) # Loop through the result buffer list and modify matching DXF codes for i, item in enumerate(rb): dxf_code = item[0] if dxf_code == 10: rb[i] = (10, Ge.Point3d(0, 0, 0)) elif dxf_code == 11: rb[i] = (11, Ge.Point3d(100, 100, 0)) # Apply changes back to the AutoCAD database Db.Core.entMod(rb)
    2 points
  21. In Python, there isn’t an assoc function, we can iterate through and search for a DXF code from pyrx import Ap, Db, Ed, Ge @Ap.Command() def doit1() -> None: # entsel with a filter ps, id, _ = Ed.Editor.entSel("\nPick it: ", Db.Line.desc()) if ps != Ed.PromptStatus.eOk: raise RuntimeError("oof {}:".format(ps)) # get the result buffer rb = Db.Core.entGet(id) # 1. Analog to Lisp: (assoc 8 rb) -> Returns the full pair (8, "LayerName") dxf_code, value = next((item for item in rb if item[0] == 8), None) # 2. Extract just the value safely if dxf_code: print(f"The layer is: {value}")
    2 points
  22. those are attribute references of a block. Since vla-fieldcode only works on Text and mtext i used Lee Macs fieldcode instead https://www.lee-mac.com/fieldcode.html It should work on Blocks Attributereferences as well now. (defun c:change_prec (/ *error* acdoc undo-mark ss target index ename obj att field-string revised-string) (defun *error* (msg) (if undo-mark (progn (vl-catch-all-apply 'vla-EndUndoMark (list acdoc)) (setq undo-mark nil) ) ) (if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")) ) (princ (strcat "\nError: " msg)) ) (princ) ) (setq acdoc (vla-get-ActiveDocument (vlax-get-acad-object))) (prompt "\nSelect text, MText, or attributed blocks: ") (while (null (setq ss (ssget '((0 . "TEXT,MTEXT,INSERT"))))) (prompt "\nNo valid text, MText, or blocks selected.") ) (initget 1 "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Current") (setq target (getkword "\nTarget precision [0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/Current]: ")) (vla-StartUndoMark acdoc) (setq undo-mark T) (repeat (setq index (sslength ss)) (setq index (1- index) ename (ssname ss index) obj (vlax-ename->vla-object ename) ) (cond ;; Text or MText ((wcmatch (vla-get-ObjectName obj) "AcDbText,AcDbMText") (setq field-string (vla-FieldCode obj)) (if (and field-string (setq revised-string (replacePrecision field-string target)) ) (vla-put-TextString obj revised-string) ) ) ;; Block reference with editable attributes ((vlax-method-applicable-p obj 'GetAttributes) (foreach att (vlax-invoke obj 'GetAttributes) (setq field-string (LM:fieldcode (vlax-vla-object->ename att))) (if (and field-string (setq revised-string (replacePrecision field-string target)) ) (vla-put-TextString att revised-string) ) ) ) ) ) (vla-EndUndoMark acdoc) (setq undo-mark nil) (vla-Regen acdoc acActiveViewport) (princ) ) (defun replacePrecision (fieldStr target / nbs prec_source return) (setq nbs 0) (cond ((vl-string-search "%<\\" fieldStr nbs) (while nbs (if (setq nbs (vl-string-search "%pr" fieldStr (setq tmp_nbs nbs))) (setq prec_source (itoa (atoi (substr fieldStr (+ nbs 4) 2))) fieldStr (vl-string-subst (if (eq target "Current") (strcat "%pr" (itoa (getvar "LUPREC"))) (strcat "%pr" target) ) (strcat "%pr" prec_source) fieldStr tmp_nbs ) nbs (1+ nbs) ) ) ) (setq return fieldStr) ) ) return ) ;; Field Code - Lee Mac ;; Returns the field expression associated with an entity (defun LM:fieldcode ( ent / replacefield replaceobject fieldstring enx ) (defun replacefield ( str enx / ent fld pos ) (if (setq pos (vl-string-search "\\_FldIdx" (setq str (replaceobject str enx)))) (progn (setq ent (assoc 360 enx) fld (entget (cdr ent)) ) (strcat (substr str 1 pos) (replacefield (fieldstring fld) fld) (replacefield (substr str (1+ (vl-string-search ">%" str pos))) (cdr (member ent enx))) ) ) str ) ) (defun replaceobject ( str enx / ent pos ) (if (setq pos (vl-string-search "ObjIdx" str)) (strcat (substr str 1 (+ pos 5)) " " (LM:ObjectID (vlax-ename->vla-object (cdr (setq ent (assoc 331 enx))))) (replaceobject (substr str (1+ (vl-string-search ">%" str pos))) (cdr (member ent enx))) ) str ) ) (defun fieldstring ( enx / itm ) (if (setq itm (assoc 3 enx)) (strcat (cdr itm) (fieldstring (cdr (member itm enx)))) (cond ((cdr (assoc 2 enx))) ("")) ) ) (if (and (wcmatch (cdr (assoc 0 (setq enx (entget ent)))) "TEXT,MTEXT,ATTRIB,MULTILEADER,*DIMENSION") (setq enx (cdr (assoc 360 enx))) (setq enx (dictsearch enx "ACAD_FIELD")) (setq enx (dictsearch (cdr (assoc -1 enx)) "TEXT")) ) (replacefield (fieldstring enx) enx) ) ) ;; ObjectID - Lee Mac ;; Returns a string containing the ObjectID of a supplied VLA-Object ;; Compatible with 32-bit & 64-bit systems (defun LM:ObjectID ( obj ) (eval (list 'defun 'LM:ObjectID '( obj ) (if (and (vl-string-search "64" (getenv "PROCESSOR_ARCHITECTURE")) (vlax-method-applicable-p (vla-get-utility (LM:acdoc)) 'getobjectidstring) ) (list 'vla-getobjectidstring (vla-get-utility (LM:acdoc)) 'obj ':vlax-false) '(itoa (vla-get-objectid obj)) ) ) ) (LM:ObjectID obj) ) ;; Active Document - Lee Mac ;; Returns the VLA Active Document Object (defun LM:acdoc nil (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object)))) (LM:acdoc) )
    2 points
  23. Here is another for allowing explode... Solved: Re: Allow exploding outside the block editor - Autodesk Community Are these drawings from AutoCAD Civil 3D or some other CAD? (defun c:AllBlkYHtchN (/ ss i ent) (vl-load-com) ;;-------------------------------------------------- ;; Set Allow Exploding = Yes for all block definitions ;;-------------------------------------------------- (vlax-map-collection (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object))) '(lambda (blk) (if (vlax-property-available-p blk 'Explodable) (vlax-put-property blk 'Explodable :vlax-true) ) ) ) ;;-------------------------------------------------- ;; Set all hatches Annotative = No ;;-------------------------------------------------- (if (setq ss (ssget "_X" '((0 . "HATCH")))) (progn (setq i 0) (repeat (sslength ss) (setq ent (ssname ss i)) (vl-catch-all-apply '(lambda () (setpropertyvalue ent "Annotative" 0) ) ) (setq i (1+ i)) ) ) ) (princ (strcat "\nUpdated " (itoa (if ss (sslength ss) 0)) " hatch(es). All explodable block definitions enabled." ) ) (princ) ) Do you need nested hatches and blocks, dynamic and/or anonymous blocks?
    2 points
  24. Just a comment in Bricscad V25 the setpropertyvalue does not work, the get does work. One of those odd bugs
    2 points
  25. So did you ever figure out how to do it, OP? I don't know how someone doesn't manually save like every 5 min. I can tell now that this is not a natural reaction for everyone. I am a millennial and it's been metaphorically beaten in my head throughout my all school years to save often. I save after every small bit of changes that I make. Hope you found a way that works for you, though!!
    2 points
  26. I posted this at the swamp, this is pretty cool Proof of concept (V25, V26, V27Beta) - appload BrxBlockManXX.brx - type blockman at the prompt - select a drawing from the directory control - double click or drag a block from the List control to the current drawing - double click the main preview to insert the whole drawing - click the open folder button to add your favorite folder(s) - use the dropdown to navigate to a favorite folder - right click on a dwg to open it let me know if it crashes lol edit, posted the source and binaries here https://github.com/CEXT-Dan/BrxBlockMan
    1 point
  27. You have to make two Field, once for Distance of Block, then Once for Arrray Object (item or column * row). Cause an Array Object now is include all block, all Field of length in per Array is fixed
    1 point
  28. from pyrx import Ap, Ax, Db, Ed, Ge, Br def getAllFieldsIds(db: Db.Database): ids: list[Db.ObjectId] = [] nod = Db.Dictionary(db.namedObjectsDictionaryId()) fieldListId = nod.getAt("ACAD_FIELDLIST") fieldList = Db.Core.entGet(fieldListId) for fieldItem in fieldList: if fieldItem[0] == 330 and fieldItem[1].isDerivedFrom(Db.Field.desc()): ids.append(fieldItem[1]) return set(ids) @Ap.Command() def doit() -> None: db = Db.curDb() field_ids = getAllFieldsIds(db) for id in field_ids: field = Db.Field(id, Db.OpenMode.kForRead) fmt = field.getFormat() if 'pr3' in fmt: field.upgradeOpen() new_fmt = fmt.replace('pr3', 'pr4') field.setFormat(new_fmt) field.evaluate(Db.FieldEvalContext.kDemand, db) print(f"Updated field format from {fmt} to {new_fmt}")
    1 point
  29. @CamDuy gave it a try it appears to only look for a text object the OP wants an attribute in a block also to be updated.
    1 point
  30. Agreed. I am 100% on the side of [turn Autosave OFF] and use one of the many ways to save your data file every time you do something you don't want to lose.
    1 point
  31. 1 point
  32. That is cool! But didn't AutoCAD 2027 released something tiny bit similar (project workspace?)
    1 point
  33. CopyRenameBlockV1-5_byCamDuy.lsp Try using this file. @Nikon
    1 point
  34. Nice Lisp VicoWang! This looks like a great solution to the dreaded startup suite, some suggestions; Is it possible to have the "Asset Name" be the file name by default? Could the "Version" field default to 0?
    1 point
  35. We use Civil 3D, so we have more tools. Typically we get a batch of points in state plane coordinates. That means you can draw a line anywhere along the Y axis of those coordinates and get a fairly accurate North. It's not totally accurate because, obviously, that same vertical line is parallel at the ends of your state, which can be hundreds of miles apart. That's what a datum is for, I guess, to reconcile the grid with the surface of the Earth. This seems like a simple problem, but it's a nightmare if you don't have enough data. What I'll typically do is get a screen grab from an aerial map, making sure it's oriented to North, at a known scale, with a graphic scale included. Add that image to the drawing as an Xref at rotation 0. Scale it so that the graphic scale is correct. Then the fun part: find locations that match your drawing and line them up. Then the nightmare part: keep in mind that aerial images aren't always taken from directly above that area, so there's going to be some skew--and you have no way of knowing what that skew factor is. Sometimes you have to decide which points are more important to get right and let the rest be off. There's a command named ALIGN, which is very handy here: pick two or three points from the image and the corresponding points from the drawing; decide whether to scale the image; and watch the magic. With a drone you could get an image from a known spot, but not everyone has access to a drone. Other strategies: look for benchmarks in your drawing. In the US there's a system of markers placed by the Geodetic Survey. Surveyors often begin their locating from a benchmark, geodetic or otherwise. What you're trying to do is find three points that will define a plane. The other strategy only works if you know some property corners or can locate them: get a plat (not a deed, those cost money) for a piece of property. It will include bearings and distances for each border line. That gives you distance and direction between your property corners, so you can define your plane. Of course all these strategies depend on the drawing being in World UCS. You sometimes find a Plan North, and you can create a UCS to match that. Orienting the drawing to some other UCS will lead to problems down the line, I've been there.
    1 point
  36. Did not look to hard but an obvious one for me was. (setq road-text-layer "Road-Labels") ; The layer where the text numbers will go If layer "Road=labels" does not exist then program will crash, IF does not exist so just "Make" the layer. In lots of code I am writing I will take advantage of a global defun that is in another preloaded lisp, it has a checklayer function. This something like all you would need. (chklayer "Road-Label" 1 "Continous") (setq road-text-layer "Road-Labels") Agree with other post label at mid point, Using vertices can get be returned form a pline that is drawn in wrong direction than you think. Yours (setq current-dist-start (vlax-curve-getDistAtPoint road-entity start-pt)) I have a swap or flip a pline so start direction is from end selected. But using mid solves this. May not need this function if using mid. There is VL get coordinates that returns all the vertice XYZ. (defun helper-find-and-sort-intersections (setq lst (vlax-safearray->list (vlax-variant-value (vla-get-coordinates obj)))) Also this for pline vertice points, thanks to lee--mac. (setq plent (entsel "\nPick rectang")) (if plent (setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (car plent)))))) (princ co-ord) Just another idea when doing add more items to an existing drawing, do a "does the labels exist already" ? If so then get them all and find last label then add one to it. You have a layer name so can ssget MTEXT for that layer. Just me I don't tend to do this, make a list of entities, then process that list. It's a personal preference (while (setq entity (ssname road-ss i)) (setq global:all-roads (cons entity global:all-roads)) (setq i (1+ i)) ) I just act on the current entity returned by the while or a Repeat and do the labelling of that entity. This is sort of double handling the SSGET if you use Pick PIck Pick method the selection set should be in the pick order (setq first-road (car (entsel "\nSelect the FIRST road (from your selection): "))) Otherwise use a Pick and label method it will be fast. The label will appear as fast as you pick. Maybe even a dual method pick and window. Having a bit of a look I think code can be shortened a lot.
    1 point
  37. @VicoWang I don't do anything with the cloud but I know some of my clients are going that way for various reasons, in the very simple way the Install.lsp works there is no reason why the programs etc can not be loaded to the cloud. You only need correct support paths hopefully set, I don't use the cloud. One other thing is we had laptops where I worked, so when outside in the field the user would select the correct icon on the desktop, we had two icons "In office" and "Out of office" then the correct profile was loaded. The "out of office" would look on the laptop for programs etc, Yes had a slightly different set of menu's. The profile choice is in the ICON properties.
    1 point
  38. Hello. May I make a suggestion? Perhaps you could simplify the user prompts from this: (setq first-road (car (entsel "\nSelect the FIRST road (from your selection): "))) (setq start-point (getpoint "\nClick near the START point of the first road: ")) to a single prompt: (setq first-road (car (setq es (entsel "\nSelect the FIRST road near the START point (from your selection): "))) start-point (cadr es) ) Also, your code calculates the midpoint based on the number of vertices rather than on the actual distance along the road. You might prefer to place the label at the geometric midpoint by replacing this: (setq mid-param (/ (vlax-curve-getEndParam road-entity) 2.0)) with this: (setq total-dist (vlax-curve-getDistAtParam road-entity (vlax-curve-getEndParam road-entity)) mid-param (vlax-curve-getParamAtDist road-entity (/ total-dist 2.0)) )
    1 point
  39. Type VC to start. Read it on the command line when loading .VLX.
    1 point
  40. Watching this whole "AI taking over" debate unfold, I feel like I'm seeing people in our industry fall into three different camps: First, there’s the Spectator. They use AI to generate flashy concept art or write basic emails. It’s pure consumption—cool to look at, but they don't really know how the engine works. Then you have the Skeptical Co-Pilot. This is where I sit for my daily development. You let AI do the heavy lifting for specific, tedious tasks, but you absolutely do not trust it blindly. You sandbox its output and rigorously test it before ever putting it into your actual workflow. Finally, there’s the Blind Believer. This is the whole "AI Agent" crowd trying to run a one-man firm. They type a prompt and expect a flawless final product the next morning. The reality? You have no idea what kind of spaghetti code or geometric garbage is hidden inside that black box, and auditing it takes longer than just doing the work yourself. Speaking of that "skeptical co-pilot" approach, I actually went down a massive rabbit hole with it recently. I was trying to solve a very pragmatic problem: How do we get an LLM to generate hyper-precise CAD geometry without eating up a million tokens and spitting out hallucinated garbage? Natural language just doesn't cut it for drafting. So, I worked with an AI to invent a prototype "Universal Morphological Matrix" (I just call it V-Code). The idea was to strip away all the human linguistic fluff and reduce CAD commands down to an absolute, 256-token hex-based root system. It basically compresses professional CAD knowledge into a tiny "Cosmic Language", which a local interpreter can then unpack back into precise AutoCAD/LISP commands. I pushed the experiment so far that I jokingly asked the AI to use this highly compressed logic to solve the P vs NP math problem. It confidently spit out a bunch of hex codes and claimed it had solved it. Did I believe it? Absolutely not, because I couldn't read its alien derivation track at all, haha! At the end of the day, AI is an incredibly powerful engine. But if you take your hands off the steering wheel and just blindly trust the machine, you're going to crash. It remains a tool exclusively for people who already know exactly what they are doing.
    1 point
  41. download: https://www.vedacad.com/ type code: A7CEHQ Drawing test MPL: https://drive.google.com/file/d/1WgMLRDxaiLchbshI3o_f3WHrV7rHX03e/view?usp=sharing AutoCAD: https://shrinkme.click/Multi_Plot_MPL BricsCAD: https://shrinkme.click/Multi_Plot_MPL_BricsCAD ZwCAD: https://shrinkme.click/Multi_Plot_MPL_ZwCAD
    1 point
  42. Yes need a much better realistic sample dwg with say a couple of different scenarios, array,non array and so on, even different lengths. There is a way of getting array info, you read the 1st object for properties, then the numbers in the row and column values.
    1 point
  43. Set bit 1 of the QAFLAGS system variable (storing the original value and resetting after the command); with bit 1 enabled, the EXPLODE command will accept selection sets when invoked from the LISP API. Alternatively, ensure that this bit is not set and only pass a single entity with no double quotes. The key point is that by controlling the bit, you can ensure consistent behaviour.
    1 point
  44. a little story : This is the famous Myth of Thamus and Theuth, found in the dialogue Phaedrus by the Greek philosopher Plato (written around 370 BCE). In this text, Plato has his teacher Socrates relate an ancient Egyptian anecdote. Here is how the story unfolds: The Invention The Egyptian god Theuth (Thoth), the deity of inventions, visits Thamus, the king (pharaoh) of Egypt. Theuth presents his various creations, including arithmetic, geometry, and astronomy. Finally, he introduces the written word. Theuth is enthusiastic and claims: "This invention will make the Egyptians wiser and improve their memories. It is a potion for both memory and wisdom!" The Pharaoh's Objection King Thamus is not impressed and responds with deep skepticism. He argues that writing will have the exact opposite effect: Memory loss: People will stop training their memories. By relying on external written characters, they will no longer internalize knowledge. The illusion of wisdom: People will read quantities of information without proper instruction. As a result, they will appear knowledgeable but will actually remain ignorant, becoming conceited and difficult to get along with. The Historical Irony Socrates used this story to argue that spoken dialogue is superior to the written word. He believed text is dead; it cannot answer back or clarify itself when misunderstood. The ultimate irony is that Socrates himself never wrote anything down. The only reason we know this story today is because his student, Plato, wrote it down. This ancient debate resurfaces with every technological leap. The same anxieties were voiced about the printing press, calculators, the internet, and now, Artificial Intelligence (AI).
    1 point
  45. This particular issue has been in play for a long time. Have you ever gone to a food joint, the power is out, and the staff refuse to prepare food for you because they can't ring it up? Like they've never heard of pencil and paper or making change. If you can't do the basic, human version of your job, you'll be left in the dark (sometimes literally) when the AI can't do its job. Worse, you won't recognize when the AI is making a mistake. Without a real-world backup, and the sense to use it, you're at the mercy of the AI and its hallucinations. It's the height of irresponsibility to replace us with something that needs its hand held all the time in case it has a malfunction.
    1 point
  46. AI has been around a long time, LLM since the 1990's, LISP was created for AI programming IIRC. It's a tool just like VLIDE, VS Code, etc. for programming. Problem, just like before, people came on to forums often demanding a code, etc. be written to make their life easier instead of learning something on their own to do it themselves. Most forums used to provide help and occasionally a custom code, etc. just like... That's a long list of requests. So now they demand AI to do their demands, those with some abilities have success, those that have great abilities have great success, etc. I know recently a man in Lee County, FL was arrested for a crime committed in or near Jacksonville, FL due to AI facial recognition, done by a third county's AI program, no second looks, no reasonable investigation, the man had never been to Jacksonville and a valid alibi for the time showing such. That's the bigger problem with AI right now, accepting the results without question. From the comments I see everywhere a great many seem tired of the AI everything.
    1 point
  47. I’m loving AI, it’s allowed me to do stuff that would take months to write in days. Example, this dark mode project to BricsCAD (https://github.com/CEXT-Dan/BrxDarkMenu) would have taken months to research.I had already done some win32 programming in the past, but very little. In short, you kind of have to know what you’re doing to use AI. I read about the Brown university thing where the professor made the students do their exams in class and most of the class failed. Scary! People need to at least learn foundational level stuff before using AI. What if the cloud is down, or you reach your token max, would you be able to go old school and continue? Or just sit there and twiddle your thumbs. With regards to anti-scraping, I see lots of open-source projects moving off GitHub to other places like Codeberg so their projects aren’t scraped, I guess so big companies that use AI don’t end up getting their code. I’m the opposite, I want AI to train on my code (if its open source)
    1 point
  48. Couple of comments to add: MHUPP mentioned anti-scraping, years ago I had a website and would layer the important images, put together they showed correctly but a left click, copy, paste, gave something like just the yellow and a transparent colour block - had to dig a little deeper to get the original image... so it is something that has happened kind of for years. If it is out there though I don't know if you can have a true anti-scraping system and have it visible to the humans CADTutor, for the future of AutoCAD, I am not concerned - though I am also including the others such as BricsCAD and so on - many of the issues on one system are common to the others and this forum will be relevant for a while yet (15 years please, till I retire...).
    1 point
  49. Have you tried using a multi-line? This looks like it is comprised of 3 lines (2-continuous either side of a width adjusted polyline). You could mimic this with the three lines, simply offsetting the centerline and changing the ltype to continuous and the width to 0.
    1 point
×
×
  • Create New...