Recent Posts

Pages: 1 2 [3] 4 5 ... 10
21
Math and Geometry / Re: K-d Tree for AutoCAD Point3d
« Last post by (gile) on June 17, 2013, 06:24:41 PM »
Here's the F# version.

The main interest is that it allows parallel execution for building the tree while targeting the Framwork 2.0 so that it can be used with AutoCAD version from 2007 to 2011.

The F# specific constructs and types are only used internally.
The public methods (the same as in the C# version) are writen to be used with other .NET languages (C# or VB) they return Point3d arrays rather than Point3dCollections. A 'Pair' type (class) is used to replace the missing Tuple class in .NET Frameworks prior to 4.0.

The FsPoint3dTree.dll which can be referenced in C# or VB projects (it may be needed to install the F# runtime).

Code: [Select]
    namespace Gile.Point3dTree
     
    open System
    open Autodesk.AutoCAD.Geometry
     
    module private Array =
       let median (compare: 'a -> 'a -> int) (items: 'a[])=
           if items = null || items.Length = 0 then
               failwith "items"
           let l = items.Length
           let k = l / 2
     
           let rec loop f t =
               if f < t then swap f t items.[(f+t) / 2] f t
               else items.[.. k-1], items.[k], items.[k+1 ..]
           and swap a b c f t =
               if a < b then
                   if compare items.[a] c > -1 then
                       let tmp = items.[b]
                       items.[b] <- items.[a]
                       items.[a] <- tmp
                       swap a (b-1) c f t
                   else
                       swap (a+1) b c f t
               else
                   let n = if compare items.[a] c > 0 then a - 1 else a
                   if k <= n
                   then loop f n
                   else loop (n+1) t
     
           loop 0 (l-1)
     
    type private TreeNode =
       | Empty
       | Node of int * Point3d option * Point3d * TreeNode * TreeNode 
     
    /// <summary>
    /// Defines a tuple (double) to be used with versions of .NET Framework prior to 4.0
    /// </summary>
    /// <typeparam name="T1">Type of the first item.</typeparam>
    /// <typeparam name="T2">Type of the second item.</typeparam>
    /// <param name="item1">First item.</param>
    /// <param name="item2">Second item.</param>
    type Pair<'T1, 'T2>(item1, item2) =
     
       /// <summary>
       /// Gets the first item of the pair.
       /// </summary>
       member this.Item1 with get() = item1
     
       /// <summary>
       /// Gets the second item of the pair.
       /// </summary>
       member this.Item2 with get() = item2
     
       /// <summary>
       /// Creates a new instance of Pair.
       /// </summary>
       /// <param name="item1">First item of the pair.</param>
       /// <param name="item2">Second item of the pair.</param>
       /// <returns>a new Pair containing the items.</returns>
       static member Create(item1, item2) = Pair(item1, item2)
     
     
    /// <summary>
    /// Creates an new instance of Point3dTree.
    /// </summary>
    /// <param name="points">The Point3d collection to fill the tree.</param>
    /// <param name="ignoreZ">A value indicating if the Z coordinate of points is ignored
    /// (as if all points were projected to the XY plane).</param>
    type Point3dTree (points: Point3d seq, ignoreZ: bool) =
       do if points = null then raise (System.ArgumentNullException("points"))
     
       let dimension = if ignoreZ then 2 else 3
       let sqrDist (p1: Point3d) (p2: Point3d) =
           if ignoreZ
           then (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y)
           else (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y) + (p1.Z - p2.Z) * (p1.Z - p2.Z)
     
       let rec shift n d =
           if n >>> d > 1 then shift n (d+1) else d
       let pDepth = shift System.Environment.ProcessorCount 0
     
       let create pts =
           let rec loop depth parent = function
               | [||] -> Empty
               | pts ->
                   let d = depth % dimension
                   let left, median, right =
                       pts |> Array.median(fun (p1: Point3d) p2 -> compare p1.[d] p2.[d])
                   let children =
                       if depth < pDepth then
                           [ async { return loop (depth + 1) (Some(median)) left };
                             async { return loop (depth + 1) (Some(median)) right } ]
                           |> Async.Parallel
                           |> Async.RunSynchronously
                       else
                           [| loop (depth + 1) (Some(median)) left;
                              loop (depth + 1) (Some(median)) right |]
                   Node(depth, parent, median, children.[0], children.[1])
           loop 0 None pts
     
       let root = points |> Seq.distinct |> Seq.toArray |> create
     
       let rec findNeighbour location node (current, bestDist) =
           match node with
           | Empty -> (current, bestDist)
           | Node(depth, _, point, left, right) ->
               let dist = sqrDist point location
               let d = depth % dimension
               let bestPair =
                   if dist < bestDist
                   then point, dist
                   else current, bestDist
               if bestDist < (location.[d] - point.[d]) * (location.[d] - point.[d]) then
                   findNeighbour location (if location.[d] < point.[d] then left else right) bestPair
               else
                   findNeighbour location left bestPair
                   |> findNeighbour location right
     
       let rec getNeighbours center radius node acc =
           match node with
           | Empty -> acc
           | Node(depth, _, point, left, right) ->
               let acc = if sqrDist center point <= radius then point :: acc else acc
               let d= depth % dimension;
               let coordCen, coordPt = center.[d], point.[d]
               if (coordCen - coordPt) * (coordCen - coordPt) > radius then
                   getNeighbours center radius (if coordCen < coordPt then left else right) acc
               else
                   getNeighbours center radius left acc
                   |> getNeighbours center radius right
     
       let rec getKNeighbours center number node (pairs: (float * Point3d) list) =
           match node with
           | Empty -> pairs
           | Node(depth, _, point, left, right) ->
               let dist = sqrDist center point
               let pairs =
                   match pairs.Length with
                   | 0 -> [ (dist, point) ]
                   | l when l < number ->
                       if (dist > fst pairs.Head)
                       then (dist, point) :: pairs
                       else pairs.Head :: (dist, point) :: pairs.Tail
                   | _ ->
                       if dist < fst pairs.Head
                       then ((dist, point) :: pairs.Tail) |> List.sortBy(fun p -> -fst p)
                       else pairs
               let d = depth % dimension
               let coordCen, coordCur = center.[d], point.[d]
               if (coordCen - coordCur) * (coordCen - coordCur) > fst pairs.Head then
                   getKNeighbours center number (if coordCen < coordCur then left else right) pairs
               else
                   getKNeighbours center number left pairs
                   |> getKNeighbours center number right
     
       let rec findRange (lowerLeft: Point3d) (upperRight: Point3d) node (acc: Point3d list) =
           match node with
           | Empty -> acc
           | Node(depth, _, point, left, right) ->
               let acc =
                   if ignoreZ then
                       if point.X >= lowerLeft.X && point.X <= upperRight.X &&
                          point.Y >= lowerLeft.Y && point.Y <= upperRight.Y
                       then point :: acc else acc
                   else
                       if point.X >= lowerLeft.X && point.X <= upperRight.X &&
                          point.Y >= lowerLeft.Y && point.Y <= upperRight.Y &&
                          point.Z >= lowerLeft.Z && point.Z <= upperRight.Z
                       then point :: acc else acc
               let d = depth % dimension
               if upperRight.[d] < point.[d]
               then findRange lowerLeft upperRight left acc
               elif lowerLeft.[d] > point.[d]
               then findRange lowerLeft upperRight right acc
               else findRange lowerLeft upperRight left acc
                    |> findRange lowerLeft upperRight right
     
       let rec getConnexions node radius (nodes, pairs) =
           match node with
           | Empty -> (nodes, pairs)
           | Node(depth, parent, point, left, right) ->
               let pairs =
                   nodes
                   |> List.fold(fun acc (n: TreeNode) ->
                       match n with
                       | Empty -> acc
                       | Node(dep, par, _, _, _) ->
                           let pt = par.Value
                           let d = (dep + 1) % dimension
                           if (point.[d] - pt.[d]) * (point.[d] - pt.[d]) <= radius
                           then getNeighbours point radius n acc
                           else acc)
                       (getNeighbours point radius left []
                       |> getNeighbours point radius right)
                   |> List.map(fun p -> Pair<Point3d, Point3d>(point, p))
                   |> List.fold(fun acc p -> p :: acc) pairs
               let nodes =
                   match nodes with
                   | [] -> if right = Empty then [] else [right]
                   | h :: t  ->
                       if right = Empty
                       then if left = Empty then t else nodes
                       else right :: nodes
               getConnexions left radius (nodes, pairs)
               |> getConnexions right radius           
     
       /// <summary>
       /// Creates an new instance of Point3dTree with ignoreZ = false (default).
       /// </summary>
       /// <param name="points">The Point3d collection to fill the tree.</param>
       new (points: Point3d seq) = Point3dTree(points, false)
     
       /// <summary>
       /// Gets the nearest neighbour.
       /// </summary>
       /// <param name="point">The point from which search the nearest neighbour.</param>
       /// <returns>The nearest point in the collection from the specified one.</returns>
       member this.NearestNeighbour(location) =
           match root with
           | Empty -> raise (System.ArgumentNullException("root"))
           | Node(_, _, point, _, _) ->
               findNeighbour location root (point, Double.MaxValue)
               |> fst
     
       /// <summary>
       /// Gets the neighbours within the specified distance.
       /// </summary>
       /// <param name="point">The point from which search the nearest neighbours.</param>
       /// <param name="radius">The distance in which collect the neighbours.</param>
       /// <returns>The points which distance from the specified point is less or equal to the specified distance.</returns>
       member this.NearestNeighbours(center, radius) =
           getNeighbours center (radius * radius) root []
           |> List.toArray
     
       /// <summary>
       /// Gets the given number of nearest neighbours.
       /// </summary>
       /// <param name="point">The point from which search the nearest neighbours.</param>
       /// <param name="number">The number of points to collect.</param>
       /// <returns>The n nearest neighbours of the specified point.</returns>
       member this.NearestNeighbours(center, number) =
           getKNeighbours center number root []
           |> List.map(fun p -> snd p)
           |> List.toArray
     
       /// <summary>
       /// Gets the points in a range.
       /// </summary>
       /// <param name="pt1">The first corner of range.</param>
       /// <param name="pt2">The opposite corner of the range.</param>
       /// <returns>All points within the box.</returns>
       member this.BoxedRange(pt1: Point3d, pt2: Point3d) =
           let lowerLeft = Point3d(min pt1.X pt2.X, min pt1.Y pt2.Y, min pt1.Z pt2.Z)
           let upperRight = Point3d(max pt1.X pt2.X, max pt1.Y pt2.Y, max pt1.Z pt2.Z)
           findRange lowerLeft upperRight root []
           |> List.toArray
     
       /// <summary>
       /// Gets all the pairs of points which distance is less or equal than the specified distance.
       /// </summary>
       /// <param name="radius">The maximum distance between two points. </param>
       /// <returns>The pairs of points which distance is less or equal than the specified distance.</returns>
       member this.ConnectAll(radius) =
           getConnexions root (radius * radius) ([], [])
           |> snd
           |> List.toArray
22
Math and Geometry / K-d Tree for AutoCAD Point3d
« Last post by (gile) on June 17, 2013, 06:03:20 PM »
Hi

This is more related to 'Data Structure' than 'Geometry' but I didn't know where to post it.

This class may be used to improve performances in case of many queries in a quite large amount of points (see here).
It targets the Framwork 4.0 to use some parallelization features.

According to the value of the 'ignoreZ' constructor argument, the resulting tree is a 2d tree (ignoreZ = true) or a 3d tree (ignoreZ = false, default).
Use ignoreZ = true if all points in the input collection lie on a plane parallel to XY or if the points have to be considered as projected on the XY plane.

The Point3dTree public methods:
NearestNeighbour(Point3d) Gets the nearest neighbour.
NearestNeighbours(Point3d, int) Gets the n nearest neighbours.
NearestNeighbours(Point3d, double) Gets the nearest neighbours within the distance.
BoxedRange(Point3d, Point3d) Gets the points in a range.
ConnectAll(double) Gets all the pairs of points which distance is less or equal than the specified distance.
The last one was was almost used for performance tests (and to reply to this challenge).

Code: [Select]
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Autodesk.AutoCAD.Geometry;
     
    namespace PointKdTree
    {
       /// <summary>
       /// Node of a Point3dTree
       /// </summary>
       public class TreeNode
       {
           /// <summary>
           /// Creates a new instance of TreeNode
           /// </summary>
           /// <param name="value">The 3d point value of the node.</param>
           public TreeNode(Point3d value) { this.Value = value; }
     
           /// <summary>
           /// Gets the value (Point3d) of the node.
           /// </summary>
           public Point3d Value { get; internal set; }
     
           /// <summary>
           /// Gets the parent node.
           /// </summary>
           public TreeNode Parent { get; internal set; }
     
           /// <summary>
           /// Gets the left child node.
           /// </summary>
           public TreeNode LeftChild { get; internal set; }
     
           /// <summary>
           /// Gets the right child node.
           /// </summary>
           public TreeNode RightChild { get; internal set; }
     
           /// <summary>
           /// Gets the depth of the node in tree.
           /// </summary>
           public int Depth { get; internal set; }
     
           /// <summary>
           /// Gets a value indicating if the current node is a LeftChild node.
           /// </summary>
           public bool IsLeft { get; internal set; }
       }
     
       /// <summary>
       /// Provides methods to organize 3d points in a Kd tree structure to speed up the search of neighbours.
       /// A boolean constructor parameter (ignoreZ) indicates if the resulting Kd tree is a 3d tree or a 2d tree.
       /// Use ignoreZ = true if all points in the input collection lie on a plane parallel to XY
       /// or if the points have to be considered as projected on the XY plane.
       /// </summary>
       public class Point3dTree
       {
           #region Private fields
     
           private int dimension;
           private int parallelDepth;
           private bool ignoreZ;
           private Func<Point3d, Point3d, double> sqrDist;
     
           #endregion
     
           #region Constructor
     
           /// <summary>
           /// Creates an new instance of Point3dTree.
           /// </summary>
           /// <param name="points">The Point3d collection to fill the tree.</param>
           /// <param name="ignoreZ">A value indicating if the Z coordinate of points is ignored
           /// (as if all points were projected to the XY plane).</param>
           public Point3dTree(IEnumerable<Point3d> points, bool ignoreZ = false)
           {
               if (points == null)
                   throw new ArgumentNullException("points");
               this.ignoreZ = ignoreZ;
               this.dimension = ignoreZ ? 2 : 3;
               if (ignoreZ)
                   this.sqrDist = SqrDistance2d;
               else
                   this.sqrDist = SqrDistance3d;
               int numProc = System.Environment.ProcessorCount;
               this.parallelDepth = -1;
               while (numProc >> ++this.parallelDepth > 1) ;
               Point3d[] pts = points.Distinct().ToArray();
               this.Root = Create(pts, 0, null, false);
           }
     
           #endregion
     
           #region Public properties
     
           /// <summary>
           /// Gets the root node of the tree.
           /// </summary>
           public TreeNode Root { get; private set; }
     
           #endregion
     
           #region Public methods
     
           /// <summary>
           /// Gets the nearest neighbour.
           /// </summary>
           /// <param name="point">The point from which search the nearest neighbour.</param>
           /// <returns>The nearest point in the collection from the specified one.</returns>
           public Point3d NearestNeighbour(Point3d point)
           {
               return GetNeighbour(point, this.Root, this.Root.Value, double.MaxValue);
           }
     
           /// <summary>
           /// Gets the neighbours within the specified distance.
           /// </summary>
           /// <param name="point">The point from which search the nearest neighbours.</param>
           /// <param name="radius">The distance in which collect the neighbours.</param>
           /// <returns>The points which distance from the specified point is less or equal to the specified distance.</returns>
           public Point3dCollection NearestNeighbours(Point3d point, double radius)
           {
               Point3dCollection points = new Point3dCollection();
               GetNeighboursAtDistance(point, radius * radius, this.Root, points);
               return points;
           }
     
           /// <summary>
           /// Gets the given number of nearest neighbours.
           /// </summary>
           /// <param name="point">The point from which search the nearest neighbours.</param>
           /// <param name="number">The number of points to collect.</param>
           /// <returns>The n nearest neighbours of the specified point.</returns>
           public Point3dCollection NearestNeighbours(Point3d point, int number)
           {
               List<Tuple<double, Point3d>> pairs = new List<Tuple<double, Point3d>>(number);
               GetKNeighbours(point, number, this.Root, pairs);
               Point3dCollection points = new Point3dCollection();
               for (int i = 0; i < pairs.Count; i++)
               {
                   points.Add(pairs[i].Item2);
               }
               return points;
           }
     
           /// <summary>
           /// Gets the points in a range.
           /// </summary>
           /// <param name="pt1">The first corner of range.</param>
           /// <param name="pt2">The opposite corner of the range.</param>
           /// <returns>All points within the box.</returns>
           public Point3dCollection BoxedRange(Point3d pt1, Point3d pt2)
           {
               Point3d lowerLeft = new Point3d(
                   Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y), Math.Min(pt1.Z, pt2.Z));
               Point3d upperRight = new Point3d(
                   Math.Max(pt1.X, pt2.X), Math.Max(pt1.Y, pt2.Y), Math.Max(pt1.Z, pt2.Z));
               Point3dCollection points = new Point3dCollection();
               FindRange(lowerLeft, upperRight, this.Root, points);
               return points;
           }
     
           /// <summary>
           /// Gets all the pairs of points which distance is less or equal than the specified distance.
           /// </summary>
           /// <param name="radius">The maximum distance between two points. </param>
           /// <returns>The pairs of points which distance is less or equal than the specified distance.</returns>
           public List<Tuple<Point3d, Point3d>> ConnectAll(double radius)
           {
               List<Tuple<Point3d, Point3d>> connexions = new List<Tuple<Point3d, Point3d>>();
               GetConnexions(this.Root, radius * radius, connexions);
               return connexions;
           }
     
           #endregion
     
           #region Private methods
     
           private TreeNode Create(Point3d[] points, int depth, TreeNode parent, bool isLeft)
           {
               int length = points.Length;
               if (length == 0) return null;
               int d = depth % this.dimension;
               Point3d median = points.QuickSelectMedian((p1, p2) => p1[d].CompareTo(p2[d]));
               TreeNode node = new TreeNode(median);
               node.Depth = depth;
               node.Parent = parent;
               node.IsLeft = isLeft;
               int mid = length / 2;
               int rlen = length - mid - 1;
               Point3d[] left = new Point3d[mid];
               Point3d[] right = new Point3d[rlen];
               Array.Copy(points, 0, left, 0, mid);
               Array.Copy(points, mid + 1, right, 0, rlen);
               if (depth < this.parallelDepth)
               {
                   System.Threading.Tasks.Parallel.Invoke(
                      () => node.LeftChild = Create(left, depth + 1, node, true),
                      () => node.RightChild = Create(right, depth + 1, node, false)
                   );
               }
               else
               {
                   node.LeftChild = Create(left, depth + 1, node, true);
                   node.RightChild = Create(right, depth + 1, node, false);
               }
               return node;
           }
     
           private Point3d GetNeighbour(Point3d center, TreeNode node, Point3d currentBest, double bestDist)
           {
               if (node == null)
                   return currentBest;
               Point3d current = node.Value;
               int d = node.Depth % this.dimension;
               double coordCen = center[d];
               double coordCur = current[d];
               double dist = this.sqrDist(center, current);
               if (dist >= 0.0 && dist < bestDist)
               {
                   currentBest = current;
                   bestDist = dist;
               }
               dist = coordCen - coordCur;
               if (bestDist < dist * dist)
               {
                   currentBest = GetNeighbour(
                       center, coordCen < coordCur ? node.LeftChild : node.RightChild, currentBest, bestDist);
                   bestDist = this.sqrDist(center, currentBest);
               }
               else
               {
                   currentBest = GetNeighbour(center, node.LeftChild, currentBest, bestDist);
                   bestDist = this.sqrDist(center, currentBest);
                   currentBest = GetNeighbour(center, node.RightChild, currentBest, bestDist);
                   bestDist = this.sqrDist(center, currentBest);
               }
               return currentBest;
           }
     
           private void GetNeighboursAtDistance(Point3d center, double radius, TreeNode node, Point3dCollection points)
           {
               if (node == null) return;
               Point3d current = node.Value;
               double dist = this.sqrDist(center, current);
               if (dist <= radius)
               {
                   points.Add(current);
               }
               int d = node.Depth % this.dimension;
               double coordCen = center[d];
               double coordCur = current[d];
               dist = coordCen - coordCur;
               if (dist * dist > radius)
               {
                   if (coordCen < coordCur)
                   {
                       GetNeighboursAtDistance(center, radius, node.LeftChild, points);
                   }
                   else
                   {
                       GetNeighboursAtDistance(center, radius, node.RightChild, points);
                   }
               }
               else
               {
                   GetNeighboursAtDistance(center, radius, node.LeftChild, points);
                   GetNeighboursAtDistance(center, radius, node.RightChild, points);
               }
           }
     
           private void GetKNeighbours(Point3d center, int number, TreeNode node, List<Tuple<double, Point3d>> pairs)
           {
               if (node == null) return;
               Point3d current = node.Value;
               double dist = this.sqrDist(center, current);
               int cnt = pairs.Count;
               if (cnt == 0)
               {
                   pairs.Add(new Tuple<double, Point3d>(dist, current));
               }
               else if (cnt < number)
               {
                   if (dist > pairs[0].Item1)
                   {
                       pairs.Insert(0, new Tuple<double, Point3d>(dist, current));
                   }
                   else
                   {
                       pairs.Add(new Tuple<double, Point3d>(dist, current));
                   }
               }
               else if (dist < pairs[0].Item1)
               {
                   pairs[0] = new Tuple<double, Point3d>(dist, current);
                   pairs.Sort((p1, p2) => p2.Item1.CompareTo(p1.Item1));
               }
               int d = node.Depth % this.dimension;
               double coordCen = center[d];
               double coordCur = current[d];
               dist = coordCen - coordCur;
               if (dist * dist > pairs[0].Item1)
               {
                   if (coordCen < coordCur)
                   {
                       GetKNeighbours(center, number, node.LeftChild, pairs);
                   }
                   else
                   {
                       GetKNeighbours(center, number, node.RightChild, pairs);
                   }
               }
               else
               {
                   GetKNeighbours(center, number, node.LeftChild, pairs);
                   GetKNeighbours(center, number, node.RightChild, pairs);
               }
           }
     
           private void FindRange(Point3d lowerLeft, Point3d upperRight, TreeNode node, Point3dCollection points)
           {
               if (node == null)
                   return;
               Point3d current = node.Value;
               if (ignoreZ)
               {
                   if (current.X >= lowerLeft.X && current.X <= upperRight.X &&
                       current.Y >= lowerLeft.Y && current.Y <= upperRight.Y)
                       points.Add(current);
               }
               else
               {
                   if (current.X >= lowerLeft.X && current.X <= upperRight.X &&
                       current.Y >= lowerLeft.Y && current.Y <= upperRight.Y &&
                       current.Z >= lowerLeft.Z && current.Z <= upperRight.Z)
                       points.Add(current);
               }
               int d = node.Depth % this.dimension;
               if (upperRight[d] < current[d])
                   FindRange(lowerLeft, upperRight, node.LeftChild, points);
               else if (lowerLeft[d] > current[d])
                   FindRange(lowerLeft, upperRight, node.RightChild, points);
               else
               {
                   FindRange(lowerLeft, upperRight, node.LeftChild, points);
                   FindRange(lowerLeft, upperRight, node.RightChild, points);
               }
           }
     
           private void GetConnexions(TreeNode node, double radius, List<Tuple<Point3d, Point3d>> connexions)
           {
               if (node == null) return;
               Point3dCollection points = new Point3dCollection();
               Point3d center = node.Value;
               if (ignoreZ)
               GetRightParentsNeighbours(center, node, radius, points);
               GetNeighboursAtDistance(center, radius, node.LeftChild, points);
               GetNeighboursAtDistance(center, radius, node.RightChild, points);
               for (int i = 0; i < points.Count; i++)
               {
                   connexions.Add(new Tuple<Point3d, Point3d>(center, points[i]));
               }
               GetConnexions(node.LeftChild, radius, connexions);
               GetConnexions(node.RightChild, radius, connexions);
           }
     
           private void GetRightParentsNeighbours(Point3d center, TreeNode node, double radius, Point3dCollection points)
           {
               TreeNode parent = GetRightParent(node);
               if (parent == null) return;
               int d = parent.Depth % this.dimension;
               double dist = center[d] - parent.Value[d];
               if (dist * dist <= radius)
               {
                   GetNeighboursAtDistance(center, radius, parent.RightChild, points);
               }
               GetRightParentsNeighbours(center, parent, radius, points);
           }
     
           private TreeNode GetRightParent(TreeNode node)
           {
               TreeNode parent = node.Parent;
               if (parent == null) return null;
               if (node.IsLeft) return parent;
               return GetRightParent(parent);
           }
     
           private double SqrDistance2d(Point3d p1, Point3d p2)
           {
               return (p1.X - p2.X) * (p1.X - p2.X) +
                   (p1.Y - p2.Y) * (p1.Y - p2.Y);
           }
     
           private double SqrDistance3d(Point3d p1, Point3d p2)
           {
               return (p1.X - p2.X) * (p1.X - p2.X) +
                   (p1.Y - p2.Y) * (p1.Y - p2.Y) +
                   (p1.Z - p2.Z) * (p1.Z - p2.Z);
           }
     
           #endregion
       }
     
       static class Extensions
       {
           // Credit: Tony Tanzillo
           // http://www.theswamp.org/index.php?topic=44312.msg495808#msg495808
           public static T QuickSelectMedian<T>(this T[] items, Comparison<T> compare)
           {
               int l = items.Length;
               int k = l / 2;
               if (items == null || l == 0)
                   throw new ArgumentException("array");
               int from = 0;
               int to = l - 1;
               while (from < to)
               {
                   int r = from;
                   int w = to;
                   T current = items[(r + w) / 2];
                   while (r < w)
                   {
                       if (compare(items[r], current) > -1)
                       {
                           var tmp = items[w];
                           items[w] = items[r];
                           items[r] = tmp;
                           w--;
                       }
                       else
                       {
                           r++;
                       }
                   }
                   if (compare(items[r], current) > 0)
                   {
                       r--;
                   }
                   if (k <= r)
                   {
                       to = r;
                   }
                   else
                   {
                       from = r + 1;
                   }
               }
               return items[k];
           }
       }
    }
     
23
     
   C#
   
Code: [Select]

[CommandMethod("liso")]
        public static void testLayerIsol()
        {
            Database db = HostApplicationServices.WorkingDatabase;

            Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;

            PromptEntityOptions opt = new PromptEntityOptions( "\nSelect an entity :");

                PromptEntityResult res = ed.GetEntity(opt);

                if (res.Status != PromptStatus.OK) return;
     
                    ObjectId entId=  res.ObjectId;
                   
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                Entity ent= tr.GetObject(entId, OpenMode.ForRead) as Entity;

                if (ent==null) return;

                string lname= ent.Layer;

                using (LayerTable lt = db.LayerTableId.GetObject(OpenMode.ForRead, false) as LayerTable)
                {
                 
                    db.Clayer=lt[lname];
               
                    foreach (ObjectId layId in lt)
                    {

                        if (layId != lt[lname])
                        {
                            LayerTableRecord ltr = tr.GetObject(layId, OpenMode.ForWrite, false) as LayerTableRecord;

                            if ((!ltr.IsDependent) && ((!ltr.Name.Contains("*|*")) | (!ltr.Name.Contains("X*"))))
                            {
                                ltr.IsOff = true;

                            }
                        }
                    }
       
                }
                tr.Commit();
            }
        }


   
