Leaderboard
Popular Content
Showing content with the highest reputation since 08/09/2026 in all areas
-
Another way to do it: transform lines, polylines/polyarcs, circles or arcs into mutilines. This way we retain the properties of the chosen multiline style. Arcs are simulated with segments. ;; ListBox (gile) ;; Boite de dialogue permettant un ou plusieurs choix dans une liste ;; ;; Arguments ;; title : le titre de la boite de dialogue (chaîne) ;; msg ; message (chaîne), "" ou nil pour aucun ;; keylab : une liste d'association du type ((key1 . label1) (key2 . label2) ...) ;; flag : 0 = liste déroulante ;; 1 = liste choix unique ;; 2 = liste choix multipes ;; ;; Retour : la clé de l'option (flag = 0 ou 1) ou la liste des clés des options (flag = 2) ;; ;; Exemple d'utilisation ;; (listbox "Présentation" "Choisir une présentation" (mapcar 'cons (layoutlist) (layoutlist)) 1) (defun ListBox (title msg keylab flag / tmp file dcl_id choice) (setq tmp (vl-filename-mktemp "tmp.dcl") file (open tmp "w") ) (write-line (strcat "ListBox:dialog{label=\"" title "\";") file ) (if (and msg (/= msg "")) (write-line (strcat ":text{label=\"" msg "\";}") file) ) (write-line (cond ((= 0 flag) "spacer;:popup_list{key=\"lst\";") ((= 1 flag) "spacer;:list_box{key=\"lst\";") (T "spacer;:list_box{key=\"lst\";multiple_select=true;") ) file ) (write-line "}spacer;ok_button;}" file) (close file) (setq dcl_id (load_dialog tmp)) (if (not (new_dialog "ListBox" dcl_id)) (exit) ) (start_list "lst") (mapcar 'add_list (mapcar 'cdr keylab)) (end_list) (action_tile "accept" "(or (= (get_tile \"lst\") \"\") (if (= 2 flag) (progn (foreach n (str2lst (get_tile \"lst\") \" \") (setq choice (cons (nth (atoi n) (mapcar 'car keylab)) choice)) ) (setq choice (reverse choice)) ) (setq choice (nth (atoi (get_tile \"lst\")) (mapcar 'car keylab))) ) ) (done_dialog)" ) (start_dialog) (unload_dialog dcl_id) (vl-file-delete tmp) choice ) (defun def_bulg_pl (ls lb flag_closed / ls lb rad a l_new) (if (not (zerop flag_closed)) (setq ls (append ls (list (car ls))))) (while (cadr ls) (if (zerop (car lb)) (setq l_new (append l_new (list (car ls)))) (progn (setq rad (/ (distance (car ls) (cadr ls)) (sin (* 2.0 (atan (abs (car lb))))) 2.0) a (- (/ pi 2.0) (- pi (* 2.0 (atan (abs (car lb)))))) ) (if (< a 0.0) (setq a (- (* 2.0 pi) a))) (if (or (and (< (car lb) 0.0) (> (car lb) -1.0)) (> (car lb) 1.0)) (setq l_new (append l_new (reverse (cdr (reverse (bulge_pts (polar (car ls) (- (angle (car ls) (cadr ls)) a) rad) (car ls) (cadr ls) rad (car lb))))))) (setq l_new (append l_new (reverse (cdr (reverse (bulge_pts (polar (car ls) (+ (angle (car ls) (cadr ls)) a) rad) (car ls) (cadr ls) rad (car lb))))))) ) ) ) (setq ls (cdr ls) lb (cdr lb)) ) (append l_new (list (car ls))) ) (defun bulge_pts (pt_cen pt_begin pt_end rad sens / inc ang nm p1 p2 lst) (setq inc (angle pt_cen (if (< sens 0.0) pt_end pt_begin)) ang (+ (* 2.0 pi) (angle pt_cen (if (< sens 0.0) pt_begin pt_end))) nm (fix (/ (rem (- ang inc) (* 2.0 pi)) (/ (* pi 2.0) 36.0))) ) (repeat nm (setq p1 (polar pt_cen inc rad) inc (+ inc (/ (* pi 2.0) 36.0)) lst (append lst (list p1)) ) ) (setq p2 (polar pt_cen ang rad) lst (append lst (list p2)) ) (if (< sens 0.0) (reverse lst) lst) ) (defun c:polyarc2ml ( / jspl nbr l_mlstyl sel_styl ent dxf_ent typent name_layer closed lst l_bulg e_next dxf_next oldlayer oldosm key_mod scale_ml) (princ "\nSelect polylines/lines/circles/arcs for transform to multilines: ") (setq jspl (ssget '((0 . "*POLYLINE,LINE,CIRCLE,ARC") (-4 . "<NOT") (-4 . "&") (70 . 124) (-4 . "NOT>"))) nbr 0 ) (cond (jspl (setq l_mlstyl (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 3)) (dictsearch (namedobjdict) "ACAD_MLINESTYLE") ) ) ) (while (not (setq sel_styl (listbox "Multilines style" "Choose a Multiline style" (mapcar 'cons l_mlstyl l_mlstyl) 1)))) (setvar "cmlstyle" sel_styl) (initget "Top Zero Bottom") (setq key_mod (getkword (strcat "\nGive justification type [Top/Zero/Bottom] <" (cond ((eq (getvar "cmljust") 0) "Top" ) ((eq (getvar "cmljust") 1) "Zero" ) ((eq (getvar "cmljust") 2) "Bottom" ) ) ">: " ) ) ) (if key_mod (cond ((eq key_mod "Top") (setvar "cmljust" 0)) ((eq key_mod "Zero") (setvar "cmljust" 1)) ((eq key_mod "Bottom") (setvar "cmljust" 2)) ) ) (setq scale_ml (getdist (strcat "\nGive scale for multiline <" (rtos (getvar "cmlscale")) ">: "))) (if scale_ml (setvar "cmlscale" scale_ml)) (setq oldlayer (getvar "clayer") oldosm (getvar "osmode")) (setvar "osmode" 0) (setvar "cmdecho" 0) (command "_.ucs" "_world") (repeat (sslength jspl) (setq typent (cdr (assoc 0 (setq dxf_ent (entget (setq ent (ssname jspl nbr)))))) name_layer (cdr (assoc 8 dxf_ent)) ) (cond ((eq typent "LWPOLYLINE") (setq closed (boole 1 (cdr (assoc 70 dxf_ent)) 1) lst (mapcar '(lambda (x) (trans x ent 1)) (mapcar 'cdr (vl-remove-if '(lambda (x) (/= (car x) 10)) dxf_ent))) l_bulg (mapcar 'cdr (vl-remove-if '(lambda (x) (/= (car x) 42)) dxf_ent)) lst (def_bulg_pl lst l_bulg closed) ) ) ((eq typent "POLYLINE") (setq closed (boole 1 (cdr (assoc 70 dxf_ent)) 1) e_next (entnext ent) ) (while (= "VERTEX" (cdr (assoc 0 (setq dxf_next (entget e_next))))) (if (zerop (boole 1 223 (cdr (assoc 70 dxf_next)))) (setq lst (cons (trans (cdr (assoc 10 dxf_next)) ent 1) lst) l_bulg (cons (cdr (assoc 42 dxf_next)) l_bulg) ) ) (setq e_next (entnext e_next)) ) (setq lst (reverse lst) l_bulg (reverse l_bulg) lst (def_bulg_pl lst l_bulg closed) ) ) ((eq typent "LINE") (setq lst (list (trans (cdr (assoc 10 dxf_ent)) 0 1) (trans (cdr (assoc 11 dxf_ent)) 0 1)) closed 0 ) ) ((eq typent "CIRCLE") (setq lst (bulge_pts (trans (cdr (assoc 10 dxf_ent)) ent 1) (polar (trans (cdr (assoc 10 dxf_ent)) ent 1) 0.0 (cdr (assoc 40 dxf_ent))) (polar (trans (cdr (assoc 10 dxf_ent)) ent 1) (- (* 2.0 pi) (/ (* pi 2.0) 36.0)) (cdr (assoc 40 dxf_ent))) (cdr (assoc 40 dxf_ent)) 1 ) lst (append lst (list (car lst))) closed 1 ) ) ((eq typent "ARC") (setq lst (bulge_pts (trans (cdr (assoc 10 dxf_ent)) ent 1) (polar (trans (cdr (assoc 10 dxf_ent)) ent 1) (cdr (assoc 50 dxf_ent)) (cdr (assoc 40 dxf_ent))) (polar (trans (cdr (assoc 10 dxf_ent)) ent 1) (cdr (assoc 51 dxf_ent)) (cdr (assoc 40 dxf_ent))) (cdr (assoc 40 dxf_ent)) 1 ) closed 0 ) ) ) (cond (lst (setvar "clayer" name_layer) (command "_.mline") (foreach n lst (command n)) (if (not (zerop closed)) (command "_close") (command "")) (entdel ent) ) ) (setq nbr (1+ nbr) lst nil l_bulg nil) ) (command "_.ucs" "_previous") (setvar "clayer" oldlayer) (setvar "osmode" oldosm) (setvar "cmdecho" 1) ) (T (princ "\nSelect is empty")) ) (prin1) )4 points
-
4 points
-
In another post there was questions about changing Mline styles for existing Mlines. So answered that and thought what about adding fillets to a mline. Wel as we know you can not do that, so did it this way. Converting the individual mlines to plines then filleting the plines produced. The fillet radius changing matching the offsets. ; Convert mline to plines and add a rdius. ; By AlanH Aug 2026 (defun LWPoly (lst cls) (entmakex (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 70 cls)) (mapcar (function (lambda (p) (cons 10 p))) lst))) ) (defun c:ml2plrad ( / oldsnap pt1 pt2 ent obj obj2 co-ords dict col lst x) (setq oldsnap (getvar 'osmode)) (setvar 'osmode 0) (setq pt1 (getpoint "\nPick 1st point for drag ")) (setq pt2 (getpoint pt1 "\nPick 2nd point ")) (setq pts (list pt1 pt2)) (setq ent (ssname (ssget "F" pts (list (cons 0 "Mline"))) 0)) (setq obj (vlax-ename->vla-object ent)) (setq styleName (vla-get-StyleName obj)) (setq lay (vlax-get obj 'layer)) (setvar 'clayer lay) (setq co-ords (vlax-get obj 'coordinates)) (vla-delete obj) (setq pts2 '() x 0) (repeat (/ (length co-ords) 3) (setq pts2 (cons (list (nth x co-ords)(nth (1+ x) co-ords)) pts2)) (setq x (+ x 3)) ) (setq dict (dictsearch (cdr (assoc -1 (dictsearch (namedobjdict) "ACAD_MLINESTYLE"))) styleName)) (setq offsets (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 49)) dict))) (setq col (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 62)) dict))) (setq col (cdr col)) ; ignore 1st color (setq lst '() x 0) (repeat (length col) (setq lst (cons (list (nth x offsets)(nth x col)) lst)) (setq x (1+ x)) ) (LWPoly pts2 0) (setvar 'filletrad (getreal "\nEnter Fillet radius for most outside offset ")) (command "fillet" "P" (entlast)) (setq x 1) (repeat (- (length col) 1) (setq obj2 (vlax-ename->vla-object (entlast))) (vlax-put obj2 'color (nth (1- x) col)) (vla-offset (vlax-ename->vla-object (entlast)) (- (nth x offsets)(nth (1- x) offsets))) (setq x (1+ x)) ) (setq obj2 (vlax-ename->vla-object (entlast))) (vlax-put obj2 'color (nth (1- x) col)) (setvar 'osmode oldsnap) (princ) ) (c:ml2plrad)3 points
-
3 points
-
Been playing quite a bit with Gilles Chanteau's kdtree lisp app published at theSwamp kd-tree (AutoLISP). So decided to turn it into a dll to use from autolisp. I am attaching the C# code below and a bat file to compile it for Autocad 2017. The dll will create the following function for autolisp: KDtreeLisp.dll Reference & Command SyntaxIn AutoLISP documentation standards, optional parameters are enclosed in square brackets [optional]. (KD-BUILD pointList [dimensions] [customHandle]) Builds a KD-Tree spatial index from a list of points. Arguments: pointList: LIST — List of 2D or 3D point lists ((x y z) ...). dimensions (optional): INT — 2 for 2D $(X,Y)$ or 3 for 3D $(X,Y,Z)$. Default is 2. customHandle (optional): STR — Custom string handle identifier. Returns: STR handle (e.g., "<KD-TREE-1>" or "<KD-TREE-SURVEY>"), or nil on failure. (KD-NEAREST handle targetPoint [count] [maxRadius]) Finds the nearest n points to a target point. Arguments: handle: STR — KD-Tree handle string. targetPoint: LIST — Target point (x y z). count (optional): INT — Number of nearest points to retrieve. Default is 1. maxRadius (optional): REAL or INT — Maximum search radius limit. Points farther than this distance are ignored. Returns:If count = 1 (or omitted): A single point (x y z). If count > 1: A list of points ((x1 y1 z1) (x2 y2 z2) ...). (KD-NEAREST-INFO handle targetPoint [count] [maxRadius]) Finds nearest points with detailed metadata. Arguments: handle: STR — KD-Tree handle string. targetPoint: LIST — Target point (x y z). count (optional): INT — Number of points to retrieve. Default is 1. maxRadius (optional): REAL or INT — Maximum search radius limit. Returns: A list of detailed entries (((x y z) index distance) ...). (KD-RANGE handle centerPoint radius) Finds all points inside a fixed search radius without a count limit. Arguments: handle: STR — KD-Tree handle string. centerPoint: LIST — Center search coordinate (x y z). radius: REAL or INT — Search radius. Returns: A list of all enclosed points ((x1 y1 z1) (x2 y2 z2) ...) sorted by distance, or nil if none are found. (KD-FREE [handle]) Frees tree memory. Arguments: handle (optional): STR — Tree handle to free. If omitted, clears all active trees. Returns: INT — Number of trees removed. Once you've compiled the C#, kdtreelisp.dll will be created and ready to use in Autocad. using System; using System.Collections.Generic; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; namespace KdTreeLisp { // ========================================== // 1. DATA STRUCTURES & TREE ENGINE // ========================================== public class KdItem { public Point3d Point { get; set; } public int Id { get; set; } public KdItem(Point3d pt, int id) { Point = pt; Id = id; } } public class KdNode { public Point3d Point { get; set; } public int Id { get; set; } public KdNode Left { get; set; } public KdNode Right { get; set; } public KdNode(Point3d point, int id) { Point = point; Id = id; } } public class NeighborResult : IComparable<NeighborResult> { public KdNode Node { get; set; } public double DistanceSq { get; set; } public NeighborResult(KdNode node, double distSq) { Node = node; DistanceSq = distSq; } public int CompareTo(NeighborResult other) { return other.DistanceSq.CompareTo(this.DistanceSq); } } public class KdTree { public KdNode Root { get; private set; } public int ActiveDimensions { get; private set; } public void Build(List<KdItem> items, int activeDimensions) { ActiveDimensions = Math.Max(1, Math.Min(3, activeDimensions)); Root = BuildRecursive(items, 0); } private KdNode BuildRecursive(List<KdItem> items, int depth) { if (items == null || items.Count == 0) return null; int axis = depth % ActiveDimensions; items.Sort(delegate(KdItem a, KdItem b) { return GetAxisValue(a.Point, axis).CompareTo(GetAxisValue(b.Point, axis)); }); int medianIndex = items.Count / 2; KdNode node = new KdNode(items[medianIndex].Point, items[medianIndex].Id); node.Left = BuildRecursive(items.GetRange(0, medianIndex), depth + 1); node.Right = BuildRecursive(items.GetRange(medianIndex + 1, items.Count - (medianIndex + 1)), depth + 1); return node; } public double CalculateDistanceSq(Point3d p1, Point3d p2) { double dx = p1.X - p2.X; double dy = p1.Y - p2.Y; if (ActiveDimensions == 2) { return dx * dx + dy * dy; } double dz = p1.Z - p2.Z; return dx * dx + dy * dy + dz * dz; } // K-Nearest Neighbor Search with Optional Maximum Radius Limit public List<NeighborResult> FindNearest(Point3d target, int count, double maxRadius = double.MaxValue) { List<NeighborResult> heap = new List<NeighborResult>(); if (Root == null || count <= 0) return heap; double maxDistSq = (maxRadius == double.MaxValue) ? double.MaxValue : maxRadius * maxRadius; SearchNearest(Root, target, count, maxDistSq, heap, 0); // Sort ascending by distance before returning heap.Sort(delegate(NeighborResult a, NeighborResult b) { return a.DistanceSq.CompareTo(b.DistanceSq); }); return heap; } private void SearchNearest(KdNode current, Point3d target, int count, double maxDistSq, List<NeighborResult> heap, int depth) { if (current == null) return; double distSq = CalculateDistanceSq(current.Point, target); // Accept point only if inside maximum distance threshold if (distSq <= maxDistSq) { if (heap.Count < count) { heap.Add(new NeighborResult(current, distSq)); heap.Sort(); } else if (distSq < heap[0].DistanceSq) { heap[0] = new NeighborResult(current, distSq); heap.Sort(); } } int axis = depth % ActiveDimensions; double diff = GetAxisValue(target, axis) - GetAxisValue(current.Point, axis); KdNode primary = diff < 0 ? current.Left : current.Right; KdNode secondary = diff < 0 ? current.Right : current.Left; SearchNearest(primary, target, count, maxDistSq, heap, depth + 1); // Pruning condition: check if secondary subtree could contain points closer than current worst candidate double currentSearchRadiusSq = (heap.Count < count) ? maxDistSq : Math.Min(heap[0].DistanceSq, maxDistSq); if (diff * diff < currentSearchRadiusSq) { SearchNearest(secondary, target, count, maxDistSq, heap, depth + 1); } } // Range Search: Retrieves ALL points within radius public List<NeighborResult> RangeSearch(Point3d center, double radius) { List<NeighborResult> results = new List<NeighborResult>(); if (Root == null || radius < 0) return results; double radiusSq = radius * radius; SearchRangeRecursive(Root, center, radiusSq, results, 0); results.Sort(delegate(NeighborResult a, NeighborResult b) { return a.DistanceSq.CompareTo(b.DistanceSq); }); return results; } private void SearchRangeRecursive(KdNode current, Point3d center, double radiusSq, List<NeighborResult> results, int depth) { if (current == null) return; double distSq = CalculateDistanceSq(current.Point, center); if (distSq <= radiusSq) { results.Add(new NeighborResult(current, distSq)); } int axis = depth % ActiveDimensions; double diff = GetAxisValue(center, axis) - GetAxisValue(current.Point, axis); if (diff < 0) { SearchRangeRecursive(current.Left, center, radiusSq, results, depth + 1); if (diff * diff <= radiusSq) { SearchRangeRecursive(current.Right, center, radiusSq, results, depth + 1); } } else { SearchRangeRecursive(current.Right, center, radiusSq, results, depth + 1); if (diff * diff <= radiusSq) { SearchRangeRecursive(current.Left, center, radiusSq, results, depth + 1); } } } private double GetAxisValue(Point3d pt, int axis) { switch (axis) { case 0: return pt.X; case 1: return pt.Y; default: return pt.Z; } } } // ========================================== // 2. AUTOLISP INTERFACE BRIDGE // ========================================== public class LispBridge { private static readonly Dictionary<string, KdTree> _trees = new Dictionary<string, KdTree>(); private static int _treeCounter = 1; // Signature: (KD-BUILD pointList [dimensions] [customHandle]) [LispFunction("KD-BUILD")] public static TypedValue BuildTree(ResultBuffer args) { if (args == null) return new TypedValue((int)LispDataType.Nil); TypedValue[] arr = args.AsArray(); List<KdItem> items = new List<KdItem>(); int idCounter = 0; int requestedDimensions = 2; string customHandle = null; foreach (TypedValue tv in arr) { if (tv.TypeCode == (int)LispDataType.Point3d) { items.Add(new KdItem((Point3d)tv.Value, idCounter++)); } else if (tv.TypeCode == (int)LispDataType.Point2d) { Point2d pt2 = (Point2d)tv.Value; items.Add(new KdItem(new Point3d(pt2.X, pt2.Y, 0.0), idCounter++)); } else if (tv.TypeCode == (int)LispDataType.Int16 || tv.TypeCode == (int)LispDataType.Int32) { requestedDimensions = Convert.ToInt32(tv.Value); } else if (tv.TypeCode == (int)LispDataType.Text) { customHandle = Convert.ToString(tv.Value); } } if (items.Count == 0) return new TypedValue((int)LispDataType.Nil); KdTree tree = new KdTree(); tree.Build(items, requestedDimensions); string handle = string.IsNullOrEmpty(customHandle) ? string.Format("<KD-TREE-{0}>", _treeCounter++) : string.Format("<KD-TREE-{0}>", customHandle.ToUpper()); _trees[handle] = tree; return new TypedValue((int)LispDataType.Text, handle); } // Signature: (KD-NEAREST handle targetPoint [count] [maxRadius]) [LispFunction("KD-NEAREST")] public static ResultBuffer FindNearest(ResultBuffer args) { if (args == null) return null; List<TypedValue> values = ExtractValues(args); if (values.Count < 2) return null; if (values[0].TypeCode != (int)LispDataType.Text) return null; string handle = Convert.ToString(values[0].Value); if (!_trees.ContainsKey(handle)) return null; KdTree tree = _trees[handle]; if (tree.Root == null) return null; Point3d target; if (values[1].TypeCode == (int)LispDataType.Point3d) { target = (Point3d)values[1].Value; } else if (values[1].TypeCode == (int)LispDataType.Point2d) { Point2d p2 = (Point2d)values[1].Value; target = new Point3d(p2.X, p2.Y, 0.0); } else { return null; } int count = 1; if (values.Count > 2 && (values[2].TypeCode == (int)LispDataType.Int16 || values[2].TypeCode == (int)LispDataType.Int32)) { count = Convert.ToInt32(values[2].Value); } double maxRadius = double.MaxValue; if (values.Count > 3) { TypedValue v = values[3]; if (v.TypeCode == (int)LispDataType.Double || v.TypeCode == (int)LispDataType.Int16 || v.TypeCode == (int)LispDataType.Int32) { maxRadius = Convert.ToDouble(v.Value); } } List<NeighborResult> results = tree.FindNearest(target, count, maxRadius); if (results.Count == 0) return null; ResultBuffer res = new ResultBuffer(); if (count == 1) { res.Add(new TypedValue((int)LispDataType.Point3d, results[0].Node.Point)); } else { res.Add(new TypedValue((int)LispDataType.ListBegin)); foreach (NeighborResult item in results) { res.Add(new TypedValue((int)LispDataType.Point3d, item.Node.Point)); } res.Add(new TypedValue((int)LispDataType.ListEnd)); } return res; } // Signature: (KD-NEAREST-INFO handle targetPoint [count] [maxRadius]) [LispFunction("KD-NEAREST-INFO")] public static ResultBuffer FindNearestInfo(ResultBuffer args) { if (args == null) return null; List<TypedValue> values = ExtractValues(args); if (values.Count < 2) return null; if (values[0].TypeCode != (int)LispDataType.Text) return null; string handle = Convert.ToString(values[0].Value); if (!_trees.ContainsKey(handle)) return null; KdTree tree = _trees[handle]; Point3d target; if (values[1].TypeCode == (int)LispDataType.Point3d) target = (Point3d)values[1].Value; else if (values[1].TypeCode == (int)LispDataType.Point2d) target = new Point3d(((Point2d)values[1].Value).X, ((Point2d)values[1].Value).Y, 0.0); else return null; int count = 1; if (values.Count > 2 && (values[2].TypeCode == (int)LispDataType.Int16 || values[2].TypeCode == (int)LispDataType.Int32)) count = Convert.ToInt32(values[2].Value); double maxRadius = double.MaxValue; if (values.Count > 3) { TypedValue v = values[3]; if (v.TypeCode == (int)LispDataType.Double || v.TypeCode == (int)LispDataType.Int16 || v.TypeCode == (int)LispDataType.Int32) maxRadius = Convert.ToDouble(v.Value); } List<NeighborResult> results = tree.FindNearest(target, count, maxRadius); if (results.Count == 0) return null; ResultBuffer res = new ResultBuffer(); res.Add(new TypedValue((int)LispDataType.ListBegin)); foreach (NeighborResult item in results) { res.Add(new TypedValue((int)LispDataType.ListBegin)); res.Add(new TypedValue((int)LispDataType.Point3d, item.Node.Point)); res.Add(new TypedValue((int)LispDataType.Int32, item.Node.Id)); res.Add(new TypedValue((int)LispDataType.Double, Math.Sqrt(item.DistanceSq))); res.Add(new TypedValue((int)LispDataType.ListEnd)); } res.Add(new TypedValue((int)LispDataType.ListEnd)); return res; } // Signature: (KD-RANGE handle centerPoint radius) [LispFunction("KD-RANGE")] public static ResultBuffer RangeSearch(ResultBuffer args) { if (args == null) return null; List<TypedValue> values = ExtractValues(args); if (values.Count < 3) return null; if (values[0].TypeCode != (int)LispDataType.Text) return null; string handle = Convert.ToString(values[0].Value); if (!_trees.ContainsKey(handle)) return null; KdTree tree = _trees[handle]; Point3d center; if (values[1].TypeCode == (int)LispDataType.Point3d) center = (Point3d)values[1].Value; else if (values[1].TypeCode == (int)LispDataType.Point2d) center = new Point3d(((Point2d)values[1].Value).X, ((Point2d)values[1].Value).Y, 0.0); else return null; double radius = 0.0; TypedValue rVal = values[2]; if (rVal.TypeCode == (int)LispDataType.Double || rVal.TypeCode == (int)LispDataType.Int16 || rVal.TypeCode == (int)LispDataType.Int32) { radius = Convert.ToDouble(rVal.Value); } else { return null; } List<NeighborResult> results = tree.RangeSearch(center, radius); if (results.Count == 0) return null; ResultBuffer res = new ResultBuffer(); res.Add(new TypedValue((int)LispDataType.ListBegin)); foreach (NeighborResult item in results) { res.Add(new TypedValue((int)LispDataType.Point3d, item.Node.Point)); } res.Add(new TypedValue((int)LispDataType.ListEnd)); return res; } // Signature: (KD-FREE [handle]) [LispFunction("KD-FREE")] public static TypedValue FreeTree(ResultBuffer args) { if (args == null) { int count = _trees.Count; _trees.Clear(); return new TypedValue((int)LispDataType.Int32, count); } List<TypedValue> values = ExtractValues(args); if (values.Count == 0 || values[0].TypeCode != (int)LispDataType.Text) { int count = _trees.Count; _trees.Clear(); return new TypedValue((int)LispDataType.Int32, count); } string handle = Convert.ToString(values[0].Value); bool removed = _trees.Remove(handle); return new TypedValue((int)LispDataType.Int32, removed ? 1 : 0); } private static List<TypedValue> ExtractValues(ResultBuffer resbuf) { List<TypedValue> list = new List<TypedValue>(); foreach (TypedValue tv in resbuf.AsArray()) { if (tv.TypeCode != (int)LispDataType.ListBegin && tv.TypeCode != (int)LispDataType.ListEnd) { list.Add(tv); } } return list; } } } ymg KDtreeLisp.cs Build.bat2 points
-
In ARX you would use these for general cleanup AcDbDatabase::eraseEmptyObjects(kAllEmptyObj) AcDbDatabase::purge (AcDbObjectIdArray&) # may require multiple passes AcDbDatabase::purge (AcDbObjectIdGraph&) # single pass I made a python sample here. https://www.theswamp.org/index.php?topic=60192 For something like overkill, AcGeCurveCurveInt3d is the go-to class. As it gives overlap information Here’s another python sample for finding overlapping polylines https://www.theswamp.org/index.php?topic=59828 Proxies, you can erase, or call swapid on a non-owned object. AutoCAD won’t save orphaned objects Of course with these types of methods, you must let the end user confirm the operation, as BigAl mentions, they can be destructive2 points
-
Create several splines on the XY plane then move each one in Z so that they have increasing Z values from one spline to the next. In this example the z values for the splines are 0.0, 2, 4, and 6. Use LOFT to create a surface from the splines (shown in red). From the Properties panel, change the U isoline property to a larger value (e.g.,12) and the V isoline value to 0. Select the surface and move the grips to localy adjust the spacing between isolines to meet your requirements. Note, the green arrows show grips that have been moved to increase spacing between adjacent isolines. Unfortunatly, if you need individual polylines or splines on the XY plane you will need to use SECTION to create them individually. For example,section the surface paralle to the XY plane through points at (0,0,0.5), (0,0,1), (0,0,1.5), etc.2 points
-
I have always dimensioned in paper space. Never have experienced any problems. No need to assign multiple scale factors.2 points
-
You could also add these 2, purgezerolangth and purgezerotxt, they will remove some entities but not generally make a massive change to size. (defun PurgeZeroLengths ( / MySS Fuzz acount DelSS MyEnt EndA EndB) ;; for within blocks (setq MySS (ssget (list (cons 0 "LINE,SPLINE,LWPOLYLINE,POLYLINE,ARC,CIRCLE,ELLIPSE")))) (setq Fuzz 0.0001) ; Fuzz factor to delete very short entities (setq acount 0) (setq DelSS (ssadd)) (while (< acount (sslength MySS)) (setq MyEnt (ssname MySS acount)) (if (equal (vlax-curve-getDistAtParam MyEnt (vlax-curve-getEndParam MyEnt)) 0) (progn (setq DelSS (ssadd MyEnt DelSS)) ) ) ; end if ;;If less then a length (if (< (vlax-curve-getDistAtParam MyEnt (vlax-curve-getEndParam MyEnt)) Fuzz) (progn (setq DelSS (ssadd MyEnt DelSS)) ) ) ; end if (setq acount (+ acount 1)) ) ; end while (princ "\nDeleting ")(princ (sslength DelSS))(princ " lines") (command "erase" DelSS "") (princ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun c:PurgeZeroTexts ( / MySS acount DelSS MyEnt MyText) (setq MySS (ssget (list (cons 0 "*TEXT")(cons 1 "")))) (setq acount 0) (setq DelSS (ssadd)) (if MySS (progn (while (< acount (sslength MySS)) (setq MyEnt (ssname MySS acount)) (setq MyText (cdr (assoc 1 (entget MyEnt)))) (if (equal MyText "") (progn (setq DelSS (ssadd MyEnt DelSS)) ) ) ; end if (setq acount (+ acount 1)) ) ; end while (princ "\nDeleting ")(princ (sslength DelSS))(princ " lines") (command "erase" DelSS "") ) ; end progn (progn (princ "No zero content texts found") ) ) ; end if (princ) )2 points
-
Here's another Net app to facilitate the simplification of polyline with lots of segments. I am including the code and a bat file to compile it for Autocad 2017. Once you've compiled VWSimplifyInteractive.cs into VWSimplifyInteractive.dll, Netload it into autocad. New comand VWSimplifyInteractive will now be available to trhe command line or Autolisp. If you run the command you will be asked to select a polyline. The selected poly will be copied in Magenta,then a dialog box with 3 sliders will appear to let you vary the parameter of the simplification. The polyline is simplified in real-time and you can adjust the parameters until you Accept or Cancel. Note that your original polyline remains untouched and that the simplified one is place on layer "Simplified Poly" with color Green. once you press Accept. Here's the C# code: // VWSimplifyInteractive.cs // Interactive Visvalingam + Zhou-Jones for AutoCAD 2017 using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using AcApp = Autodesk.AutoCAD.ApplicationServices.Application; [assembly: CommandClass(typeof(VWSimplify.InteractiveCommands))] namespace VWSimplify { public class InteractiveCommands { [CommandMethod("VWSimplifyInteractive", CommandFlags.Modal | CommandFlags.Session)] public void Run() { Document doc = AcApp.DocumentManager.MdiActiveDocument; if (doc == null) return; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSelect polyline to simplify: "); peo.SetRejectMessage("\nOnly LWPOLYLINE allowed."); peo.AddAllowedClass(typeof(Polyline), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; ObjectId srcId = per.ObjectId; // Create and show the modeless form var form = new SimplifyForm(srcId); AcApp.ShowModelessDialog(form); } } public class SimplifyForm : Form { private ObjectId _srcId; private ObjectId _previewId = ObjectId.Null; private TrackBar tbPercent; private CheckBox chkFlat, chkSkew, chkConv; private TrackBar tbFlat, tbSkew, tbConv; private Label lblPercent, lblVertices, lblFlat, lblSkew, lblConv; private Button btnAccept, btnCancel; // Current parameters private double _percent = 15.0; private bool _useFlat = true; private bool _useSkew = false; private bool _useConv = true; private double _flatStrength = 1.5; // reasonable start private double _skewStrength = 1.0; private double _convStrength = 2.5; // reasonable start public SimplifyForm(ObjectId srcId) { _srcId = srcId; InitializeComponent(); this.Shown += SimplifyForm_Shown; } private void SimplifyForm_Shown(object sender, EventArgs e) { UpdatePreview(); // First preview once form is displayed } private void InitializeComponent() { this.Text = "VW Simplify – Interactive"; this.Size = new Size(380, 445); this.FormBorderStyle = FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; int y = 15; // Percentage lblPercent = new Label() { Left = 15, Top = y, Width = 330, Text = "Target Ratio: 15%" }; tbPercent = new TrackBar() { Left = 15, Top = y + 20, Width = 330, Minimum = 1, Maximum = 100, Value = 15, TickFrequency = 5 }; tbPercent.ValueChanged += (s, e) => { _percent = tbPercent.Value; lblPercent.Text = "Target Ratio: " + _percent + "%"; UpdatePreview(); }; y += 65; // Vertex Counter Label lblVertices = new Label() { Left = 15, Top = y, Width = 330, Text = "Vertices: Original: - | Current: - (-%)", ForeColor = Color.DarkBlue }; y += 25; // Flatness chkFlat = new CheckBox() { Left = 15, Top = y, Text = "Use Flatness weight", Checked = true, Width = 200 }; chkFlat.CheckedChanged += (s, e) => { _useFlat = chkFlat.Checked; tbFlat.Enabled = _useFlat; UpdatePreview(); }; y += 25; lblFlat = new Label() { Left = 30, Top = y, Width = 300, Text = "Flatness strength: 1.5" }; tbFlat = new TrackBar() { Left = 30, Top = y + 20, Width = 300, Minimum = 10, Maximum = 40, Value = 15, // 1.0 – 4.0 TickFrequency = 5 }; tbFlat.ValueChanged += (s, e) => { _flatStrength = tbFlat.Value / 10.0; lblFlat.Text = "Flatness strength: " + _flatStrength.ToString("0.0"); UpdatePreview(); }; y += 65; // Skewness chkSkew = new CheckBox() { Left = 15, Top = y, Text = "Use Skewness weight", Checked = false, Width = 200 }; chkSkew.CheckedChanged += (s, e) => { _useSkew = chkSkew.Checked; tbSkew.Enabled = _useSkew; UpdatePreview(); }; y += 25; lblSkew = new Label() { Left = 30, Top = y, Width = 300, Text = "Skewness strength: 1.0" }; tbSkew = new TrackBar() { Left = 30, Top = y + 20, Width = 300, Minimum = 10, Maximum = 30, Value = 10, Enabled = false }; tbSkew.ValueChanged += (s, e) => { _skewStrength = tbSkew.Value / 10.0; lblSkew.Text = "Skewness strength: " + _skewStrength.ToString("0.0"); UpdatePreview(); }; y += 65; // Convexity chkConv = new CheckBox() { Left = 15, Top = y, Text = "Use Convexity weight", Checked = true, Width = 200 }; chkConv.CheckedChanged += (s, e) => { _useConv = chkConv.Checked; tbConv.Enabled = _useConv; UpdatePreview(); }; y += 25; lblConv = new Label() { Left = 30, Top = y, Width = 300, Text = "Convexity strength: 2.5" }; tbConv = new TrackBar() { Left = 30, Top = y + 20, Width = 300, Minimum = 10, Maximum = 50, Value = 25, // 1.0 – 5.0 TickFrequency = 5 }; tbConv.ValueChanged += (s, e) => { _convStrength = tbConv.Value / 10.0; lblConv.Text = "Convexity strength: " + _convStrength.ToString("0.0"); UpdatePreview(); }; y += 70; // Buttons btnAccept = new Button() { Text = "Accept", Left = 80, Top = y, Width = 90 }; btnCancel = new Button() { Text = "Cancel", Left = 190, Top = y, Width = 90 }; btnAccept.Click += BtnAccept_Click; btnCancel.Click += BtnCancel_Click; this.Controls.AddRange(new Control[] { lblPercent, tbPercent, lblVertices, chkFlat, lblFlat, tbFlat, chkSkew, lblSkew, tbSkew, chkConv, lblConv, tbConv, btnAccept, btnCancel }); this.FormClosing += (s, e) => CleanupPreview(false); } private void UpdatePreview() { Document doc = AcApp.DocumentManager.MdiActiveDocument; if (doc == null) return; int originalCount = 0; int simplifiedCount = 0; using (DocumentLock dl = doc.LockDocument()) using (Transaction tr = doc.TransactionManager.StartTransaction()) { Polyline src = tr.GetObject(_srcId, OpenMode.ForRead) as Polyline; if (src == null) { tr.Commit(); return; } originalCount = src.NumberOfVertices; List<Point2d> simplified = Simplify(src, _percent, _useFlat, _useSkew, _useConv, _flatStrength, _skewStrength, _convStrength); if (simplified == null || simplified.Count < 2) { tr.Commit(); return; } simplifiedCount = simplified.Count; BlockTableRecord btr = (BlockTableRecord)tr.GetObject(doc.Database.CurrentSpaceId, OpenMode.ForWrite); // Erase old preview polyline if it exists if (!_previewId.IsNull && !_previewId.IsErased) { DBObject oldObj = tr.GetObject(_previewId, OpenMode.ForWrite, false); if (oldObj != null) { oldObj.Erase(); } _previewId = ObjectId.Null; } // Construct new polyline Polyline preview = new Polyline(); for (int i = 0; i < simplified.Count; i++) { preview.AddVertexAt(i, simplified[i], 0, 0, 0); } preview.Closed = src.Closed && simplified.Count >= 3; preview.ColorIndex = 6; // Magenta preview.ConstantWidth = 0; btr.AppendEntity(preview); tr.AddNewlyCreatedDBObject(preview, true); _previewId = preview.ObjectId; tr.Commit(); } // Update UI vertex stats if (originalCount > 0) { double reduction = 100.0 * (1.0 - ((double)simplifiedCount / originalCount)); lblVertices.Text = string.Format("Vertices: Original: {0} | Current: {1} ({2:0.0}% reduced)", originalCount, simplifiedCount, reduction); } AcApp.DocumentManager.MdiActiveDocument.Editor.Regen(); } private void BtnAccept_Click(object sender, EventArgs e) { Document doc = AcApp.DocumentManager.MdiActiveDocument; if (doc == null) return; using (DocumentLock dl = doc.LockDocument()) using (Transaction tr = doc.TransactionManager.StartTransaction()) { if (!_previewId.IsNull && !_previewId.IsErased) { Polyline preview = tr.GetObject(_previewId, OpenMode.ForWrite) as Polyline; if (preview != null) { // Ensure layer exists LayerTable lt = (LayerTable)tr.GetObject(doc.Database.LayerTableId, OpenMode.ForRead); ObjectId layerId; if (!lt.Has("Simplified Poly")) { lt.UpgradeOpen(); LayerTableRecord ltr = new LayerTableRecord(); ltr.Name = "Simplified Poly"; ltr.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex( Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 3); // green layerId = lt.Add(ltr); tr.AddNewlyCreatedDBObject(ltr, true); } else layerId = lt["Simplified Poly"]; preview.LayerId = layerId; preview.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex( Autodesk.AutoCAD.Colors.ColorMethod.ByLayer, 256); // Add XData with parameters AddXData(preview, tr, doc.Database); _previewId = ObjectId.Null; // prevent cleanup from erasing it } } tr.Commit(); } this.Close(); } private void BtnCancel_Click(object sender, EventArgs e) { CleanupPreview(true); this.Close(); } private void CleanupPreview(bool erase) { if (_previewId.IsNull || _previewId.IsErased) return; Document doc = AcApp.DocumentManager.MdiActiveDocument; if (doc == null) return; using (DocumentLock dl = doc.LockDocument()) using (Transaction tr = doc.TransactionManager.StartTransaction()) { if (erase) { DBObject obj = tr.GetObject(_previewId, OpenMode.ForWrite, false); if (obj != null) obj.Erase(); } tr.Commit(); } _previewId = ObjectId.Null; } private void AddXData(Polyline pl, Transaction tr, Database db) { RegAppTable rat = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead); if (!rat.Has("VW_SIMPLIFY")) { rat.UpgradeOpen(); RegAppTableRecord reg = new RegAppTableRecord(); reg.Name = "VW_SIMPLIFY"; rat.Add(reg); tr.AddNewlyCreatedDBObject(reg, true); } ResultBuffer rb = new ResultBuffer( new TypedValue(1001, "VW_SIMPLIFY"), new TypedValue(1000, "Visvalingam-ZhouJones"), new TypedValue(1040, _percent), new TypedValue(1071, _useFlat ? 1 : 0), new TypedValue(1040, _flatStrength), new TypedValue(1071, _useSkew ? 1 : 0), new TypedValue(1040, _skewStrength), new TypedValue(1071, _useConv ? 1 : 0), new TypedValue(1040, _convStrength) ); pl.XData = rb; } //-------------------------------------------------------------------- // Simplification core with Zhou-Jones weights //-------------------------------------------------------------------- private List<Point2d> Simplify(Polyline src, double percent, bool useFlat, bool useSkew, bool useConv, double flatStr, double skewStr, double convStr) { int n = src.NumberOfVertices; if (n < 3) return null; List<Point2d> pts = new List<Point2d>(n); for (int i = 0; i < n; i++) pts.Add(src.GetPoint2dAt(i)); bool closed = src.Closed; if (closed && !pts[0].IsEqualTo(pts[pts.Count - 1], new Tolerance(1e-10, 1e-10))) pts.Add(pts[0]); int target = (int)Math.Max(2, Math.Round(n * percent / 100.0)); if (closed) target = Math.Max(target, 3); return VisvalingamZhouJones(pts, target, useFlat, useSkew, useConv, flatStr, skewStr, convStr); } private List<Point2d> VisvalingamZhouJones(List<Point2d> pts, int target, bool useFlat, bool useSkew, bool useConv, double flatStr, double skewStr, double convStr) { int n = pts.Count; if (n <= target) return new List<Point2d>(pts); Point2d[] points = pts.ToArray(); double[] areas = new double[n]; bool[] alive = new bool[n]; int[] prev = new int[n]; int[] next = new int[n]; for (int i = 0; i < n; i++) { alive[i] = true; prev[i] = i - 1; next[i] = i + 1; areas[i] = double.MaxValue; } prev[0] = -1; next[n - 1] = -1; var heap = new SortedSet<HeapItem>(); for (int i = 1; i < n - 1; i++) { double a = WeightedArea(points, i, prev, next, useFlat, useSkew, useConv, flatStr, skewStr, convStr); areas[i] = a; heap.Add(new HeapItem(a, i)); } double lastArea = 0.0; int live = n; while (heap.Count > 0 && live > target) { HeapItem item = heap.Min; heap.Remove(item); int idx = item.Index; if (!alive[idx] || Math.Abs(item.Area - areas[idx]) > 1e-12) continue; double a = Math.Max(item.Area, lastArea); lastArea = a; areas[idx] = a; alive[idx] = false; live--; int p0 = prev[idx]; int p2 = next[idx]; if (p0 >= 0) next[p0] = p2; if (p2 >= 0) prev[p2] = p0; if (p0 >= 0 && alive[p0] && prev[p0] >= 0) { double na = WeightedArea(points, p0, prev, next, useFlat, useSkew, useConv, flatStr, skewStr, convStr); if (na < lastArea) na = lastArea; areas[p0] = na; heap.Add(new HeapItem(na, p0)); } if (p2 >= 0 && alive[p2] && next[p2] >= 0) { double na = WeightedArea(points, p2, prev, next, useFlat, useSkew, useConv, flatStr, skewStr, convStr); if (na < lastArea) na = lastArea; areas[p2] = na; heap.Add(new HeapItem(na, p2)); } } List<Point2d> res = new List<Point2d>(); for (int i = 0; i < n; i++) if (alive[i]) res.Add(points[i]); return res; } private double WeightedArea(Point2d[] pts, int i, int[] prev, int[] next, bool useFlat, bool useSkew, bool useConv, double flatStr, double skewStr, double convStr) { Point2d a = pts[prev[i]]; Point2d b = pts[i]; Point2d c = pts[next[i]]; double ea = TriangleArea(a, b, c); if (ea < 1e-20) return 0.0; double wFlat = 1.0, wSkew = 1.0, wConv = 1.0; // Base length and height double baseLen = a.GetDistanceTo(c); if (baseLen < 1e-12) return ea; // Height double area2 = Math.Abs((b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X)); double height = area2 / baseLen; // ---- Flatness ---- if (useFlat) { double ratio = height / baseLen; wFlat = Math.Pow(Math.Max(ratio, 1e-6), flatStr); } // ---- Skewness (prefer isosceles) ---- if (useSkew) { double d1 = a.GetDistanceTo(b); double d2 = b.GetDistanceTo(c); double maxd = Math.Max(d1, d2); double mind = Math.Min(d1, d2); double skewRatio = (maxd > 1e-12) ? mind / maxd : 1.0; wSkew = Math.Pow(skewRatio, skewStr); } // ---- Convexity ---- if (useConv) { // Cross product sign to determine turn direction double cross = (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X); if (cross > 0) wConv = convStr; // boost convex else wConv = 1.0; // concave stays normal } return ea * wFlat * wSkew * wConv; } private double TriangleArea(Point2d a, Point2d b, Point2d c) { return 0.5 * Math.Abs(a.X * (b.Y - c.Y) + b.X * (c.Y - a.Y) + c.X * (a.Y - b.Y)); } private class HeapItem : IComparable<HeapItem> { public double Area; public int Index; public HeapItem(double area, int index) { Area = area; Index = index; } public int CompareTo(HeapItem other) { int cmp = Area.CompareTo(other.Area); return cmp != 0 ? cmp : Index.CompareTo(other.Index); } } } } Bat file to compile for Acad 2017, From a powershell prompt issue: .\Build VWSimplifyInteractive @echo off if "%~1"=="" ( echo Error: No source file specified. echo Usage: build.bat SourceFileName exit /b 1 ) :: 1. Define Compiler and Directory Paths set CSC="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe" set NETFRAMEWORK=C:\Windows\Microsoft.NET\Framework64\v4.0.30319 set NETWPF=C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF set ACAD=C:\Program Files\Autodesk\AutoCAD 2017 :: 2. Search Paths for /lib set LIBPATHS=/lib:"%NETFRAMEWORK%","%NETWPF%","%ACAD%" :: 3. Standard & Core .NET Assemblies set SYS_REFS=/r:System.dll /r:System.Core.dll /r:System.Data.dll /r:System.Drawing.dll /r:System.Xml.dll /r:System.Xml.Linq.dll :: 4. WPF, UI, & Windows Interop Assemblies set UI_REFS=/r:WindowsBase.dll /r:PresentationCore.dll /r:PresentationFramework.dll /r:System.Xaml.dll /r:System.Windows.Forms.dll :: 5. AutoCAD Assemblies set ACAD_REFS=/r:AcCoreMgd.dll /r:AcDbMgd.dll /r:AcMgd.dll :: 6. Optional Third-Party/Local DLLs in current folder set LOCAL_REFS= if exist "*.dll" ( set LOCAL_REFS=/lib:"%CD%" ) :: Execute Compilation %CSC% /target:library /platform:x64 /out:"%~1.dll" %LIBPATHS% %LOCAL_REFS% %SYS_REFS% %UI_REFS% %ACAD_REFS% "%~1.cs" if %ERRORLEVEL% equ 0 ( echo. echo Successfully built %~1.dll ) else ( echo. echo Compilation failed. ) VWSimplifyInteractive.cs Build.bat2 points
-
all you would need to do is edit the bat file to point at the target platform. AI says you can jut create a project file next to the .cs, then use “dotnet build -c Release” <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <!-- Use net48 for AutoCAD 2021-2024, or net8.0-windows for AutoCAD 2025+ --> <TargetFramework>net8.0-windows</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <Platforms>x64</Platforms> </PropertyGroup> <!-- Reference your AutoCAD libraries --> <ItemGroup> <Reference Include="AcCoreMgd"> <HintPath>C:\Program Files\Autodesk\AutoCAD 2017\AcCoreMgd.dll</HintPath> <Private>False</Private> <!-- Prevents copying AutoCAD DLLs to your output folder --> </Reference> <Reference Include="AcDbMgd"> <HintPath>C:\Program Files\Autodesk\AutoCAD 2017\AcDbMgd.dll</HintPath> <Private>False</Private> </Reference> <Reference Include="AcMgd"> <HintPath>C:\Program Files\Autodesk\AutoCAD 2017\AcMgd.dll</HintPath> <Private>False</Private> </Reference> </ItemGroup> </Project>2 points
-
2 points
-
As previously stated, used an install lisp, only a few minutes.2 points
-
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
-
If you use Etransmit it will add extra files to what is exported, in particular say custom fonts and xrefs.2 points
-
@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
-
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
-
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 tool2 points
-
@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
-
@CivilTechSource the Block/dwg select is part of the POP menu interface, in particular the Icon section. It's just made with Notepad and you save a MNU file., Autocad handles the actual dcl. Re images yes they are slides, SLD files. Ok the how to. 1st step is you must shrink your screen area down to about 1/4 size. When slides were introduced screens were 640x480 so current screens are way more pixels. I use a lisp to make the slides insert say a block, zoom E, Zoom 0.9XP then MSLIDE, Erase last and insert next. Obviously the name of the saved slide is in the lisp. Without going into now you can make like 200 slides very quickly including inserting other block dwg's. You can use a program called Slide library it compresses all your slides into one SLB file a bit easier to manage, I have numerous slb files that contain common items eg landscaping, cars. ***MENUGROUP=CADARC ***POP1 **CADARC2018 [CADARC] LOAD CADARC]^C^C(LOAD "CA3ENTR2013")(LOAD "CA4USRLA-2") [->Set Up] [DRAWING SETUP]^c^C^p(load "ca11set") [--] ............. ............. ............. ............. ***icon **FURN [FURNITURE:] [CTONE(CHAIR-1)]^c^cINSERT ca3ch-1 DRAG \1;;DRAG [CTONE(CHAIR-2)]^c^cINSERT ca3ch-2 DRAG \1;;DRAG [CTONE(SOFA-1)]^c^cINSERT ca3sof1 DRAG \1;;DRAG1 point
-
Block Library pallet - I had that 20 years ago with FastCAD - which inspired me to make something very similar to BigALs - though I think the workings behind are a bit different - might be wrong, BigAl, do you use slide files for the thumbnails? (I remember you giving me a good instruction of them a few years ago now... which I then ignored.... and went with vector images). Can apply any command / LISP to the thumbnails (for example I have a tab 'Get': "Google", "CAD Standards", "Current Folder" which runs just the LISP to open chrome / explorer) - I think BigAl can do the same too. (B&W because I got too lazy to colour them all in)1 point
-
When that is what you need done, NCOPY is a wonderful tool. You don't have to worry about orientation or layers, you don't have to cut and paste from somewhere else, you just select the object(s) you want. I don't use it often, but when I do, it's a real time saver. It's been in AutoCAD since 2013, so there's no excuse not to know about it.1 point
-
I don't know if there was ever another LISP/Program to do this type of get length at least I never found one, my original just did what I needed, I have since made it more generally useful (I hope). As per the drawing I will attach, I just need to get the length of the center between the inner and outer of the perimeter of guards, etc. to determine the unrolled length. Normally the guards are 3D and I create the profiles with SOLPROF which creates an anonymous block (I used to change these with UNANON) or sometimes in the past I have used SOLVIEW and SOLDRAW, the same issue arises that you just can't select them and get the profile length. So originally that's what this LISP was created to do (I still have some of the older basic versions). I have upgraded it to it's current state and also still working on another version, but only small enhancements. For inside a block that is scaled, you will need to multiply the results by the scale factor, working through a viewport the viewport needs to be active, so I might tackle those issues as well as make a more detailed CSV. I also will try to make sure it works in non-AutoCAD like BricsCAD, CMS IntelliCAD, nanoCAD, etc. when I get time. I lightly tested in most situations, I have no idea how it acts on non-uniformly scaled blocks, though. It handles gaps and slight overlaps, I have some settings at the top, hopefully with enough instructions to modify on your own. Where I work (except for the machine shop which uses decimal inches) they use Architectural units, I did not double check this in Metric, so if someone would report back on that it would help. GETLEN_2.0.lsp Guard Test Met.dwg BlkLenTest.dwg1 point
-
I'll try to get to this and finish the Excel today if I can free up some time. I can only test Calc on my home computer, but I'll give it a blind shot at work if I get time, then test and trouble shoot at home. Is the GetLen 2.0.lsp working better in Metric now?1 point
-
Hi, The GeometryExtensions.NET library provides a generic KdTree<T> class which uses parallel computation for building the tree. It also provides an example of Point3dTree class but can used with any type of object providing a 'getPosition' function. // public KdTree(IEnumerable<T> source, Func<T, Point3d>?getPosition, int dimension) var tree = new KdTree<BlockReference>(blockList, br => br.Position, 2);1 point
-
I forgot all about Govert's programs. I use them on the home computers that have AutoCAD 2000i.1 point
-
1 point
-
1 point
-
1 point
-
Just a comment if a dwg has been made by CIV3D the purge command will not remove objects even un used, you need to run PURGESTYLESANDSETTINGS it can make a big difference. After run normal Purge. Also in CIV3D surfaces are inside a dwg. But you may need CIV3D to run purges&s or remove surfaces. Similar for other CAD 3rd party add ons can have lots of proxy objects, you can use "ZOMBIE KILLER" to remove proxy objects, say in Bricscad the opening screen will show a message dwg has proxy objects.1 point
-
1 point
-
For Excel direct the simplest is open a new Excel. You can open an existing excel by file name or even get current Excel Worksheet. You can then get say last row that contains something so that when you add more answers you know the row to start at. I would just make a simple lisp that has all the required defuns in it. Open a new Excel. Then write the row answers. with say a 1 row gap. As version 1. Yes version 2 Open new, use existing, open an existing file. The other defuns that could be added are stuff like color cell text and backgrounds. I called this little lisp "Alan open-read-write excel.lsp" ; Excel function using lisp ; By AlanH and inspiration from others ; Gilles ; JefferyPSanders.com ; Lee-mac ; MunteanStefan ; danielrodriguez ; code by the great FIXO no longer with us (defun Openexcel ( / ) (princ "\nOpening Excel...") ;; Try to get or create Excel instance (setq myxl (vl-catch-all-apply 'vlax-get-or-create-object '("Excel.Application"))) (if (vl-catch-all-error-p myxl) (progn (prompt "\nError: Could not start Excel.") (exit) ) ) (if (= (vlax-get-property (vlax-get-property myXL 'WorkBooks) 'count) 0) (vlax-invoke-method (vlax-get-property myXL 'WorkBooks) 'Add) ) (vla-put-visible myXL :vlax-true) (vlax-put-property myxl 'ScreenUpdating :vlax-true) (vlax-put-property myXL 'DisplayAlerts :vlax-true) (princ) ) ;; Thanks to fixo ;; ;; = Set Excel cell text = ;; (defun xlsetcelltext ( row column text) (setq cells (vlax-get-property (vlax-get-property myxl "ActiveSheet") "Cells")) (vl-catch-all-apply 'vlax-put-property (list cells 'Item row column (vlax-make-variant (vl-princ-to-string text) vlax-vbstring))) ) ;; Thanks to fixo ;; get value of a cell (defun getcell2 (row column / ) (setq cells (vlax-get-property (vlax-get-property myxl "ActiveSheet") "Cells")) (setq cell (vlax-get (vlax-variant-value (vlax-get-property cells "Item" row column)) 'value)) ) A sample sequence. You could put all the code in your program. Maybe later will post something with a Excel option. (if (not openexcel)(load "alan open-read-write.lsp")) (openexcel) (xlsetcelltext 4 4 "Alan") (getcell2 4 4) @SLW210 Happy to do the CSV, Excel or Libreoffice code. Post updated code and dcl etc.1 point
-
I would like to add another advantage of plotting in paper space is the ability to have multiple vports looking at the same area in the model but using different scales.1 point
-
Welcome You can try distributing plugins using the VedaCAD method, which supports LSP, FAS, VLX, ARX, and DLL format plugins. There's no need to configure paths or copy code anymore; on the user side, a 6-digit VCID = a certain plugin function, and it is directly available.1 point
-
I used to only work in model space and I would never have switched possibly if not for the new office that uses paper space templates.. I see only one advantage of this : publishing automatically all selected pages at once vs plot windows from model space.1 point
-
Since Acad first introduced DCL's that is like 40+ years ago, there has been no improvements to DCL's. This may be a big opportunity for Bricscad to add some more features. A few obvious ones. Text color Text style Text size Using other methods like .Net, VBA and maybe Open dcl the latter I don't use, allow for some of the options to be used. Obviously it's a support request, given that Bricscad has added VL functions not in other software, then maybe some new dcl options would be good. A proper forms engine would be good. So before sending a support request any other suggestions ? Hopefully more support requests will follow.1 point
-
Here is libreoffice code. Hopefully it is the correct one. Re display answers. The simplest is use Alert just add the "\n" in string for multi lines. Yes can do a dcl its made up of text paragraphs. And message boxes as last idea. (alert "This is line one\nline 2\nline 3") ;;;;;;;;;;;;;;;;;;;;; ; make text dcl from list ; By Alan H july 2026 (defun AHmakepara (lst / fo x dcl_id) (setq fo (open (setq fname (vl-filename-mktemp "" "" ".dcl")) "w")) (write-line "AHpara: dialog {" fo) (write-line (strcat " label = " (chr 34) "Current values" (chr 34) " ;") fo) (write-line " : column {" fo) (write-line " width =25;" fo) (write-line " : paragraph {" fo) (setq x 0) (repeat (length lst) (write-line " : text_part {" fo) (write-line (strcat "label = " (chr 34) (nth x lst) (chr 34) ";") fo) (setq x (1+ x)) (write-line " }" fo) ) (write-line " }" fo) (write-line "spacer_1 ;" fo) (write-line "ok_cancel ; }" fo) (write-line " }" fo) (close fo) (setq dcl_id (load_dialog fname)) (if (not (new_dialog "AHpara" dcl_id)) (exit) ) (action_tile "accept" "(setq ans 1)(done_dialog)") (action_tile "cancel" "(setq ans 2)(done_dialog)") (start_dialog) (unload_dialog dcl_id) (vl-file-delete fname) (princ ans) (princ) ) ; (if (not AHmakepara)(load "Multi para.lsp")) ; (setq lst (list "This is line 1 " "this is line 2" "line 3" "A big line 4 like this")) ; (AHmakepara lst) ;;;;;;;;;;;;;;;;;;;;;; ; this allows for a time so message closes. (defun MsgBox (title options message time / WshShell) (setq WshShell (vlax-create-object "WScript.Shell")) (vlax-invoke WshShell 'Run (strcat "mshta.exe vbscript:close(CreateObject(\"WScript.Shell\").Popup(\"" message "\"," (itoa time) ",\"" title "\"," (itoa options)"))" ) ) (vlax-release-object WshShell) ) (MsgBox "this is me" 0 "have a good day" 1) ; pretty sure can do multi line, using \n or \r ? libre2.lsp1 point
-
1 point
-
Nice! I used Nanoflann for the python wrappers, Ge.Point2dTree, Ge.Point3dTree https://github.com/jlblancoc/nanoflann it builds the tree multi-threaded. Nanoflann can be made dynamic in that it can add or remove points, though I didn’t add that in to the python wrappers. I also created a wrapper for AutoLISP here https://github.com/CEXT-Dan/ads_geo Wrappers are limited though, in C++ you can create a payload I.e. { Point Data } Otherwise, you have to create a hashmap to link the point with the payload. A professional C# version might use an interface for X,Y,Z, so you can expand the tree to allow any class or structure that has the proper interface1 point
-
I am kind of a Green Horn when it comes to compiling. I don't even have vstudio. So I still use the legacy csc compiler. On top of that i only have access to acad 2017, so I am not aware of what would be needed to compile it for more recent version of Autocad.1 point
-
Yes outputting results as both may be the simplest way. Re make a dcl, I use say multi radio buttons.lsp as it only needs 3 lines of code to work, you comment out the vla-deletefile, so the dcl code remains, I then use the RLX convert dcl to lisp so paste the converted code into my programs, using the multi just saves typing to make the source dcl. Just another comment, I have a make a radio button dcl from a dwg. RLX was looking into doing similar. I have code also for Libreoffice Calc reading and writing plus more. Happy to post. Opening is not as straight forward as Excel. Where are the grand kids ? I am north of Sydney. Convert dcl 2 lisp rlx.lsp1 point
-
There can be a lot more to it than that. "A closed boundary could not be determined" when creating a hatch in AutoCAD It actually says for one option- "Zoom out until all boundaries are visible. Then specify a new pick point", but I have actually had to zoom way in. "Valid hatch boundary not found." when adding Hatches in AutoCAD Products Also AutoCAD has an issue sometimes Select Object works, even though you should be able to use Pick points. This is about Boundary, but affects Hatches as well... Read the entire thread. Also, you can read this thread, though also boundary related. So basically the issue, besides the obvious gaps, elevations, et al, is summed up by @eldon1 point
-
@SLW210 did a little bit of testing and works ok in Metric dwt. The only thing is the Architectural result. Limited Testing in Bricscad V25. made some shapes and inserted some blocks. A rectang 5000x4000 mm or decimal units. For metric don't need Architectural units. Curve length: 18000 Gaps: 0 Total: 18000 Architectural: 1500'-0" ?? For metric could do dwg is in mm but result is in metres to 3 decimals. You could use the Multi radio buttons.lsp to make choices. As its demand loaded you do not have to add it to your code. Re CSV your more than welcome to use the defuns in Alan Excel.lsp to write direct to Excel. Could demand load a lisp with just the defuns needed as don't need all that is in the lisp. Just a Ps a big file to screen copy maybe also post a file copy.1 point
-
1 point
-
I moved your thread to the AutoCAD 3D Modelling & Rendering Forum. Please start threads in the most appropriate forum.1 point
-
import wx import random from pyrx import Ap, Db, Ed, Gs class TestDialog(wx.Dialog): def __init__(self, parent, size, pos): wx.Dialog.__init__(self) self.Create(parent, wx.ID_ANY, "", pos, size, style=wx.BORDER_NONE) self.width = size.GetWidth() self.height = size.GetHeight() self.static_bitmap = None self.image = None self.raw_data = None self.offsets = [0] * self.width self.bg_r = 0 self.bg_g = 0 self.bg_b = 0 self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.on_melt_tick, self.timer) def setImage(self, img: wx.Image): self.image = img self.raw_data = bytearray(self.image.GetData()) if len(self.raw_data) >= 3: self.bg_r = self.raw_data[0] self.bg_g = self.raw_data[1] self.bg_b = self.raw_data[2] bmp = wx.Bitmap(self.image) if not self.static_bitmap: self.static_bitmap = wx.StaticBitmap(self, wx.ID_ANY, bmp, pos=(0, 0)) else: self.static_bitmap.SetBitmap(bmp) self.static_bitmap.Bind(wx.EVT_LEFT_DOWN, self.on_click) self.timer.Start(33) def on_melt_tick(self, event): stride = self.width * 3 melted_anything = False for x in range(self.width): if self.offsets[x] < self.height: increment = random.randint(2, 8) self.offsets[x] = min(self.height, self.offsets[x] + increment) melted_anything = True offset = self.offsets[x] if offset == 0: continue x_offset = x * 3 for y in range(self.height - 1, offset - 1, -1): target_idx = (y * stride) + x_offset source_idx = ((y - offset) * stride) + x_offset self.raw_data[target_idx] = self.raw_data[source_idx] self.raw_data[target_idx + 1] = self.raw_data[source_idx + 1] self.raw_data[target_idx + 2] = self.raw_data[source_idx + 2] for y in range(offset): bg_idx = (y * stride) + x_offset self.raw_data[bg_idx] = self.bg_r self.raw_data[bg_idx + 1] = self.bg_g self.raw_data[bg_idx + 2] = self.bg_b if not melted_anything: self.timer.Stop() return self.image.SetData(bytes(self.raw_data)) self.static_bitmap.SetBitmap(wx.Bitmap(self.image)) def on_click(self, event): self.timer.Stop() self.EndModal(wx.ID_OK) @Ap.Command() def doit(): doc = Ap.curDoc() db = doc.database() wxDoc: wx.Window = doc.getWxWindow() sz = wxDoc.GetSize() pos = wxDoc.GetScreenPosition() img: wx.Image = Gs.Core.getBlockImage(db.modelSpaceId(), sz.GetWidth(), sz.GetHeight(), 1.0) dlg = TestDialog(wxDoc, size=sz, pos=pos) dlg.setImage(img) dlg.ShowModal() dlg.Destroy()1 point
-
1 point
-
I forgot all about this thread, meant to get back to it. My apologies. Elmer FEM – open source multiphysical simulation software CALCULIX: A Three-Dimensional Structural Finite Elemente Program use with PrePoMax Structural Analysis & Steel Design Software | AutoCalcs Free Online 3D Structural Finite Element Analysis Software There are some more open-source and free programs out there. These have a free trial. Finite Element Analysis (FEA) Software | Autodesk Download Inventor | Inventor Free Trial | Autodesk FEA Simulation Basics | Autodesk Inventor 20231 point
-
1,045 downloads
;-------------------------------------------------; ; EDGENET ROUTINE - TWIN OF COMMAND EDGESURF ; ;-------------------------------------------------; ; Author : Marko Ribar, d.i.a. (architect) ; ; Copyright (C) - All rights reserved, 11.2019. ; ;-------------------------------------------------; ; You have permission to copy any part of code ; ; with guarantee that this header will be ; ; present in material that is modified or ; ; partly remained the same as in this routine ; ; version. If header is removed, you are ; ; responsible to mention author and link from ; ; where the code is publiced with explicit ; ; mark that material is copyrighted and is not ; ; for further distribution or selling or base ; ; for gaining any material or any other benefit ; ; than for learning and study and eventual ; ; improvement of its present functionality. ; ;-------------------------------------------------; edgenet-newest.lsp is routine that works similar to command EDGESURF... The difference between EDGESURF and EDGENET-NEWEST.LSP is that LSP version makes Polygon Mesh that is with softer and smaller magnitude lofting approximation... If you wish you can check several routines packed in ZIP and find the one you prefer... They are little slower than built-in EDGESURF, but nevertheless IMHO they are good examples of how this task can be solved from LISP perspective... As always I am opened for any input and your versions (if you have and willing to share)... Regards, Marko Ribar, d.i.a. (architect)1 point -
I don't think it was Excel you loaded the data to in the late 70's, perhaps Lotus 1-2-3 Per wikipediea "Microsoft originally marketed a spreadsheet program called Multiplan in 1982. Multiplan became very popular on CP/M systems, but on MS-DOS systems it lost popularity to Lotus 1-2-3. Microsoft released the first version of Excel for the Macintosh on September 30, 1985, and the first Windows version was 2.05 (to synchronize with the Macintosh version 2.2) in November 1987."1 point
