Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/22/2026 in Posts

  1. Hi everyone, I'm Vico, an architectural designer with about 12 years in the industry. I'm based in China and have mostly been active in local developer forums, but I've always respected the open-source spirit here. I wanted to share a quick tool I wrote and also get your feedback on an idea. Codebase Packer — a LISP for AI-assisted work Over the past months I've been building a web-based side-project for CAD. The frontend work forced me to lean heavily on AI assistants (Claude, ChatGPT). The biggest bottleneck was always the context window: opening and pasting 30+ files manually drove me crazy. So I solved it with a little LISP routine. Codebase Packer lets you point at a folder and aggregate every file inside into a single .txt, ready for an LLM prompt. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; ;;; Command CPK (Codebase Packer) - Version 1.0 Release ;;; ;;; ;;; ;;; Features: ;;; ;;; Efficiently extracts the directory structure and file contents ;;; ;;; of a project. Features smart character encoding detection and ;;; ;;; automatically saves the packed file as UTF-8 alongside the ;;; ;;; project folder for AI-friendly integration. ;;; ;;; ;;; ;;; Author: Vico Wang ;;; ;;; Compatibility: AutoCAD 2006+ (Visual LISP / ActiveX) ;;; ;;; ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (vl-load-com) (defun cpk:getdate ( / cd ) (setq cd (rtos (getvar 'cdate) 2 6)) (strcat (substr cd 1 4) (substr cd 5 2) (substr cd 7 2)) ) (defun cpk:read ( fn / ext charset stm text err ) (setq ext (strcase (vl-filename-extension fn) t) charset (if (member ext '(".lsp" ".dcl" ".mnl" ".bat" ".ini")) "GBK" "UTF-8") text "" ) (if (setq stm (vlax-create-object "adodb.stream")) (progn (setq err (vl-catch-all-apply '(lambda () (vlax-put-property stm 'type 2) (vlax-put-property stm 'mode 3) (vlax-put-property stm 'charset charset) (vlax-invoke stm 'open) (vlax-invoke stm 'loadfromfile fn) (if (> (vlax-get-property stm 'size) 0) (setq text (vlax-invoke stm 'readtext -1)) ) ) ) ) (if (= 'vla-object (type stm)) (progn (vl-catch-all-apply '(lambda () (vlax-invoke stm 'close))) (vlax-release-object stm) ) ) (if (vl-catch-all-error-p err) (strcat "// Note: Error reading file - " (vl-catch-all-error-message err)) (if (= "" text) "// Note: File is empty or extraction failed" text) ) ) "// Note: ADODB.Stream component missing" ) ) (defun cpk:traverse ( fso dir prefix islast root / fobj subdirs files items i cnt name rel ) (if (setq fobj (vl-catch-all-apply 'vlax-invoke (list fso 'getfolder dir))) (if (not (vl-catch-all-error-p fobj)) (progn (if (/= (strcase dir) (strcase root)) (setq name (vlax-get fobj 'name) rel (vl-string-translate "\\" "/" (substr dir (+ 2 (strlen root)))) out-tree (cons (strcat prefix (if islast "©¸©¤©¤ " "©À©¤©¤ ") name "/ # " rel) out-tree) ) ) (setq items nil) (vlax-for x (vlax-get fobj 'subfolders) (setq items (cons (cons x t) items))) (vlax-for x (vlax-get fobj 'files) (setq items (cons (cons x nil) items))) (setq items (reverse items) cnt (length items) i 0 ) (setq prefix (if (= (strcase dir) (strcase root)) "" (strcat prefix (if islast " " "©¦ ")))) (foreach item items (setq i (1+ i) name (vlax-get (car item) 'name) ) (if (cdr item) (cpk:traverse fso (vlax-get (car item) 'path) prefix (= i cnt) root) (progn (setq rel (vl-string-translate "\\" "/" (substr (vlax-get (car item) 'path) (+ 2 (strlen root))))) (setq out-tree (cons (strcat prefix (if (= i cnt) "©¸©¤©¤ " "©À©¤©¤ ") name " # maps to /" rel) out-tree)) (setq out-files (cons (list (vlax-get (car item) 'path) name rel) out-files)) ) ) ) (vlax-release-object fobj) ) ) ) ) (defun c:cpk ( / *error* old-cmd out-tree out-files fso shl fld root-dir root-name lst fn rel sv-dir sv-path stm cnt err ) (defun *error* ( msg ) (foreach obj (list fso shl fld stm) (if (and obj (= 'vla-object (type obj)) (not (vlax-object-released-p obj))) (vl-catch-all-apply 'vlax-release-object (list obj)) ) ) (if old-cmd (setvar 'cmdecho old-cmd)) (if (and msg (not (wcmatch (strcase msg t) "*break*,*cancel*,*exit*"))) (princ (strcat "\nCPK Error: " msg)) ) (princ) ) (setq old-cmd (getvar 'cmdecho)) (setvar 'cmdecho 0) (princ "\nSelect root folder to pack...") (if (setq shl (vlax-create-object "shell.application")) (progn (if (setq fld (vlax-invoke shl 'browseforfolder 0 "Select project root folder (Codebase Packer)" 0 0)) (setq root-dir (vlax-get (vlax-get fld 'self) 'path)) ) (vlax-release-object shl) ) ) (if root-dir (progn (setq fso (vlax-create-object "scripting.filesystemobject") root-name (vlax-get (vlax-invoke fso 'getfolder root-dir) 'name) out-tree (list (strcat root-name "/ # [Root Directory] " root-dir) "") ) ;; Automatically uses out-tree and out-files via LISP dynamic scoping (cpk:traverse fso root-dir "" t root-dir) (setq lst (list "Part A: Overall Folder and File Structure\n")) (foreach x (reverse out-tree) (setq lst (cons (strcat x "\n") lst)) ) (setq lst (cons "\n\nPart B: Specific File Contents\n" lst) out-files (reverse out-files) cnt (length out-files) ) (foreach x out-files (setq fn (car x) rel (caddr x) ) (setq lst (cons (strcat "\n------------------------------------------------------------\n" "File location: " rel "\n" "File name: " (cadr x) "\n" "------------------------------------------------------------\n\n" (cpk:read fn) "\n") lst) ) ) (setq lst (reverse lst)) (setq sv-dir (vl-catch-all-apply 'vlax-invoke (list fso 'getparentfoldername root-dir))) (if (or (vl-catch-all-error-p sv-dir) (= "" sv-dir)) (setq sv-dir root-dir) ) (if (/= "\\" (substr sv-dir (strlen sv-dir))) (setq sv-dir (strcat sv-dir "\\")) ) (if (setq sv-path (getfiled "Save Packed File" (strcat sv-dir root-name "-Packed-" (cpk:getdate) ".txt") "txt" 1)) (if (setq stm (vlax-create-object "adodb.stream")) (progn (setq err (vl-catch-all-apply '(lambda () (vlax-put-property stm 'type 2) (vlax-put-property stm 'mode 3) (vlax-put-property stm 'charset "utf-8") (vlax-invoke stm 'open) (foreach x lst (vlax-invoke stm 'writetext x)) (vlax-invoke stm 'savetofile sv-path 2) (vlax-invoke stm 'close) ) ) ) (vlax-release-object stm) (if (vl-catch-all-error-p err) (alert "\nUnable to write file. Please check permissions or file path.") (alert (strcat "Processing complete!\n\nProcessed " (itoa cnt) " files.\nFile saved (UTF-8) to:\n" sv-path)) ) ) ) ) (vlax-release-object fso) ) ) (*error* nil) (princ) ) (princ "\nCodebase Packer (Version 1.0 Release, Author: Vico Wang) loaded. Type CPK to start.") (princ) The story behind this tool That web frontend I mentioned? It turned into VedaCAD — an experiment in modernising how we manage CAD environments. We're all still copying .arg profiles and fixing broken Support paths like it's 1999. I wanted something simpler: wrap your scripts and configs into 6-character ShareCodes, Then type the ID in the VC panel and pull it down to use it directly. There is a fully free tier (BASE mode works offline, FREE tier allows sync up to 3MB per file). For creators, I'm experimenting with some tools like push-updates and a tip-jar (0% commission), but honestly the platform is still young and I'm here mostly to listen. If you'd like to try the Codebase Packer without copy-pasting, you can install it into AutoCAD using ShareCode 0FBGZB (whatever that means for you — no pressure). I'd genuinely appreciate any thoughts, especially from the veterans. Is "environment sync" a real pain point for you? Am I solving a problem that's just mine? Cheers, Vico
    2 points
  2. One that’s free : ), Gemini, also GLM is pretty good a lisp. With AI, don’t try to one shot it, work though the ACIS/SAT patterns and ask questions
    2 points
  3. 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.
    2 points
  4. AI + AutoCAD, Python is the way, connect to agents in AutoCAD’s process space, I connect to LM studio
    1 point
  5. Paid tools are fine as well. I currently use a custom GPT called AutoCAD Automator. I usually design the overall algorithm myself. I use AI mainly to write supporting functions, research specific AutoCAD or ACIS/SAT topics in depth, compare alternative approaches, and help improve individual parts of the code. If you know a tool that would be more effective for this kind of workflow, I would be interested in trying it or switching to it.
    1 point
  6. Thank you. I am very happy to join this community that keeps pace with the times. It is my honor. I have seen your discussion about AI. As long as you put the master and the slave, not blind, they are just tools to make things better and faster.
    1 point
  7. @Danielm103 Thank you for the explanations and code examples. I will compare the suggested methods, decide which one is the most suitable, and start testing it. You mentioned that one of the code examples was generated with AI. Which AI tools do you use for writing or improving AutoLISP, Python, .NET, or ObjectARX code? Do you have any recommendations based on your experience?
    1 point
  8. Thank you. My concern is not damaging the original solid, but losing topology after exploding the copy. I need to identify each face, its boundary edges, edge lengths, and which faces share the same edge. Would exploding a copy preserve enough information to determine these relationships reliably?
    1 point
  9. Just revisiting this after a little revelation - Joe Burke's SUPERFLATTEN will do exactly what I need
    1 point
  10. something like this (AI generated) ;;; ========================================================================= ;;; AutoLISP ACIS/SAT Geometric Decoder Script - Print to Screen ;;; Decodes scrambled DXF groups 1 and 3 data and prints it to the command line ;;; ========================================================================= (defun c:DecodeSatPrint ( / ent enx dxfPair strBytes itm lin cha decodedStr) (vl-load-com) ;; 1. User prompts to select a valid 3D Solid or Region (setq ent (car (entsel "\nSelect 3D Solid or Region to decode: "))) (if ent (progn (setq enx (entget ent)) ;; Verify if the entity type actually holds ACIS data (if (member (cdr (assoc 0 enx)) '("3DSOLID" "REGION" "SURFACE" "BODY")) (progn (princ "\n--- START OF DECODED ACIS SAT DATA ---\n") ;; 2. Parse and Loop through DXF group codes 1 and 3 (while (setq dxfPair (car enx)) (if (member (car dxfPair) '(1 3)) (progn ;; Convert string to ASCII character byte-list and reverse it (setq strBytes (reverse (vl-string->list (cdr dxfPair))) itm nil lin nil) ;; Rebuild scrambled bytes using standard bitwise operators (while strBytes (setq cha (car strBytes) strBytes (cdr strBytes)) (cond ((= cha 95)) ;; Skip formatting delimiters ((= cha 86) (setq itm (cons 73 itm))) ((= cha 32) (setq lin (cons (if itm (vl-list->string itm) "") lin) itm nil)) ((boole 6 cha 95) (setq itm (cons (boole 6 cha 95) itm))) ) ) ;; Print structural line streams directly to the command line (setq decodedStr (vl-list->string itm)) (if (/= decodedStr "") (princ (strcat decodedStr "\n")) ) ) ) (setq enx (cdr enx)) ) (princ "--- END OF DECODED ACIS SAT DATA ---\n") (princ "\nTip: Press F2 to open the AutoCAD Text Window to copy the full log.") ) (princ "\nError: Selected entity does not contain ACIS geometry data.") ) ) ) (princ) ) (princ "\nACIS SAT Decoder (Print version) Loaded. Type 'DecodeSatPrint' to execute.") (princ) asmheader body lump transform shell face face loop plane-surface face loop plane-surface coedge face loop plane-surface coedge coedge coedge coedge edge I'd bet you could make AI make a mini brep for lisp
    1 point
  11. It’s possible with lisp, but really hard. When you entget a solid, you see the garbage at the end that looks like “{kn rn {rn {km rnqhlokhlhhjjnimjmoll {kl nqhlokhlhhjjnimjmoll”, you can actually decode that and get vertices, edges and faces. Python, .NET, or ObjectARX you can use AcDbAssocPersSubentIdPE, It’s like a BRep shortcut. Or use Brep from pyrx import Ap, Db, Ed, Ge, Br print("added command pygetsubents") def pygetsubents(ent: Db.Entity): pe = Db.AssocPersSubentIdPE(ent.queryX(Db.AssocPersSubentIdPE.desc())) print("vertex") for vtx in pe.getAllSubentities(ent, Db.SubentType.kVertexSubentType): # Get the geometric position of each vertex pos = pe.getVertexSubentityGeometry(ent, vtx) print(pos) print("edge") for edge in pe.getAllSubentities(ent, Db.SubentType.kEdgeSubentType): curve = pe.getEdgeSubentityGeometry(ent, edge) print(curve.getStartPoint(), curve.getEndPoint()) print("surface") for face in pe.getAllSubentities(ent, Db.SubentType.kFaceSubentType): brface = Br.Face() brface.setSubentPath(Db.FullSubentPath(ent.objectId(), face)) print("Area", brface.getArea()) @Ap.Command() def doit(): es, id, pnt = Ed.Editor.entSel("\nPick it: \n") ent = Db.Entity(id) pygetsubents(ent) Command: DOIT Pick it: vertex (117.71953884538620,11.77489209746249,100.00000000000000) (117.71953884538620,16.43799615292209,100.00000000000000) (17.71953884538620,16.43799615292209,100.00000000000000) (17.71953884538620,11.77489209746249,100.00000000000000) (117.71953884538620,16.43799615292209,0.00000000000000) (117.71953884538620,11.77489209746249,0.00000000000000) (17.71953884538620,11.77489209746249,0.00000000000000) (17.71953884538620,16.43799615292209,0.00000000000000) edge (17.71953884538620,16.43799615292209,100.00000000000000) (117.71953884538620,16.43799615292209,100.00000000000000) (117.71953884538620,16.43799615292209,0.00000000000000) (17.71953884538620,16.43799615292209,0.00000000000000) (17.71953884538620,11.77489209746249,100.00000000000000) (17.71953884538620,16.43799615292209,100.00000000000000) (17.71953884538620,16.43799615292209,100.00000000000000) (17.71953884538620,16.43799615292209,0.00000000000000) (17.71953884538620,16.43799615292209,0.00000000000000) (17.71953884538620,11.77489209746249,0.00000000000000) (117.71953884538620,11.77489209746249,100.00000000000000) (17.71953884538620,11.77489209746249,100.00000000000000) (17.71953884538620,11.77489209746249,100.00000000000000) (17.71953884538620,11.77489209746249,0.00000000000000) (17.71953884538620,11.77489209746249,0.00000000000000) (117.71953884538620,11.77489209746249,0.00000000000000) (117.71953884538620,16.43799615292209,100.00000000000000) (117.71953884538620,16.43799615292209,0.00000000000000) (117.71953884538620,16.43799615292209,100.00000000000000) (117.71953884538620,11.77489209746249,100.00000000000000) (117.71953884538620,11.77489209746249,100.00000000000000) (117.71953884538620,11.77489209746249,0.00000000000000) (117.71953884538620,11.77489209746249,0.00000000000000) (117.71953884538620,16.43799615292209,0.00000000000000) surface Area 466.31040554595984 Area 466.31040554595984 Area 10000.0 Area 466.31040554595984 Area 10000.0 Area 466.31040554595984
    1 point
  12. Regarding your initial message... Try : (command "_.explode" obj) (while (< 0 (getvar (quote cmdactive))) (command "") ) HTH.
    1 point
  13. With out looking at the code the error is probably calling obj again but it is no longer valid (because its exploded). if you want to look at exploded items you have to then add them to a selection set use this method. https://www.cadtutor.net/forum/topic/85374-why-would-entlast-not-be-getting-the-unioned-entity-in-this-code/#findComment-640512 -Edit You can also look inside blocks to pull information you want without exploding.
    1 point
  14. Often times I would make a copy of a polyline explode it and work over its sub-parts deleting them as i go. no reason you shouldn't do the same here keep the original un touched, make a copy either to a new location or layer and explode and process each part. you shouldn't avoid explode just use it on the copy. -edit https://www.cadtutor.net/forum/topic/34725-autocad2012-3d-solidsurface-into-3d-face/#findComment-281787
    1 point
  15. 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
×
×
  • Create New...