Code: [Select]

        [CommandMethod("loff")]
        public static void testLayersOff()
           {
            Database db = HostApplicationServices.WorkingDatabase;

            Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;

            PromptEntityOptions opt = new PromptEntityOptions( "\nSelect an entity :");

                PromptEntityResult res = ed.GetEntity(opt);

                if (res.Status != PromptStatus.OK) return;
     
                    ObjectId entId=  res.ObjectId;
                   
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                Entity ent= tr.GetObject(entId, OpenMode.ForRead) as Entity;

                if (ent==null) return;

                string lname= ent.Layer;

                using (LayerTable lt = db.LayerTableId.GetObject(OpenMode.ForRead, false) as LayerTable)
                {
                   LayerTableRecord clayer = tr.GetObject(db.Clayer, OpenMode.ForRead) as LayerTableRecord;  //current layer
                   
                    if (lt[lname]==db.Clayer)
                    {
                        Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Could not turn off the current layer.");

                        return;
                    }
                    LayerTableRecord ltr = tr.GetObject(lt[lname], OpenMode.ForWrite, false) as LayerTableRecord;

                    if ((!ltr.IsDependent) && ((!ltr.Name.Contains("*|*")) | (!ltr.Name.Contains("X*"))))
                    {
                        ltr.IsOff = true;
                    }           
                }
                tr.Commit();
            }
        }


   VB.NET
   
