Jump to content

All Activity

This stream auto-updates

  1. Today
  2. I came up with it. If it could be completely rewritten, that would be great.
  3. SLW210

    xdrx

    I haven't seen the person that was posting here promoting that in a while, but you might try messaging them here or their website. @XDSoft
  4. I forgot to mention, for keeping up with the revisions we have Excel drawing lists with the Drawing names, dates and latest revision number on the network. P&IDs keep a dated track of each and every revision in cast things get put back to an older revision.
  5. From where did that LISP originate? Mandarin? Glancing through that LISP a little, I am almost positive the best way would be to completely write something new.
  6. Danielm103

    KDTree as a NET application.

    Well done, nice use of Parallel.For! Kdtree’s are definitely a must have in the CAD programmer’s tool box.
  7. ymg3

    KDTree as a NET application.

    @Danielm103 Well I did managed to scrape some milliseconds. However not where it counts in the pairing. Most of the gain in collection of entities. So in the end it is still gile's code. ymg Command: PAIRKD --------- TIMING ------------------------------- Collecting entities: 236 milliseconds Building kdTree: 67 milliseconds Pairing lines and texts: 34 milliseconds Coloring lines and texts: 123 milliseconds Total Elapsed Time: 460 milliseconds Total Number of Groups: 102 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Gile.AutoCAD.R20.Geometry; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application; [assembly: CommandClass(typeof(PairLinesWithTextsR17.Commands))] namespace PairLinesWithTextsR17 { public class Commands { private struct EntityPosition { public Entity Entity { get; } public Point3d Position { get; } public EntityPosition(Entity entity, Point3d position) { Entity = entity; Position = position; } } [CommandMethod("PAIRKD")] public void ParallelPairTextsWithLines3() { // Force GC collection prior to timing to avoid GC halts during execution GC.Collect(); GC.WaitForPendingFinalizers(); Stopwatch stopwatch = Stopwatch.StartNew(); Document doc = AcAp.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; RXClass lineClass = RXObject.GetClass(typeof(Line)); RXClass textClass = RXObject.GetClass(typeof(DBText)); // Pre-allocate generous capacity to prevent memory reallocations List<EntityPosition> midLines = new List<EntityPosition>(16384); List<EntityPosition> textList = new List<EntityPosition>(16384); using (doc.LockDocument()) using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead); ObjectId lineLayerId = lt.Has("1") ? lt["1"] : ObjectId.Null; ObjectId textLayerId = lt.Has("4") ? lt["4"] : ObjectId.Null; BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead); // 1. Fast Collection Phase foreach (ObjectId id in modelSpace) { RXClass rxClass = id.ObjectClass; if (rxClass == lineClass) { Line line = (Line)tr.GetObject(id, OpenMode.ForRead); if (line.LayerId == lineLayerId) { Point3d midPoint = new Point3d( (line.StartPoint.X + line.EndPoint.X) * 0.5, (line.StartPoint.Y + line.EndPoint.Y) * 0.5, (line.StartPoint.Z + line.EndPoint.Z) * 0.5 ); midLines.Add(new EntityPosition(line, midPoint)); } } else if (rxClass == textClass) { DBText text = (DBText)tr.GetObject(id, OpenMode.ForRead); if (text.LayerId == textLayerId) { Point3d pos = (text.Justify == AttachmentPoint.BaseLeft) ? text.Position : text.AlignmentPoint; textList.Add(new EntityPosition(text, pos)); } } } EntityPosition[][] textGroups = textList .GroupBy(t => ((DBText)t.Entity).TextString) .Select(g => g.ToArray()) .ToArray(); long t1 = stopwatch.ElapsedMilliseconds; // 2. KdTree Construction KdTree<EntityPosition> lineTree = new KdTree<EntityPosition>(midLines, ml => ml.Position, 2); long t2 = stopwatch.ElapsedMilliseconds; // 3. Parallel pairing (Math + Spatial Search) int numGroups = textGroups.Length; HashSet<Entity>[] uniqueGroupEntities = new HashSet<Entity>[numGroups]; Parallel.For(0, numGroups, i => { EntityPosition[] group = textGroups[i]; HashSet<Entity> uniqueSet = new HashSet<Entity>(group.Length * 2); for (int j = 0; j < group.Length; j++) { EntityPosition textItem = group[j]; uniqueSet.Add(textItem.Entity); Entity nearestLine = lineTree.GetNearestNeighbour(textItem.Position).Entity; uniqueSet.Add(nearestLine); } uniqueGroupEntities[i] = uniqueSet; }); long t3 = stopwatch.ElapsedMilliseconds; // 4. Sequential Database Modification Phase for (int i = 0; i < numGroups; i++) { int colorIndex = (i % 255) + 1; HashSet<Entity> uniqueSet = uniqueGroupEntities[i]; foreach (Entity entity in uniqueSet) { if (entity.ColorIndex != colorIndex) { if (!entity.IsWriteEnabled) { entity.UpgradeOpen(); } entity.ColorIndex = colorIndex; } } } long t4 = stopwatch.ElapsedMilliseconds; stopwatch.Stop(); ed.WriteMessage($"\n--------- TIMING -------------------------------"); ed.WriteMessage($"\nCollecting entities: {t1} milliseconds"); ed.WriteMessage($"\nBuilding kdTree: {t2 - t1} milliseconds"); ed.WriteMessage($"\nPairing lines and texts: {t3 - t2} milliseconds"); ed.WriteMessage($"\nColoring lines and texts: {t4 - t3} milliseconds\n"); ed.WriteMessage($"\nTotal Elapsed Time: {t4} milliseconds"); ed.WriteMessage($"\nTotal Number of Groups: {numGroups}"); tr.Commit(); } } } } pairkd.dll
  8. Thanks @SLW210 for editing. I couldn't figure out how to format the code, but now I know how!
  9. Yesterday
  10. Paul Li

    Error in Drawing file

    could you share your dwg?
  11. Likewise, we save a full copy of the as issued drawings, plus the PDF mark ups and check prints each in a separate folder. Unless specified otherwise all our files are suffixed with the revision code. Mark ups and check prints are in sequentially numbered and dated folders - so we can always go back. Typical folders: 1.0 Working Drawings 2.0 Check Prints - 2.1 Check Print 01-01-26 - 2.2 Check Print 15-03-26 3.0 Markups - 3.1 Markup 01-01-26 - 3.2 Markup 10 -03-26 4.0 Previous Versions And of course if there is a significant change between issues, I'll save the before and after away somewhere safe We usually issue PDFs during the project and if required the as-builts as dwgs right at the end I believe that the construction cloud saves each save as a new version whether it is a new revision or not
  12. Please use code tags in the future. (<> in the text editor) and please post the code formatted.
  13. Steven P

    Getting Error message on opening Cadtutor.

    Answer from another forum which is a bit more than my answer above - the errors are a kind of firewall to stop the Al bots scraping the websites, taking all the bandwidth, slowing things for the humans - something we'll have to live with for a while I think
  14. Paul Li

    Getting Error message on opening Cadtutor.

    usually after I click Try Again then it'll work..not sure why..
  15. Paul Li

    xdrx

    Perhaps you should contact the 3rd party vendor where you install this program from to get the file?
  16. ymg3

    KDTree as a NET application.

    @Danielm103, I did build gile's code to autocad 2017 and ran it testmore.dwg Results for PLWT_KDTREE: --------- TIMING------------------------------- Collecting entities: 315 milliseconds Building kdTree: 69 milliseconds Pairing lines and texts: 28 milliseconds Coloring lines and texts: 121 milliseconds Total Elapsed Time: 533 milliseconds Total Number of Colors: 102 colors With that kind of results, I don't see what I could improve on here. I am attaching the cs file converted for acad 2017 and Gile.AutoCAD.R20.Geometry ymg pairs.cs
  17. granat

    xdrx

    c:\program files (x86)\xdsoft\sys\xdrx.x64.25.arx cannot find a procedure that it needs.
  18. (defun ht:chars (s / l i n c a) (setq l '() i 1 n (strlen s) ) (while (<= i n) (setq c (substr s i 1) a (ascii c) ) (if (and a (> a 127) (< i n)) (setq l (cons (substr s i 2) l) i (+ i 2) ) (setq l (cons c l) i (1+ i) ) ) ) (reverse l) ) (defun ht:bbox (s hgt wf sty obl / e tb fallback) (setq fallback (list (list 0.0 0.0 0.0) (list 0.0 0.0 0.0))) (if (or (null s) (= s "")) fallback (progn (setq e (entmakex (append (list '(0 . "TEXT") '(100 . "AcDbEntity") '(100 . "AcDbText") '(10 0.0 0.0 0.0) (cons 40 hgt) (cons 1 s) (cons 41 wf) (cons 7 sty) '(72 . 0) '(73 . 0) ) (if obl (list (cons 51 obl)) nil ) (list (cons 11 '(0.0 0.0 0.0))) ) ) ) (if e (progn (setq tb (textbox (entget e))) (entdel e) (if (and tb (listp tb) (listp (car tb)) (listp (cadr tb))) tb fallback ) ) fallback ) ) ) ) (defun ht:wid (s hgt wf sty obl) (car (cadr (ht:bbox s hgt wf sty obl))) ) (defun ht:layout (chars hgt wf sty obl / prefix out result n i x0 x1 totalw) (setq prefix "" out '() ) (foreach ch chars (setq out (cons (list ch (- (ht:wid (strcat prefix ch) hgt wf sty obl) (ht:wid ch hgt wf sty obl) ) ) out ) ) (setq prefix (strcat prefix ch)) ) (setq out (reverse out) totalw (ht:wid prefix hgt wf sty obl) n (length out) i 0 result '() ) (while (< i n) (setq x0 (cadr (nth i out)) x1 (if (< i (1- n)) (cadr (nth (1+ i) out)) totalw ) ) (setq result (cons (list (car (nth i out)) x0 x1) result)) (setq i (1+ i)) ) (reverse result) ) (defun ht:origin (ed / g72 g73 rot x y cx cy tb mnx mxx mny mxy hgt) (setq g72 (cond ((cdr (assoc 72 ed))) (t 0) ) g73 (cond ((cdr (assoc 73 ed))) (t 0) ) rot (cond ((cdr (assoc 50 ed))) (t 0.0) ) hgt (cdr (assoc 40 ed)) ) (if (and (= g72 0) (= g73 0)) (setq x (car (cdr (assoc 10 ed))) y (cadr (cdr (assoc 10 ed))) ) (setq x (car (cdr (assoc 11 ed))) y (cadr (cdr (assoc 11 ed))) ) ) (setq tb (ht:bbox (cdr (assoc 1 ed)) hgt (cdr (assoc 41 ed)) (cdr (assoc 7 ed)) (cdr (assoc 51 ed)) ) mnx (car (car tb)) mxx (car (cadr tb)) mny (cadr (car tb)) mxy (cadr (cadr tb)) ) (setq cx (cond ((= g72 1) (/ (+ mnx mxx) 2.0)) ((= g72 2) mxx) ((= g72 3) 0.0) ((= g72 4) (/ (+ mnx mxx) 2.0)) ((= g72 5) mnx) (t mnx) ) cy (cond ((= g73 1) mny) ((= g73 2) (/ hgt 2.0)) ((= g73 3) hgt) (t 0.0) ) ) (list (- x (- (* cx (cos rot)) (* cy (sin rot)))) (- y (+ (* cx (sin rot)) (* cy (cos rot)))) ) ) (defun ht:proj (pt base ang) (+ (* (- (car pt) (car base)) (cos ang)) (* (- (cadr pt) (cadr base)) (sin ang)) ) ) (defun ht:paint (layout base ang hgt wf lay sty obl from to / out p) (setq out '()) (foreach item layout (if (and (< (nth 1 item) to) (> (nth 2 item) from)) (progn (setq p (list (+ (car base) (* (nth 1 item) (cos ang))) (+ (cadr base) (* (nth 1 item) (sin ang))) 0.0 ) ) (entmake (append (list '(0 . "TEXT") '(100 . "AcDbEntity") (cons 8 lay) '(100 . "AcDbText") (cons 10 p) (cons 40 hgt) (cons 1 (car item)) (cons 50 ang) (cons 41 wf) (cons 7 sty) (cons 62 1) '(72 . 0) '(73 . 0) ) (if obl (list (cons 51 obl)) nil ) (list (cons 11 p)) ) ) (setq out (cons (entlast) out)) ) ) ) out ) (defun ht:clear (lst) (if (listp lst) (foreach e lst (if (entget e) (entdel e) ) ) ) ) (defun ht:run (sel / hEnt ed txt hgt wf sty lay obl ang base anchor-s chars layout input running gr code data cur-s hl-a hl-b hl-from hl-to i new-lst new-txt echo-last last-a last-b ) (setq hEnt (car sel) ed (entget hEnt) ) (if (/= "TEXT" (cdr (assoc 0 ed))) (princ "\n not a text") (progn (setq txt (cdr (assoc 1 ed)) hgt (cdr (assoc 40 ed)) wf (cond ((cdr (assoc 41 ed))) (t 1.0) ) sty (cond ((cdr (assoc 7 ed))) (t "Standard") ) lay (cdr (assoc 8 ed)) obl (cdr (assoc 51 ed)) ang (cond ((cdr (assoc 50 ed))) (t 0.0) ) base (ht:origin ed) anchor-s (ht:proj (cadr sel) base ang) chars (ht:chars txt) layout (ht:layout chars hgt wf sty obl) ) (princ "\n move mouse to change text") (setq running T input "" echo-last 0 *ht-tmp* '() last-a nil last-b nil ) (while running (setq gr (grread T 13) code (car gr) data (cadr gr) ) (cond ((= code 5) (setq cur-s (ht:proj data base ang) hl-from (min anchor-s cur-s) hl-to (max anchor-s cur-s) hl-a nil hl-b nil i 0 ) (foreach item layout (if (and (< (nth 1 item) hl-to) (> (nth 2 item) hl-from)) (progn (if (null hl-a) (setq hl-a i) ) (setq hl-b i) ) ) (setq i (1+ i)) ) (if (or (/= hl-a last-a) (/= hl-b last-b)) (progn (ht:clear *ht-tmp*) (setq *ht-tmp* (if hl-a (ht:paint layout base ang hgt wf lay sty obl hl-from hl-to ) '() ) ) (setq last-a hl-a last-b hl-b ) ) ) ) ((= code 2) (cond ((member data '(13 32)) (if (null hl-a) (princ "\n No char to hightlight") (progn (setq i 0 new-lst '() ) (foreach ch chars (cond ((< i hl-a) (setq new-lst (cons ch new-lst))) ((= i hl-a) (if (> (strlen input) 0) (foreach nc (ht:chars input) (setq new-lst (cons nc new-lst)) ) ) ) ((> i hl-b) (setq new-lst (cons ch new-lst))) (t nil) ) (setq i (1+ i)) ) (setq new-txt (apply 'strcat (reverse new-lst))) (if (= new-txt "") (setq new-txt " ") ) (entmod (subst (cons 1 new-txt) (assoc 1 ed) ed)) (entupd hEnt) (princ (strcat "\n Result: " new-txt)) ) ) (setq running nil) ) ((= data 8) (if (> (strlen input) 0) (setq input (substr input 1 (1- (strlen input)))) ) ) ((= data 27) (setq running nil)) ((and (>= data 32) (< data 127)) (setq input (strcat input (chr data))) ) ) (if running (progn (princ (strcat "\r Input: " input)) (if (< (strlen input) echo-last) (princ (make-string (- echo-last (strlen input)) 32)) ) (setq echo-last (strlen input)) ) ) ) ((member code '(3 11 25)) (setq running nil)) ) ) (princ) ) ) ) (defun c:HTEXT (/ sel res) (setq sel (entsel "\n select a text <exit>: ")) (if (null sel) (princ "\n nothing selected") (progn (setq *ht-tmp* '()) (setq res (vl-catch-all-apply 'ht:run (list sel))) (ht:clear *ht-tmp*) (setq *ht-tmp* nil) (if (vl-catch-all-error-p res) (princ (strcat "\n error: " (vl-catch-all-error-message res)) ) (terpri) ) ) ) (princ) )
  19. Last week
  20. Danielm103

    KDTree as a NET application.

    this was a fun challenge using KDTrees https://www.theswamp.org/index.php?topic=59487.0
  21. Like others if a revision then a dwg was saved. We also saved a "AS Built" dwg, all our dwg's were recorded and could be looked up, we went back to 1999. They were saved as Tiffs later on as Pdf's. As we controlled the dwg's in regards to access by others, server locked, we made sure only the latest version was in the current working directory, we had a superseded directory. As part of document control a new project had specific directories premade.
  22. ymg3

    KDTree as a NET application.

    @gile, Here I build a bridge to your GeometryExtensions.NET library, exposing essentially the same command that I had in mine . The only addition being GC:KD-MINNODE. I have also built a concavehull in C# using your kd-tree if anybody is interested. ymg using System; using System.IO; using System.Linq; using System.Globalization; using System.Collections.Generic; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Gile.AutoCAD.R20.Geometry; namespace LispGileBridge { public class ExtensionLoader : IExtensionApplication { public void Initialize() { try { var ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; // Extracts the absolute running file path dynamically via Reflection string assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location; string assemblyName = System.IO.Path.GetFileName(assemblyPath); ed.WriteMessage($"\n--> Assembly File Loaded: \"{assemblyName}\""); ed.WriteMessage($"\n--> Full Path: {assemblyPath}"); ed.WriteMessage("\n--> Available commands:"); ed.WriteMessage("\n (GC:KD-BUILD pointList [dimensions] [customHandle])"); ed.WriteMessage("\n (GC:KD-NEAREST handle Point [count] [maxRadius] [sortFlag])"); ed.WriteMessage("\n (GC:KD-NEAREST-INFO handle Point [count] [maxRadius])"); ed.WriteMessage("\n (GC:KD-RANGE handle Point radius)"); ed.WriteMessage("\n (GC:KD-MINNODE handle dimension)"); ed.WriteMessage("\n (GC:KD-FREE [handle])"); } catch { // Fallback safety silent escape check } } public void Terminate() { } } public class KdTreeBridge { // Thread-safe dictionary tracking string handles to their specific tree instances and properties private static readonly Dictionary<string, (Point3dTree Tree, bool Is2D)> _registry = new Dictionary<string, (Point3dTree, bool)>(StringComparer.OrdinalIgnoreCase); private static int _autoId = 1; // -------------------------------------------------------------------------------- // 1. (gc:kd-build pointList [dimensions] [customHandle]) // -------------------------------------------------------------------------------- [LispFunction("GC:KD-BUILD")] public static object GileKdBuild(ResultBuffer args) { if (args == null) return null; TypedValue[] arr = args.AsArray(); if (arr.Length == 0) return null; try { List<Point3d> pts = ParseLispPoints(arr, 0, out int pointsReadCount); if (pts.Count == 0) return null; // Default dimension to 2D unless explicitly specified as 3 int dimensions = 2; string customHandle = null; if (arr.Length > pointsReadCount) { int nextIdx = pointsReadCount; if (arr[nextIdx].TypeCode == (int)LispDataType.Int32 || arr[nextIdx].TypeCode == (int)LispDataType.Int16) { dimensions = Convert.ToInt32(arr[nextIdx].Value); nextIdx++; } if (arr.Length > nextIdx && arr[nextIdx].TypeCode == (int)LispDataType.Text) { customHandle = Convert.ToString(arr[nextIdx].Value); } } bool is2D = (dimensions == 2); // Gilles' constructor: ignoreZ parameter directly matches our is2D rule Point3dTree tree = new Point3dTree(pts, is2D); string handle = string.IsNullOrEmpty(customHandle) ? $"<KD-TREE-{_autoId++}>" : customHandle; _registry[handle] = (tree, is2D); return handle; } catch (System.Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\nError in KD-BUILD: {ex.Message}\n"); return null; } } // -------------------------------------------------------------------------------- // 2. (gc:kd-nearest handle targetPoint [count] [maxRadius] [sortFlag]) // -------------------------------------------------------------------------------- [LispFunction("GC:KD-NEAREST")] public static object GileKdNearest(ResultBuffer args) { if (args == null) return null; TypedValue[] arr = args.AsArray(); if (arr.Length < 2) return null; try { string handle = Convert.ToString(arr[0].Value); if (!_registry.TryGetValue(handle, out var entry)) return null; if (arr[1].TypeCode != (int)LispDataType.Point3d) return null; Point3d targetPt = (Point3d)arr[1].Value; int count = 1; double maxRadius = double.MaxValue; int sortFlag = 1; // Default: Sort by Angle if (arr.Length >= 3) count = Convert.ToInt32(arr[2].Value); if (arr.Length >= 4) maxRadius = Convert.ToDouble(arr[3].Value); if (arr.Length >= 5) sortFlag = Convert.ToInt32(arr[4].Value); var searchCollection = entry.Tree.GetNearestNeighbours(targetPt, count); if (searchCollection == null) return null; // Filter by radius limit and compile working list List<Point3d> filtered = new List<Point3d>(); foreach (Point3d pt in searchCollection) { double dist = entry.Is2D ? targetPt.DistanceTo(new Point3d(pt.X, pt.Y, targetPt.Z)) : targetPt.DistanceTo(pt); if (dist <= maxRadius) filtered.Add(pt); } if (filtered.Count == 0) return null; // Execute selected Sort mode if (sortFlag == 0) { filtered = filtered.OrderBy(p => entry.Is2D ? targetPt.DistanceTo(new Point3d(p.X, p.Y, targetPt.Z)) : targetPt.DistanceTo(p)).ToList(); } else { filtered = filtered.OrderBy(p => { double angle = Math.Atan2(p.Y - targetPt.Y, p.X - targetPt.X); return angle < 0 ? angle + (2 * Math.PI) : angle; }).ToList(); } // API Standard Rule Check: If count is 1, return single item. Else, return list. if (count == 1) { return filtered[0]; } ResultBuffer rb = new ResultBuffer(); rb.Add(new TypedValue((int)LispDataType.ListBegin)); foreach (Point3d pt in filtered) rb.Add(new TypedValue((int)LispDataType.Point3d, pt)); rb.Add(new TypedValue((int)LispDataType.ListEnd)); return rb; } catch { return null; } } // -------------------------------------------------------------------------------- // 3. (gc:kd-nearest-info handle targetPoint [count] [maxRadius]) // -------------------------------------------------------------------------------- [LispFunction("GC:KD-NEAREST-INFO")] public static object GileKdNearestInfo(ResultBuffer args) { if (args == null) return null; TypedValue[] arr = args.AsArray(); if (arr.Length < 2) return null; try { string handle = Convert.ToString(arr[0].Value); if (!_registry.TryGetValue(handle, out var entry)) return null; Point3d targetPt = (Point3d)arr[1].Value; int count = 1; double maxRadius = double.MaxValue; if (arr.Length >= 3) count = Convert.ToInt32(arr[2].Value); if (arr.Length >= 4) maxRadius = Convert.ToDouble(arr[3].Value); var searchCollection = entry.Tree.GetNearestNeighbours(targetPt, count); if (searchCollection == null) return null; ResultBuffer rb = new ResultBuffer(); rb.Add(new TypedValue((int)LispDataType.ListBegin)); // Re-locate matches to extract array index mappings cleanly int idx = 0; foreach (Point3d pt in searchCollection) { double dist = entry.Is2D ? targetPt.DistanceTo(new Point3d(pt.X, pt.Y, targetPt.Z)) : targetPt.DistanceTo(pt); if (dist <= maxRadius) { rb.Add(new TypedValue((int)LispDataType.ListBegin)); rb.Add(new TypedValue((int)LispDataType.Point3d, pt)); rb.Add(new TypedValue((int)LispDataType.Int32, idx)); // Metadata index placement rb.Add(new TypedValue((int)LispDataType.Double, dist)); rb.Add(new TypedValue((int)LispDataType.ListEnd)); } idx++; } rb.Add(new TypedValue((int)LispDataType.ListEnd)); return rb; } catch { return null; } } // -------------------------------------------------------------------------------- // 4. (gc:kd-range handle centerPoint radius) // -------------------------------------------------------------------------------- [LispFunction("GC:KD_RANGE")] public static object GileKdRange(ResultBuffer args) { if (args == null) return null; TypedValue[] arr = args.AsArray(); if (arr.Length < 3) return null; try { string handle = Convert.ToString(arr[0].Value); if (!_registry.TryGetValue(handle, out var entry)) return null; Point3d centerPt = (Point3d)arr[1].Value; double radius = Convert.ToDouble(arr[2].Value); // Passing a double directly to GetNearestNeighbours switches Gilles' engine to range search var searchCollection = entry.Tree.GetNearestNeighbours(centerPt, radius); if (searchCollection == null) return null; // Enforce distance sort ordering var sorted = searchCollection.OrderBy(p => entry.Is2D ? centerPt.DistanceTo(new Point3d(p.X, p.Y, centerPt.Z)) : centerPt.DistanceTo(p)).ToList(); ResultBuffer rb = new ResultBuffer(); rb.Add(new TypedValue((int)LispDataType.ListBegin)); foreach (Point3d pt in sorted) rb.Add(new TypedValue((int)LispDataType.Point3d, pt)); rb.Add(new TypedValue((int)LispDataType.ListEnd)); return rb; } catch { return null; } } // -------------------------------------------------------------------------------- // 5. NEW! (gc:kd-minnode handle dimension) -> Useful for Concave Hull base logic // -------------------------------------------------------------------------------- [LispFunction("GC:KD-MINNODE")] public static object GileKdMinNode(ResultBuffer args) { if (args == null) return null; TypedValue[] arr = args.AsArray(); if (arr.Length < 2) return null; try { string handle = Convert.ToString(arr[0].Value); if (!_registry.TryGetValue(handle, out var entry)) return null; int dimension = Convert.ToInt32(arr[1].Value); // 0=X, 1=Y, 2=Z // Target standard range query over all nodes to run aggregate matching var allPoints = entry.Tree.GetNearestNeighbours(Point3d.Origin, double.MaxValue); if (allPoints == null || !allPoints.Any()) return null; Point3d minPoint; switch (dimension) { case 0: // Minimum X coordinate minPoint = allPoints.OrderBy(p => p.X).First(); break; case 1: // Minimum Y coordinate minPoint = allPoints.OrderBy(p => p.Y).First(); break; case 2: // Minimum Z coordinate minPoint = allPoints.OrderBy(p => p.Z).First(); break; default: return null; } return minPoint; } catch { return null; } } // -------------------------------------------------------------------------------- // 6. (gc:kd-free [handle]) // -------------------------------------------------------------------------------- [LispFunction("GC:KD-FREE")] public static object GileKdFree(ResultBuffer args) { int removedCount = 0; if (args == null) { removedCount = _registry.Count; _registry.Clear(); _autoId = 1; } else { TypedValue[] arr = args.AsArray(); if (arr.Length > 0 && arr[0].TypeCode == (int)LispDataType.Text) { string handle = Convert.ToString(arr[0].Value); if (_registry.Remove(handle)) removedCount = 1; } else { removedCount = _registry.Count; _registry.Clear(); _autoId = 1; } } GC.Collect(); GC.WaitForPendingFinalizers(); return removedCount; } // -------------------------------------------------------------------------------- // INTERNAL ROUTINE: Streamlined input coordinate list extractor // -------------------------------------------------------------------------------- private static List<Point3d> ParseLispPoints(TypedValue[] arr, int startIndex, out int readCount) { var collected = new List<Point3d>(); readCount = 0; for (int i = startIndex; i < arr.Length; i++) { if (arr[i].Value is Point3d pt) { collected.Add(pt); readCount++; } else if (arr[i].TypeCode == (int)LispDataType.ListEnd || arr[i].TypeCode == (int)LispDataType.Int32 || arr[i].TypeCode == (int)LispDataType.Text) { break; // Stopped at non-point parameter boundaries } } return collected; } } } essentially the same command that I had in my post.
  23. If you want to learn to do that method... Making a POP with images for inserting blocks or running a program - Autodesk Community
  24. Like @CyberAngel, different places do it different. My current work place, for the work I do, I keep all copies (even those I never released) on a personal (company) cloud drive, the latest revision is the one posted on the network, the drawing name includes the revision number at the end. In most cases, the relevant personnel are emailed that a new revision is out, since one or more of them would have requested a change. P&IDs we keep the old revisions in a separate folder on the network and sometimes the same for certain projects. For contractor drawings I also put old drawings in a folder and only leave the latest revisions on the network. For ongoing projects my boss usually keeps everything in a project folder and then at the end the "As Built" goes on the network, "As Built" as in I usually (or my boss/both of us and/or a relevant engineer) have to go double check everything. Other places I have done them pretty much every method CyberAngel mentioned and probably more, as each company and even sometimes different divisions in a company wanted them done "their way".
  25. This is one of the knottiest issues in engineering work. What constitutes a full revision? When do you issue a partial revision, if you do at all? How do you track the changes? How do you roll them back if necessary? Worst of all, different shops use different criteria, and sometimes the same shop uses different criteria for different projects. It seems like common sense, since storage is so cheap these days, to save a new copy of the drawing for each revision, and append the revision number to the file name. That way the old revisions are still available if you need to refer to them or send them to someone. Even better, keep the revisions in a subfolder so they don't clutter up the main project folder. And this should go without saying--keep current backups! The current working file should have the project name (or whatever) with no revision number. Again, though, some shops will use different standards. For smaller projects, there's no need to keep old revisions, especially if you've sent them out all along. You can go back to those emails for attached copies of old drawings. As always, simpler is better. Make a plan and stick to it. Otherwise you're asking for trouble.
  26. P.S. I meant to mention this in my first response. Your title states... And then you state... You can use an AutoCAD command JOIN... JOIN (Command) | Autodesk In many situations a much better tool. You can experiment with what happens with different combinations or look through the link above.
  27. What if you need different elevations, but still need continuous linework? Flattening the entire drawing would be an issue. This would be a good time to use Qselect (or filters, LISP, et al) to select by Elevation, etc. and Join the polylines, lines, etc. Once again Overkill to remove overlaps, though a custom LISP for it all would be better most likely. As mentioned, having all of that in a drawing should be from untrained cad users and/or poor third party software importing, etc.
  28. I recently worked on a project where every revision was saved as a completely separate DWG file. After a few revisions, it became difficult to know which file was the latest one. A simpler approach is to keep the working DWG as the main file and use DWGPROPS to record revision information such as the revision number, date, and description. For issued drawings, I also keep a clear revision naming convention rather than relying only on the filename. This makes it much easier to identify the current drawing and understand its history. How do you normally manage DWG revisions on larger projects?
  1. Load more activity
×
×
  • Create New...