Code: [Select]

        <CommandMethod("liso")> _
        Public Shared Sub testLayerIsol()
            Dim db As Database = HostApplicationServices.WorkingDatabase

            Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor

            Dim opt As New PromptEntityOptions(vbLf & "Select an entity :")

            Dim res As PromptEntityResult = ed.GetEntity(opt)

            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim entId As ObjectId = res.ObjectId

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim ent As Entity = TryCast(tr.GetObject(entId, OpenMode.ForRead), Entity)

                If ent Is Nothing Then
                    Return
                End If

                Dim lname As String = ent.Layer

                Using lt As LayerTable = TryCast(db.LayerTableId.GetObject(OpenMode.ForRead, False), LayerTable)

                    db.Clayer = lt(lname)

                    For Each layId As ObjectId In lt

                        If layId <> lt(lname) Then
                            Dim ltr As LayerTableRecord = TryCast(tr.GetObject(layId, OpenMode.ForWrite, False), LayerTableRecord)

                            If (Not ltr.IsDependent) AndAlso ((Not ltr.Name.Contains("*|*")) Or (Not ltr.Name.Contains("X*"))) Then

                                ltr.IsOff = True
                            End If
                        End If

                    Next
                End Using
                tr.Commit()
            End Using
        End Sub


   
Code: [Select]

        <CommandMethod("loff")> _
        Public Shared Sub testLayersOff()
            Dim db As Database = HostApplicationServices.WorkingDatabase

            Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor

            Dim opt As New PromptEntityOptions(vbLf & "Select an entity :")

            Dim res As PromptEntityResult = ed.GetEntity(opt)

            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim entId As ObjectId = res.ObjectId

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim ent As Entity = TryCast(tr.GetObject(entId, OpenMode.ForRead), Entity)

                If ent Is Nothing Then
                    Return
                End If

                Dim lname As String = ent.Layer

                Using lt As LayerTable = TryCast(db.LayerTableId.GetObject(OpenMode.ForRead, False), LayerTable)
                    Dim clayer As LayerTableRecord = TryCast(tr.GetObject(db.Clayer, OpenMode.ForRead), LayerTableRecord)
                    'current layer
                    If lt(lname) = db.Clayer Then
                        Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Could not turn off the current layer.")

                        Return
                    End If
                    Dim ltr As LayerTableRecord = TryCast(tr.GetObject(lt(lname), OpenMode.ForWrite, False), LayerTableRecord)

                    If (Not ltr.IsDependent) AndAlso ((Not ltr.Name.Contains("*|*")) Or (Not ltr.Name.Contains("X*"))) Then
                        ltr.IsOff = True
                    End If
                End Using
                tr.Commit()
            End Using
        End Sub
24
Tables / Re: Get the MText object in a cell
« Last post by fixo on June 01, 2013, 10:45:54 PM »
In AutoCAD 2010 it might be resolved like this
Code: [Select]
Cell cell = mytable.Cells[row, column];

 string celltext = cell.GetTextString(FormatOption.IgnoreMtextFormat);
25
Windows forms / Re: Osnap Palette
« Last post by fixo on May 31, 2013, 10:44:10 AM »
Hi Gilles,
Check please if chkf11 and chkf3 was defined in your code
Regards,
Oleg
27
Text / Autonumbering with prefix
« Last post by fixo on May 30, 2013, 10:44:34 PM »
   VB.NET
Code: [Select]
#Region "AutoNumbering with prefix"

        ''' <summary>
        '''  Function to return increment string
        ''' </summary>
        ''' <param name="prefix"></param>
        ''' <param name="start"></param>
        ''' <param name="rate"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function TextInc(prefix As String, start As String, rate As Integer) As String
            Dim result As String = ""
            Dim head As String = ""
            Dim szero As Boolean = False
            Dim leg As Integer = (prefix & start).Length
            If start.StartsWith("0") Then
                szero = True
                Dim pos As Integer = start.LastIndexOf("0")

                For n As Integer = 0 To pos
                    head = head & "0"
                Next
            End If
            Dim num As Integer = Convert.ToInt32(start) + rate

            If szero Then
                result = String.Concat(prefix, head, num.ToString())
                If result.Length > leg Then
                    If head.Length > 1 Then
                        result = String.Concat(prefix, head.Remove(1, result.Length - leg), num.ToString())
                    Else
                        result = String.Concat(prefix, num.ToString())
                    End If
                End If
            Else
                result = String.Concat(prefix, num.ToString())
            End If
            Return result

        End Function

        ''' <summary>
        '''  Command for autonumbering with text with prefix
        ''' </summary>
        <CommandMethod("inm")> _
        Public Shared Sub IncrementWithFrame()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = doc.Editor
            Dim db As Database = doc.Database
            Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem
            ' Get or discard prefix as string entered by the user
            Dim pso As New PromptStringOptions(vbLf & vbTab & "Enter prefix or press Enter w/o it: ")
            pso.AllowSpaces = True
            pso.DefaultValue = ""
            Dim res As PromptResult
            res = ed.GetString(pso)
            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim pfx As String = res.StringResult
            Dim pos As Integer = pfx.Length
            ed.WriteMessage(vbLf & "Prefix Entered:" & vbTab & "{0}", pfx)
            ' Get initial number as string entered by the user
            pso = New PromptStringOptions(vbLf & "Enter initial number  : ")
            pso.UseDefaultValue = True
            pso.DefaultValue = "0001"

            res = ed.GetString(pso)
            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim strnum As String = res.StringResult
            ed.WriteMessage(vbLf & "initial number:" & vbTab & "{0}", strnum)

            Dim pio As New PromptIntegerOptions("")
            pio.Message = vbLf & "Enter an increment step: "

            ' Restrict input to positive and non-negative values
            pio.AllowZero = False
            pio.AllowNegative = False
            ' Add default value
            pio.DefaultValue = 1
            pio.AllowNone = True

            ' Get step value entered by the user
            Dim ires As PromptIntegerResult = ed.GetInteger(pio)
            If ires.Status <> PromptStatus.OK Then
                Return
            End If

            Dim rate As Integer = ires.Value

            ed.WriteMessage(vbLf & "Step entered" & vbTab & "{0}", rate)
            ' Get gap value entered by the user
            Dim pdo As New PromptDoubleOptions(vbLf & "Enter the gap size between text and frame  : ")
            pdo.AllowNone = True
            pdo.UseDefaultValue = True
            pdo.DefaultValue = db.Textsize / 2

            Dim dbres As PromptDoubleResult
            dbres = ed.GetDouble(pdo)
            If res.Status <> PromptStatus.OK Then
                Return
            End If

            Dim gap As Double = dbres.Value

            ed.WriteMessage(vbLf & "Gap Entered" & vbTab & "{0}", gap)
            ' using a current textsize
            Dim txtheight As Double = db.Textsize

            Using tr As Transaction = db.TransactionManager.StartTransaction()

                doc.TransactionManager.EnableGraphicsFlush(True)

                Dim btr As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

                Dim ppo As New PromptPointOptions(vbLf & vbTab & "Specify text insertion point (Enter to stop): ")
                ppo.AllowNone = True
                Dim ptres As PromptPointResult
                Dim n As Integer = 0

                Dim txt As String = ""
                ' get text points multiple
                Do
                    Dim pt As New Point3d()
                    ptres = ed.GetPoint(ppo)

                    If ptres.Status = PromptStatus.OK Then
                        pt = ptres.Value
                        Dim otext As New DBText()
                        otext.Position = pt
                        otext.VerticalMode = TextVerticalMode.TextVerticalMid
                        otext.HorizontalMode = TextHorizontalMode.TextMid
                        otext.AlignmentPoint = otext.Position
                        otext.AdjustAlignment(db)
                        If n = 0 Then

                            txt = TextInc(pfx, strnum, 0)
                        Else
                            txt = TextInc(pfx, strnum, rate)
                        End If

                        otext.TextString = txt

                        n += 1
                        strnum = txt.TrimStart(pfx.ToCharArray())

                        btr.AppendEntity(otext)
                        tr.AddNewlyCreatedDBObject(otext, True)
                        tr.TransactionManager.QueueForGraphicsFlush()
                        Dim plan As Plane = otext.GetPlane()
                        Dim ext As Extents3d = otext.GeometricExtents
                        Dim bl As Point3d = ext.MinPoint
                        Dim ur As Point3d = ext.MaxPoint
                        Dim mp As Point3d = New Point3d((bl.X + ur.X) / 2, (bl.Y + ur.Y) / 2, (bl.Z + ur.Z) / 2).TransformBy(ucs)
                        otext.Position = mp
                        otext.AlignmentPoint = otext.Position
                        otext.AdjustAlignment(db)

                        Dim br As New Point3d(ur.X, bl.Y, bl.Z)
                        Dim ul As New Point3d(bl.X, ur.Y, bl.Z)
                        bl = bl.Subtract(New Vector3d(gap, gap, 0)).TransformBy(ucs)
                        ur = ur.Subtract(New Vector3d(-gap, -gap, 0)).TransformBy(ucs)
                        br = br.Subtract(New Vector3d(-gap, gap, 0)).TransformBy(ucs)
                        ul = ul.Subtract(New Vector3d(gap, -gap, 0)).TransformBy(ucs)
                        Dim poly As New Polyline()
                        poly.AddVertexAt(0, bl.Convert2d(plan), 0, 0, 0)
                        poly.AddVertexAt(0, br.Convert2d(plan), 0, 0, 0)
                        poly.AddVertexAt(0, ur.Convert2d(plan), 0, 0, 0)
                        poly.AddVertexAt(0, ul.Convert2d(plan), 0, 0, 0)
                        poly.Closed = True
                        poly.ColorIndex = 1
                        btr.AppendEntity(poly)
                        tr.AddNewlyCreatedDBObject(poly, True)

                        tr.TransactionManager.QueueForGraphicsFlush()

                    End If
                Loop While ptres.Status = PromptStatus.OK
                doc.TransactionManager.FlushGraphics()
                tr.Commit()
            End Using

        End Sub
#End Region


   C#
Code: [Select]
        /// <summary>
          /// function to return increment string
        /// </summary>
        /// <param name="prefix"></param>
        /// <param name="start"></param>
        /// <param name="step"></param>
        /// <returns></returns>
        private static string TextInc(string prefix, string start, int step)
        {
            string result = "";
            string head = "";
            bool szero = false;
            int leg = (prefix + start).Length;
            if (start.StartsWith("0"))
            {
                szero = true;
                int pos = start.LastIndexOf("0");

                for (int n = 0; n <= pos; n++)
                    head = head + "0";
            }
            int num = Convert.ToInt32(start) + step;

            if (szero)
            {
                result = String.Concat(prefix, head, num.ToString());
                if (result.Length > leg)
                {
                    if (head.Length > 1)
                        result = String.Concat(prefix, head.Remove(1, result.Length - leg), num.ToString());
                    else
                        result = String.Concat(prefix, num.ToString());
                }
            }
            else
            {
                result = String.Concat(prefix, num.ToString());
            }
            return result;

        }

        /// <summary>
        ///  Command for autonumbering with text with prefix
        /// </summary>
        [CommandMethod("inm")]
        public static void IncrementWithFrame()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            Matrix3d ucs = ed.CurrentUserCoordinateSystem;
            // Get or discard prefix as string entered by the user
            PromptStringOptions pso =
                 new PromptStringOptions("\n\tEnter prefix or press Enter w/o it: ");
            pso.AllowSpaces = true;
            pso.DefaultValue = "";
            PromptResult res;
            res = ed.GetString(pso);
            if (res.Status != PromptStatus.OK)  return;

            string pfx = res.StringResult;
            int pos = pfx.Length;
            ed.WriteMessage("\nPrefix Entered:\t{0}", pfx);
            // Get initial number as string entered by the user
            pso = new PromptStringOptions("\nEnter initial number  : ");
            pso.UseDefaultValue = true;
            pso.DefaultValue = "0001";

            res = ed.GetString(pso);
            if (res.Status != PromptStatus.OK)return;

            string strnum = res.StringResult;
            ed.WriteMessage("\ninitial number:\t{0}", strnum);

            PromptIntegerOptions pio = new PromptIntegerOptions("");
            pio.Message = "\nEnter an increment step: ";

            // Restrict input to positive and non-negative values
            pio.AllowZero = false;
            pio.AllowNegative = false;
            // Add default value
            pio.DefaultValue = 1;
            pio.AllowNone = true;

            // Get step value entered by the user
            PromptIntegerResult ires = ed.GetInteger(pio);
            if (ires.Status != PromptStatus.OK) return;

            int step = ires.Value;

            ed.WriteMessage("\nStep entered\t{0}", step);
            // Get gap value entered by the user
            PromptDoubleOptions pdo =
                           new PromptDoubleOptions("\nEnter the gap size between text and frame  : ");
            pdo.AllowNone = true;
            pdo.UseDefaultValue = true;
            pdo.DefaultValue = db.Textsize / 2;

            PromptDoubleResult dbres;
            dbres = ed.GetDouble(pdo);
            if (res.Status != PromptStatus.OK)  return;

            double gap = dbres.Value;

            ed.WriteMessage("\nGap Entered\t{0}", gap);
            // using a current textsize
            double txtheight = db.Textsize;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {

                doc.TransactionManager.EnableGraphicsFlush(true);

                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                PromptPointOptions ppo = new PromptPointOptions("\n\tSpecify text insertion point (Enter to stop): ");
                ppo.AllowNone = true;
                PromptPointResult ptres;
                int n = 0;

                string txt = "";
                // get text points multiple
                do
                {
                    Point3d pt = new Point3d();
                    ptres = ed.GetPoint(ppo);

                    if (ptres.Status == PromptStatus.OK)
                    {
                        pt = ptres.Value;
                        DBText otext = new DBText();
                        otext.Position = pt;
                        otext.VerticalMode = TextVerticalMode.TextVerticalMid;
                        otext.HorizontalMode = TextHorizontalMode.TextMid;
                        otext.AlignmentPoint = otext.Position;
                        otext.AdjustAlignment(db);
                        if (n == 0)
                        {
                            txt = TextInc(pfx, strnum, 0);

                        }
                        else
                            txt = TextInc(pfx, strnum, step);

                        otext.TextString = txt;
                       
                        n += 1;
                        strnum = txt.TrimStart(pfx.ToCharArray());
                       
                        btr.AppendEntity(otext);
                        tr.AddNewlyCreatedDBObject(otext, true);
                        tr.TransactionManager.QueueForGraphicsFlush();
                        Plane plan = otext.GetPlane();
                        Extents3d ext = otext.GeometricExtents;
                        Point3d bl = ext.MinPoint;
                        Point3d ur = ext.MaxPoint;
                        Point3d mp = new Point3d((bl.X + ur.X) / 2, (bl.Y + ur.Y) / 2, (bl.Z + ur.Z) / 2).TransformBy(ucs);
                        otext.Position = mp;
                        otext.AlignmentPoint = otext.Position;
                        otext.AdjustAlignment(db);

                        Point3d br = new Point3d(ur.X, bl.Y, bl.Z);
                        Point3d ul = new Point3d(bl.X, ur.Y, bl.Z);
                        bl = bl.Subtract(new Vector3d(gap, gap, 0)).TransformBy(ucs);
                        ur = ur.Subtract(new Vector3d(-gap, -gap, 0)).TransformBy(ucs);
                        br = br.Subtract(new Vector3d(-gap, gap, 0)).TransformBy(ucs);
                        ul = ul.Subtract(new Vector3d(gap, -gap, 0)).TransformBy(ucs);
                        Polyline poly = new Polyline();
                        poly.AddVertexAt(0, bl.Convert2d(plan), 0, 0, 0);
                        poly.AddVertexAt(0, br.Convert2d(plan), 0, 0, 0);
                        poly.AddVertexAt(0, ur.Convert2d(plan), 0, 0, 0);
                        poly.AddVertexAt(0, ul.Convert2d(plan), 0, 0, 0);
                        poly.Closed = true;
                        poly.ColorIndex = 1;
                        btr.AppendEntity(poly);
                        tr.AddNewlyCreatedDBObject(poly, true);
                        tr.TransactionManager.QueueForGraphicsFlush();

                    }

                } while (ptres.Status == PromptStatus.OK);
                doc.TransactionManager.FlushGraphics();
                tr.Commit();
            }

        }
28
I am in need of the ability from a tool palette or modeless dialog to open drawings selected by the user from a user control.  The palette or modeless dialog needs to remain open during and after the opening of the drawings.  Everytime and everthing I seem to attempt ends up crashing autocad.  If anyone has thought or ideas on how to handle this operations it is welcome. 
29
Layouts and printing / Rename layouts custom way
« Last post by fixo on May 19, 2013, 02:37:37 PM »
   
Code: [Select]
VB.NET
        'Public Class LayoutTools

        ' declare layout names outside of method, keep them empty:
        Private oldname As String = ""
        Private newname As String = ""
        <CommandMethod("lre")> _
        Public Sub testLayoutsRename()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim db As Database = HostApplicationServices.WorkingDatabase
            Dim ed As Editor = doc.Editor
            Dim tr As Transaction = db.TransactionManager.StartTransaction()

            Dim ltnames As New SortedList(Of String, String)()
           ' lst of pairs <old layout name,new layout name>: '
            ltnames.Add("Layout1", "General")
            ltnames.Add("Layout2", "Floor Plan 1")
            ltnames.Add("Layout3", "Floor Plan 2")
            ltnames.Add("Layout4", "Floor Plan 3")
            '   ETC ...
            Dim lm As LayoutManager = LayoutManager.Current
            Dim lyid As ObjectId = ObjectId.Null
            Try
                Using tr
                    For Each kvp As KeyValuePair(Of String, String) In ltnames
                        oldname = kvp.Key
                        newname = kvp.Value
                        lyid = lm.GetLayoutId(oldname)

                        If lm.GetLayoutId(oldname) <> ObjectId.Null Then
                            Dim lt As Layout = TryCast(tr.GetObject(lyid, OpenMode.ForWrite), Layout)

                            AddHandler lm.LayoutRenamed, AddressOf lm_LayoutRenamed
                            AddHandler lm.LayoutToBeRenamed, AddressOf lm_LayoutToBeRenamed
                            lt.LayoutName = newname
                        End If
                    Next
                    tr.Commit()
                    ed.Regen()
                End Using
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(vbLf & "Error Reason: {0}" & vbLf, ex.ErrorStatus)
                Return
            End Try

        End Sub

        Private Sub lm_LayoutRenamed(sender As Object, e As LayoutRenamedEventArgs)
            Dim newmame As String = ""
            Try
                newmame = e.NewName
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(vbLf & "Invalid layout name: {0}" & vbLf & "{1}", e.NewName, ex.ErrorStatus)
                Return
            End Try

        End Sub
        Private Sub lm_LayoutToBeRenamed(sender As Object, e As LayoutRenamedEventArgs)
            Try
                SymbolUtilityServices.ValidateSymbolName(oldname, False)
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(vbLf & "Invalid layout name: {0}" & vbLf & "{1}", e.NewName, ex.ErrorStatus)
                Return
            End Try

        End Sub

        ' End Class 'end of class

   C#

   
Code: [Select]
        // public class LayoutTools
        // {
        // declare layout names outside of method, keep them empty:
        string oldname = ""; string newname = "";
        [CommandMethod("lre")]
        public void testLayoutsRename()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = doc.Editor;
            Transaction tr = db.TransactionManager.StartTransaction();

            SortedList<string, string> ltnames = new SortedList<string, string>();
           // lst of pairs <old layout name,new layout name>: //
            ltnames.Add("Layout1", "General");
            ltnames.Add("Layout2", "Floor Plan 1");
            ltnames.Add("Layout3", "Floor Plan 2");
            ltnames.Add("Layout4", "Floor Plan 3");//   ETC ...
            LayoutManager lm = LayoutManager.Current;
            ObjectId lyid = ObjectId.Null;
            try
            {
                using (tr)
                {
                    foreach (KeyValuePair<string, string> kvp in ltnames)
                    {
                        oldname = kvp.Key; newname = kvp.Value;
                        lyid = lm.GetLayoutId(oldname);

                        if (lm.GetLayoutId(oldname) != ObjectId.Null)
                        {
                            Layout lt = tr.GetObject(lyid, OpenMode.ForWrite) as Layout;

                            lm.LayoutRenamed += new LayoutRenamedEventHandler(lm_LayoutRenamed);
                            lm.LayoutToBeRenamed += new LayoutRenamedEventHandler(lm_LayoutToBeRenamed);
                            lt.LayoutName = newname;
                        }
                    }
                    tr.Commit();
                    ed.Regen();
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
                    "\nRerror Reason: {0}\n", ex.ErrorStatus);
                return;
            }

        }

        private void lm_LayoutRenamed(object sender, LayoutRenamedEventArgs e)
        {
            string newmame = "";
            try
            {
                newmame = e.NewName;
            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
                    "\nInvalid layout name: {0}\n{1}", e.NewName, ex.ErrorStatus);
                return;
            }

        }
        private void lm_LayoutToBeRenamed(object sender, LayoutRenamedEventArgs e)
        {
            try
            {
                SymbolUtilityServices.ValidateSymbolName(oldname, false);
            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(
                    "\nInvalid layout name: {0}\n{1}", e.NewName, ex.ErrorStatus);
                return;
            }

        }

    //}// end of class
 
30
Text / Change the background mask property of AcDbMText object programmatically
« Last post by fixo on May 18, 2013, 08:36:35 PM »

See for more an article written  by Fenton Webb here
http://adndevblog.typepad.com/autocad/2013/05/change-the-background-mask-property-of-acdbmtext-object-programmatically-using-objectarx.html
   VB.NET
   
Code: [Select]
        Public Shared Function fixoGetEntity(tr As Transaction, ed As Editor, rx As RXClass, msg As String, ByRef id As ObjectId) As ErrorStatus
            Dim es As ErrorStatus
            Dim ent As Entity
            id = ObjectId.Null
            Dim peo As New PromptEntityOptions(msg)
            peo.SetRejectMessage(vbLf & "You're missing, try again >>")
            peo.AddAllowedClass(GetType(Entity), False)
            Dim res As PromptEntityResult
            res = ed.GetEntity(peo)
            If res.Status <> PromptStatus.OK Then
                es = ErrorStatus.PointNotOnEntity
            End If
            id = res.ObjectId
            If id = ObjectId.Null Then
                es = ErrorStatus.NullObjectId
            End If
            ent = TryCast(tr.GetObject(id, OpenMode.ForRead, False), Entity)
            If ent.GetRXClass() <> rx Then
                ed.WriteMessage(vbLf & "{0}Must be a type of ""{0}"" only!", rx.DxfName)
                es = ErrorStatus.NotThatKindOfClass
            End If
            If ent Is Nothing Then
                es = ErrorStatus.NotAnEntity
            Else
                es = ErrorStatus.OK
            End If
            Return es
        End Function
        <CommandMethod("BM")> _
        Public Shared Sub test_setBackgroundFill_MText()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument

            Dim ed As Editor = doc.Editor

            Dim db As Database = HostApplicationServices.WorkingDatabase

            Dim id As ObjectId = ObjectId.Null

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                If fixoGetEntity(tr, ed, RXClass.GetClass(GetType(MText)), vbLf & "Please pick an MText entity: ", id) = ErrorStatus.OK Then

                    Dim btr As BlockTableRecord = TryCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
                    ' get entity by direct cast
                    Dim ent As Entity = DirectCast(tr.GetObject(id, OpenMode.ForRead), Entity)

                    If id.ObjectClass.DxfName = "MTEXT" Then
                        Dim mtx As MText = TryCast(ent, MText)

                        mtx.UpgradeOpen()

                        Dim color As Autodesk.AutoCAD.Colors.Color

                        If mtx.BackgroundFill Then

                            mtx.UseBackgroundColor = False


                            mtx.BackgroundFill = False
                        Else

                            mtx.BackgroundFill = True

                            color = color.FromColorIndex(ColorMethod.ByAci, CInt(1))

                            mtx.BackgroundFillColor = color


                            mtx.UseBackgroundColor = False
                        End If

                        mtx.RecordGraphicsModified(True)
                    End If
                End If
                tr.Commit()
            End Using
        End Sub

   C#
   
Code: [Select]
        public static ErrorStatus fixoGetEntity(Transaction tr, Editor ed, RXClass rx, string msg, out ObjectId id)
        {
            ErrorStatus es;
            Entity ent;
            id = ObjectId.Null;
            PromptEntityOptions peo = new PromptEntityOptions(msg);
            peo.SetRejectMessage("\nYou're missing, try again >>");
            peo.AddAllowedClass(typeof(Entity), false);
            PromptEntityResult res;
            res = ed.GetEntity(peo);
            if (res.Status != PromptStatus.OK)
                es = ErrorStatus.PointNotOnEntity;
            id = res.ObjectId;
            if (id == ObjectId.Null)
                es = ErrorStatus.NullObjectId;
            ent = tr.GetObject(id, OpenMode.ForRead, false) as Entity;
            if (ent.GetRXClass() != rx)
            {
                ed.WriteMessage("\n{0}Must be a type of \"{0}\" only!", rx.DxfName);
                es = ErrorStatus.NotThatKindOfClass;
            }
            if (ent == null)
                es = ErrorStatus.NotAnEntity;
            else es = ErrorStatus.OK;
            return es;
        }
        [CommandMethod("BM")]
        static public void test_setBackgroundFill_MText()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;

            Database db = HostApplicationServices.WorkingDatabase;

            ObjectId id = ObjectId.Null;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                if (fixoGetEntity(tr, ed, RXClass.GetClass(typeof(MText)), "\nPlease pick an MText entity: ", out id) == ErrorStatus.OK)
                {

                    BlockTableRecord btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                   // get entity by direct cast
                    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead);

                    if (id.ObjectClass.DxfName == "MTEXT")
                    {
                        MText mtx = ent as MText;

                        mtx.UpgradeOpen();

                        Autodesk.AutoCAD.Colors.Color color;

                        if (mtx.BackgroundFill )
                        {

                            mtx.UseBackgroundColor= false;

                            mtx.BackgroundFill=false;

                        }

                        else
                        {

                            mtx.BackgroundFill=true;

                            color = Color.FromColorIndex(ColorMethod.ByAci, (int)1);

                            mtx.BackgroundFillColor = color;
                           
                            mtx.UseBackgroundColor=false;

                        }

                        mtx.RecordGraphicsModified(true);

                    }
                }
                tr.Commit();
            }
        }
Pages: 1 2 [3] 4 5 ... 10