Recent Posts

Pages: 1 [2] 3 4 ... 10
11
Display / Re: Block Count in a ToolTip
« Last post by Patriiick on November 08, 2013, 04:16:48 PM »
Thanks, very useful!  :clin_oeil_rapide:
12
Display / Block Count in a ToolTip
« Last post by (gile) on November 08, 2013, 04:15:07 PM »
Hi,

Here's an example of Editor.PointMonitor event handling.
A toolTip displays the number of inserts in the current space of the block reference which the pickbox is hovering over.

C#
Code: [Select]
// (C) Copyright 2012 by Gilles Chanteau
//
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: ExtensionApplication(typeof(Gile.BlockCountExtensionApplication.BlockCountToolTip))]

namespace Gile.BlockCountExtensionApplication
{
    public class BlockCountToolTip : IExtensionApplication
    {
        private static DocumentCollection docs;
        private static RXClass blockRefClass;

        public void Initialize()
        {
            docs = AcAp.DocumentManager;
            blockRefClass = RXClass.GetClass(typeof(BlockReference));
            docs.DocumentCreated += onDocumentCreated;
            foreach (Document doc in docs)
            {
                doc.Editor.PointMonitor += onPointMonitor;
            }
        }

        public void Terminate() { }

        void onDocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            if (e.Document != null)
                e.Document.Editor.PointMonitor += onPointMonitor;
        }

        void onPointMonitor(object sender, PointMonitorEventArgs e)
        {
            if ((e.Context.History & PointHistoryBits.FromKeyboard) == PointHistoryBits.FromKeyboard)
                return;

            FullSubentityPath[] paths = e.Context.GetPickedEntities();

            if (paths == null || paths.Length == 0)
                return;

            ObjectId[] ids = paths[0].GetObjectIds();

            if (ids == null || ids.Length == 0)
                return;

            ObjectId id = ids[0];

            if (id.IsValid && id.ObjectClass == blockRefClass)
            {
                Database db = id.Database;
                int cnt = 0;
                using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
                {
                    BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                    bool isDyn = br.IsDynamicBlock;
                    BlockTableRecord btr = isDyn ?
                        (BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead) :
                        (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
                    string name = btr.Name;
                    ObjectId cSpaceId = db.CurrentSpaceId;
                    foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
                    {
                        DBObject bRef = tr.GetObject(brId, OpenMode.ForRead);
                        if (bRef.OwnerId == cSpaceId)
                            cnt++;
                    }
                    if (isDyn)
                    {
                        foreach (ObjectId anonId in btr.GetAnonymousBlockIds())
                        {
                            BlockTableRecord anonBtr = (BlockTableRecord)tr.GetObject(anonId, OpenMode.ForRead);
                            foreach (ObjectId brId in anonBtr.GetBlockReferenceIds(true, false))
                            {
                                DBObject bRef = tr.GetObject(brId, OpenMode.ForRead);
                                if (bRef.OwnerId == cSpaceId)
                                    cnt++;
                            }
                        }
                    }
                    e.AppendToolTipText(String.Format("'{0}' {1}\n{2} insert{3}\n",
                        btr.Name,
                        isDyn ? "(dynamic)" : "",
                        cnt,
                        cnt > 1 ? "s" : ""));
                    tr.Commit();
                }
            }
        }
    }
}

F#
Code: [Select]
// (C) Copyright 2012 by Gilles Chanteau
//
module Gile.BlockCount

open System
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime

let docMan = Application.DocumentManager
let blkRefClass = RXClass.GetClass(typeof<BlockReference>)

type BCountToolTip() =
    let pointMonitor (e: PointMonitorEventArgs) =
        if (e.Context.History &&& PointHistoryBits.FromKeyboard) <> PointHistoryBits.FromKeyboard then
            let paths = e.Context.GetPickedEntities()
            if paths <> null && paths.Length > 0 then
                let ids = paths.[0].GetObjectIds()
                if ids <> null && ids.Length > 0 then
                    let id  = ids.[0]
                    if id.IsValid && id.ObjectClass = blkRefClass then
                        let db = id.Database
                        let spaceId = db.CurrentSpaceId
                        use tr = db.TransactionManager.StartOpenCloseTransaction()

                        let countRefs (btr: BlockTableRecord) =
                            btr.GetBlockReferenceIds(true, false)
                            |> Seq.cast
                            |> Seq.filter(fun id -> tr.GetObject(id, OpenMode.ForRead).OwnerId = spaceId)
                            |> Seq.length

                        let br = tr.GetObject(id, OpenMode.ForRead) :?> BlockReference
                        let isDyn = br.IsDynamicBlock
                        let btrId = if isDyn then br.DynamicBlockTableRecord else br.BlockTableRecord
                        let btr = tr.GetObject(btrId, OpenMode.ForRead) :?> BlockTableRecord
                        let cnt =
                            countRefs btr +
                            if isDyn then
                                seq { for id in btr.GetAnonymousBlockIds() ->
                                        tr.GetObject(id, OpenMode.ForRead) :?> BlockTableRecord |> countRefs }
                                |> Seq.sum
                            else 0
                        e.AppendToolTipText(String.Format("'{0}' {1}\n{2} insert{3}\n",
                                                            btr.Name,
                                                            (if isDyn then "(dynamic)" else ""),
                                                            cnt,
                                                            if cnt > 1 then "s" else ""))
                        tr.Commit()

    interface IExtensionApplication with
        member x.Initialize() =
            docMan.DocumentCreated.AddHandler(fun o e ->
                if e.Document <> null then
                    e.Document.Editor.PointMonitor.AddHandler(fun o e -> pointMonitor e))
            docMan.DocumentToBeDestroyed.AddHandler(fun o e ->
                if e.Document <> null then
                    e.Document.Editor.PointMonitor.RemoveHandler(fun o e -> pointMonitor e))
            docMan
            |> Seq.cast<Document>
            |> Seq.iter(fun doc -> doc.Editor.PointMonitor.AddHandler(fun o e -> pointMonitor e))
        member x.Terminate() = ()
13
Math and Geometry / Re: Circle tangents
« Last post by (gile) on September 15, 2013, 04:31:56 PM »
As i encountered some issues with the CircularArc3d.IntersectWith() method in some randomly 3d rotated planes, I decided to try the CircularArc2d route it seems to work fine.

The two methods shown upper now call equivalent extension methods for the CircularArc2d type after converting the CircularArc3d instance into CircularArc2d ones.
The Point2d.Convert3d() extension method is extracted from the GeometryExtensions library.

Code: [Select]
using System;
using Autodesk.AutoCAD.Geometry;

namespace GeometryExtensions
{
    /// <summary>
    /// Tangent type enum
    /// </summary>
    [Flags]
    public enum TangentType { Inner = 1, Outer = 2 }

    /// <summary>
    /// Provides extension methods for the Point2d structure.
    /// </summary>
    public static class Point2dExtensions
    {       
        /// <summary>
        /// Converts a 2d point into a 3d point according to the plane defined by
        /// the specified normal vector and elevation.
        /// </summary>
        /// <param name="pt">The instance to which the method applies.</param>
        /// <param name="normal">The normal vector of the plane which the point lies on.</param>
        /// <param name="elevation">The elevation of the plane which the point lies on.</param>
        /// <returns>The corresponding 3d point</returns>
        public static Point3d Convert3d(this Point2d pt, Vector3d normal, double elevation)
        {
            return new Point3d(pt.X, pt.Y, elevation).TransformBy(Matrix3d.PlaneToWorld(normal));
        }
    }

    /// <summary>
    /// Provides extension methods for the CircularArc3d class.
    /// </summary>
    public static class CircularArc3dExtensions
    {
        /// <summary>
        /// Returns the tangents between the active CircularArc3d instance complete circle and a point.
        /// </summary>
        /// <remarks>
        /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
        /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
        /// to the point before the one on the right side.
        /// </remarks>
        /// <param name="arc">The object to which this method applies.</param>
        /// <param name="pt">The Point3d to which tangents are searched</param>
        /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns>
        /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
        public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt)
        {
            // check if arc and point lies on the plane
            Vector3d normal = arc.Normal;
            Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal);
            double elevation = arc.Center.TransformBy(WCS2OCS).Z;
            if (Math.Abs(elevation - pt.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint)
                throw new Autodesk.AutoCAD.Runtime.Exception(
                    Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

            Plane plane = new Plane(Point3d.Origin, normal);
            Matrix3d OCS2WCS = Matrix3d.PlaneToWorld(plane);
            CircularArc2d ca2d = new CircularArc2d(arc.Center.Convert2d(plane), arc.Radius);
            LineSegment2d[] lines2d = ca2d.GetTangentsTo(pt.Convert2d(plane));

            if (lines2d == null)
                return null;

            LineSegment3d[] result = new LineSegment3d[lines2d.Length];
            for (int i = 0; i < lines2d.Length; i++)
            {
                LineSegment2d ls2d = lines2d[i];
                //Point3d p1 = new Point3d(ls2d.StartPoint.X, ls2d.StartPoint.Y, elevation);
                //Point3d p2 = new Point3d(ls2d.EndPoint.X, ls2d.EndPoint.Y, elevation);
                //result[i] = new LineSegment3d(p1.TransformBy(OCS2WCS), p2.TransformBy(OCS2WCS));
                result[i] = new LineSegment3d(ls2d.StartPoint.Convert3d(normal, elevation), ls2d.EndPoint.Convert3d(normal, elevation));
            }
            return result;
        }

        /// <summary>
        /// Returns the tangents between the active CircularArc3d instance complete circle and another one.
        /// </summary>
        /// <remarks>
        /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
        /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
        /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
        /// </remarks>
        /// <param name="arc">The object to which this method applies.</param>
        /// <param name="other">The CircularArc3d to which searched for tangents.</param>
        /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
        /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
        /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
        public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags)
        {
            // check if circles lies on the same plane
            Vector3d normal = arc.Normal;
            Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal);
            double elevation = arc.Center.TransformBy(WCS2OCS).Z;
            if (!(normal.IsParallelTo(other.Normal) &&
                Math.Abs(elevation - other.Center.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint))
                throw new Autodesk.AutoCAD.Runtime.Exception(
                    Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

            Plane plane = new Plane(Point3d.Origin, normal);
            Matrix3d OCS2WCS = Matrix3d.PlaneToWorld(plane);
            CircularArc2d ca2d1 = new CircularArc2d(arc.Center.Convert2d(plane), arc.Radius);
            CircularArc2d ca2d2 = new CircularArc2d(other.Center.Convert2d(plane), other.Radius);
            LineSegment2d[] lines2d = ca2d1.GetTangentsTo(ca2d2, flags);

            if (lines2d == null)
                return null;

            LineSegment3d[] result = new LineSegment3d[lines2d.Length];
            for (int i = 0; i < lines2d.Length; i++)
            {
                LineSegment2d ls2d = lines2d[i];
                //Point3d p1 = new Point3d(ls2d.StartPoint.X, ls2d.StartPoint.Y, elevation);
                //Point3d p2 = new Point3d(ls2d.EndPoint.X, ls2d.EndPoint.Y, elevation);
                //result[i] = new LineSegment3d(p1.TransformBy(OCS2WCS), p2.TransformBy(OCS2WCS));
                result[i] = new LineSegment3d(ls2d.StartPoint.Convert3d(normal, elevation), ls2d.EndPoint.Convert3d(normal, elevation));
            }
            return result;
        }
    }

    /// <summary>
    /// Provides extension methods for the CircularArc2d class.
    /// </summary>
    public static class CircularArc2dExtensions
    {
        /// <summary>
        /// Returns the tangents between the active CircularArc2d instance complete circle and a point.
        /// </summary>
        /// <remarks>
        /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
        /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
        /// to the point before the one on the right side.
        /// </remarks>
        /// <param name="arc">The object to which this method applies.</param>
        /// <param name="pt">The Point2d to which tangents are searched</param>
        /// <returns>An array of LineSegement2d representing the tangents (2) or null if there is none.</returns>
        public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, Point2d pt)
        {
            // check if the point is inside the circle
            Point2d center = arc.Center;
            if (pt.GetDistanceTo(center) <= arc.Radius)
                return null;

            Vector2d vec = center.GetVectorTo(pt) / 2.0;
            CircularArc2d tmp = new CircularArc2d(center + vec, vec.Length);
            Point2d[] inters = arc.IntersectWith(tmp);
            if (inters == null)
                return null;
            LineSegment2d[] result = new LineSegment2d[2];
            Vector2d v1 = inters[0] - center;
            Vector2d v2 = inters[1] - center;
            int i = vec.X * v1.Y - vec.Y - v1.X > 0 ? 0 : 1;
            int j = i ^ 1;
            result[i] = new LineSegment2d(inters[0], pt);
            result[j] = new LineSegment2d(inters[1], pt);
            return result;
        }

        /// <summary>
        /// Returns the tangents between the active CircularArc2d instance complete circle and another one.
        /// </summary>
        /// <remarks>
        /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
        /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
        /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
        /// </remarks>
        /// <param name="arc">The object to which this method applies.</param>
        /// <param name="other">The CircularArc2d to which searched for tangents.</param>
        /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
        /// <returns>An array of LineSegment2d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
        public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, CircularArc2d other, TangentType flags)
        {
            // check if a circle is inside the other
            double dist = arc.Center.GetDistanceTo(other.Center);
            if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint)
                return null;

            // check if circles overlap
            bool overlap = arc.Radius + other.Radius >= dist;
            if (overlap && flags == TangentType.Inner)
                return null;

            CircularArc2d tmp1, tmp2;
            Point2d[] inters;
            Vector2d vec1, vec2, vec = other.Center - arc.Center;
            int i, j;
            LineSegment2d[] result = new LineSegment2d[(int)flags == 3 && !overlap ? 4 : 2];

            // outer tangents
            if (flags.HasFlag(TangentType.Outer))
            {
                if (arc.Radius == other.Radius)
                {
                    Line2d perp = new Line2d(arc.Center, vec.GetPerpendicularVector());
                    inters = arc.IntersectWith(perp);
                    if (inters == null)
                        return null;
                    vec1 = (inters[0] - arc.Center).GetNormal();
                    vec2 = (inters[1] - arc.Center).GetNormal();
                    i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 0 : 1;
                    j = i ^ 1;
                    result[i] = new LineSegment2d(inters[0], inters[0] + vec);
                    result[j] = new LineSegment2d(inters[1], inters[1] + vec);
                }
                else
                {
                    Point2d center = arc.Radius < other.Radius ? other.Center : arc.Center;
                    tmp1 = new CircularArc2d(center, Math.Abs(arc.Radius - other.Radius));
                    tmp2 = new CircularArc2d(arc.Center + vec / 2.0, dist / 2.0);
                    inters = tmp1.IntersectWith(tmp2);
                    if (inters == null)
                        return null;
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 0 : 1;
                    j = i ^ 1;
                    result[i] = new LineSegment2d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
                    result[j] = new LineSegment2d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
                }
            }

            // inner tangents
            if (flags.HasFlag(TangentType.Inner) && !overlap)
            {
                double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
                tmp1 = new CircularArc2d(arc.Center + vec * ratio, dist * ratio);
                inters = arc.IntersectWith(tmp1);
                if (inters == null)
                    return null;
                vec1 = (inters[0] - arc.Center).GetNormal();
                vec2 = (inters[1] - arc.Center).GetNormal();
                i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 2 : 3;
                j = i == 2 ? 3 : 2;
                result[i] = new LineSegment2d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
                result[j] = new LineSegment2d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
            }
            return result;
        }
    }
}

A Test command which draws all tangents between the two selected circles. the lines are colored according to their order in the LineSegment3d array returned by GetTangentsTo() (1 red, 2 yellow, 3 green, 4 cyan).

Code: [Select]
        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
            peo.SetRejectMessage("Only a circle.");
            peo.AddAllowedClass(typeof(Circle), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            ObjectId id1 = per.ObjectId;

            peo.Message = "\nSelect another circle: ";
            ObjectId id2;
            while (true)
            {
                per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                    return;
                id2 = per.ObjectId;
                if (id1 == id2)
                    ed.WriteMessage("\nThe second circle is the same as the first one.");
                else break;
            }

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
                    Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);

                    CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
                    CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
                    LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Inner | TangentType.Outer);
                    if (lines != null)
                    {
                        BlockTableRecord btr =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        for (int i = 0; i < lines.Length; i++)
                        {
                            Line line = new Line(lines[i].StartPoint, lines[i].EndPoint);
                            line.ColorIndex = i + 1;
                            btr.AppendEntity(line);
                            tr.AddNewlyCreatedDBObject(line, true);
                        }
                    }
                    tr.Commit();
                }
            }
            catch (System.Exception exn)
            {
                ed.WriteMessage("\n" + exn.Message);
            }
        }

14
Math and Geometry / Circle tangents
« Last post by (gile) on September 14, 2013, 06:13:46 PM »
Hi,

Two methods which extents the CircularArc3d type to find tangents between to a point or another instance of CircularArc3d.

Code: [Select]
    using System;
    using Autodesk.AutoCAD.Geometry;
     
    namespace GeometryExtensions
    {
       /// <summary>
       /// Tangent type enum
       /// </summary>
       [Flags]
       public enum TangentType { Inner = 1, Outer = 2 }
     
       /// <summary>
       /// Provides extension methods for the CircularArc3d class.
       /// </summary>
       public static class CircularArc3dExtensions
       {
           /// <summary>
           /// Returns the tangents between the active CircularArc3d instance complete circle and another one.
           /// </summary>
           /// <remarks>
           /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
           /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
           /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
           /// </remarks>
           /// <param name="arc">The object to which this method applies.</param>
           /// <param name="other">The CircularArc3d to which searched for tangents.</param>
           /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
           /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
           /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
           public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags)
           {
               // check if circles lies on the same plane
               Vector3d normal = arc.Normal;
               double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
               double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
               if (!(normal.IsParallelTo(other.Normal) &&
                   Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
                   throw new Autodesk.AutoCAD.Runtime.Exception(
                       Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
     
               // check if a circle is inside the other
               double dist = arc.Center.DistanceTo(other.Center);
               if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint)
                   return null;
     
               // check if circles overlap
               bool overlap = arc.Radius + other.Radius >= dist;
               if (overlap && flags == TangentType.Inner)
                   return null;
     
               CircularArc3d tmp1, tmp2;
               Point3d[] inters;
               Vector3d vec1, vec2, vec = other.Center - arc.Center;
               int i, j;
               LineSegment3d[] result = new LineSegment3d[(int)flags == 3 && !overlap ? 4 : 2];
     
               // outer tangents
               if (flags.HasFlag(TangentType.Outer))
               {
                   if (arc.Radius == other.Radius)
                   {
                       Line3d perp = new Line3d(arc.Center, vec.CrossProduct(normal));
                       inters = arc.IntersectWith(perp);
                       vec1 = (inters[0] - arc.Center).GetNormal();
                       vec2 = (inters[1] - arc.Center).GetNormal();
                       i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
                       j = i ^ 1;
                       result[i] = new LineSegment3d(inters[0], inters[0] + vec);
                       result[j] = new LineSegment3d(inters[1], inters[1] + vec);
                   }
                   else
                   {
                       Point3d center = arc.Radius < other.Radius ? other.Center : arc.Center;
                       tmp1 = new CircularArc3d(center, normal, Math.Abs(arc.Radius - other.Radius));
                       tmp2 = new CircularArc3d(arc.Center + vec / 2.0, normal, dist / 2.0);
                       inters = tmp1.IntersectWith(tmp2);
                       vec1 = (inters[0] - center).GetNormal();
                       vec2 = (inters[1] - center).GetNormal();
                       i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
                       j = i ^ 1;
                       result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
                       result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
                   }
               }
     
               // inner tangents
               if (flags.HasFlag(TangentType.Inner) && !overlap)
               {
                   double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
                   tmp1 = new CircularArc3d(arc.Center + vec * ratio, normal, dist * ratio);
                   inters = arc.IntersectWith(tmp1);
                   vec1 = (inters[0] - arc.Center).GetNormal();
                   vec2 = (inters[1] - arc.Center).GetNormal();
                   i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 2 : 3;
                   j = i == 2 ? 3 : 2;
                   result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
                   result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
               }
               return result;
           }
     
           /// <summary>
           /// Returns the tangents between the active CircularArc3d instance complete circle and a point.
           /// </summary>
           /// <remarks>
           /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
           /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
           /// to the point before the one on the right side.
           /// </remarks>
           /// <param name="arc">The object to which this method applies.</param>
           /// <param name="pt">The Point3d to which tangents are searched</param>
           /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns>
           /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
           public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt)
           {
               // check if circle and point lies on the plane
               Vector3d normal = arc.Normal;
               double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
               double elev2 = pt.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
               if (Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint)
                   throw new Autodesk.AutoCAD.Runtime.Exception(
                       Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
     
               // check if the point is inside the circle
               Point3d center = arc.Center;
               if (pt.DistanceTo(center) <= arc.Radius)
                   return null;
     
               Vector3d vec = pt.GetVectorTo(center) / 2.0;
               CircularArc3d tmp = new CircularArc3d(pt + vec, arc.Normal, vec.Length);
               Point3d[] inters = arc.IntersectWith(tmp);
               LineSegment3d[] result = new LineSegment3d[2];
               int i = vec.GetAngleTo(inters[0] - center, normal) < vec.GetAngleTo(inters[1] - center, normal) ? 0 : 1;
               int j = i ^ 1;
               result[i] = new LineSegment3d(inters[0], pt);
               result[j] = new LineSegment3d(inters[1], pt);
               return result;
           }
       }
    }
     

A (maybe usefull) command example which draws a closed polyline along the outer tangents and the trimmed selected circles.

Code: [Select]
            [CommandMethod("JoinCircles", CommandFlags.Modal)]
           public void JoinCircles()
           {
               Document doc = Application.DocumentManager.MdiActiveDocument;
               Database db = doc.Database;
               Editor ed = doc.Editor;
     
               PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
               peo.SetRejectMessage("Only a circle.");
               peo.AddAllowedClass(typeof(Circle), true);
               PromptEntityResult per = ed.GetEntity(peo);
               if (per.Status != PromptStatus.OK)
                   return;
               ObjectId id1 = per.ObjectId;
     
               peo.Message = "\nSelect another circle: ";
               ObjectId id2;
               while (true)
               {
                   per = ed.GetEntity(peo);
                   if (per.Status != PromptStatus.OK)
                       return;
                   id2 = per.ObjectId;
                   if (id1 == id2)
                       ed.WriteMessage("\nThe second circle is the same as the first one.");
                   else break;
               }
     
               try
               {
                   using (Transaction tr = db.TransactionManager.StartTransaction())
                   {
                       Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
                       Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
                       CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
                       CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
                       LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Outer);
                       if (lines != null)
                       {
                           BlockTableRecord btr =
                               (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                           Vector3d vec = c1.Center.GetVectorTo(c2.Center);
                           Plane plane = new Plane(Point3d.Origin, c1.Normal);
                           double a1 = vec.GetAngleTo(ca1.Center.GetVectorTo(lines[1].StartPoint), ca1.Normal) -
                               vec.GetAngleTo(ca1.Center.GetVectorTo(lines[0].StartPoint), ca1.Normal);
                           double a2 = vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[0].EndPoint), ca1.Normal) -
                               vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[1].EndPoint), ca1.Normal);
                           Polyline pline = new Polyline(4);
                           pline.AddVertexAt(0, lines[0].StartPoint.Convert2d(plane), Math.Tan(a1 / 4.0), 0.0, 0.0);
                           pline.AddVertexAt(1, lines[1].StartPoint.Convert2d(plane), 0.0, 0.0, 0.0);
                           pline.AddVertexAt(2, lines[1].EndPoint.Convert2d(plane), Math.Tan(a2 / 4.0), 0.0, 0.0);
                           pline.AddVertexAt(3, lines[0].EndPoint.Convert2d(plane), 0.0, 0.0, 0.0);
                           pline.Closed = true;
                           pline.Normal = c1.Normal;
                           pline.Elevation = c1.Center.TransformBy(Matrix3d.WorldToPlane(c1.Normal)).Z;
                           btr.AppendEntity(pline);
                           tr.AddNewlyCreatedDBObject(pline, true);
                           c1.UpgradeOpen();
                           c2.UpgradeOpen();
                           c1.Erase();
                           c2.Erase();
                       }
                       tr.Commit();
                   }
               }
               catch (System.Exception exn)
               {
                   ed.WriteMessage("\nError: " + exn.Message);
               }
           }
15
Tables / How to merge cells
« Last post by fixo on August 16, 2013, 01:24:30 PM »
Here is very basic code to creating dummy table
with merged cells, tested from A2010 through A2014:

Code: [Select]
        [CommandMethod("mcit")]
        public void MergeCellsInTable()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            int numRows = 7;
            int numCols = 4;
            double rowHeight = 15.0;
            double colWidth = 45.0;
            double verMarg = 2.5;
            double horMarg = 2.5;
            double txtHeight = 10.0;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                Table tb = new Table();
                tb.SetDatabaseDefaults();
               // Pick location
                tb.Position = ed.GetPoint("\nSpecify table location: ").Value;
                tb.Color = Color.FromRgb(107, 27, 0);         
                tb.LineWeight = LineWeight.LineWeight035;
                tb.Normal = new Vector3d(0, 0, 1);// or the same as Vector3d.Zaxis
                //To speed up regenerate table
                tb.SuppressRegenerateTable(true); //<-- optional
                tb.TableStyle = db.Tablestyle;
                // Set the height and width of the initial row and
                // column belonging by default to the blank Table
                tb.Rows[0].Height = rowHeight;
                tb.Rows[0].BackgroundColor = Color.FromRgb(148, 153, 194);
               
                tb.Columns[0].Width = colWidth;
                // Add the remaining rows and columns
                tb.InsertRows(1, rowHeight, numRows);
                tb.InsertColumns(1, colWidth, numCols - 1);
                tb.Rows[0].IsMergeAllEnabled = true;
                tb.Rows[0].Height = rowHeight;
                tb.Rows[0].TextHeight = txtHeight;
                tb.Rows[1].Height = rowHeight;
                tb.Rows[1].TextHeight = txtHeight;
                // Add the contents of the Title cell
                Cell tc = tb.Cells[0, 0];
                tc.Contents.Add();
                tc.Contents[0].TextHeight = txtHeight;
                tc.Contents[0].TextString = "Title";
                // Add some flowers
                // Column widths might be vary
                List<double> wids = new List<double>(new double[] { 65,70,70,65 });
                List<string[]> tabledata = new List<string[]>(){
                     new string[]{"alpha","bravo","charlie","delta"},
                     new string[]{"echo","foxtrott","golf","hotel"},
                     new string[]{"india","juliett","kilo","lima"},
                     new string[]{"mike","november","oscar","papa"},
                     new string[]{"quebec","romeo","sierra","tango"},
                     new string[]{"uniform","victor","whiskey","x-ray"},
                 new string[]{"yankee","zulu","fixo","over"}};
                for (int j = 0; j < numCols; j++)
                {
                    tb.Columns[j].Width = wids[j];
                    tb.Columns[j].Alignment = CellAlignment.MiddleCenter;
                    short color=16;
                    if (j > 0)  color = 16;
                    tb.Columns[j].ContentColor = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, color);
                }
                for (int i = 1; i <= numRows; i++)
                {
                    tb.Rows[i].Height = rowHeight; tb.Rows[i].TextStyleId = db.Textstyle;
                    //tb.Rows[i].TextStyleId = txtId '<-- potential crash of Acad, you can  use SetTextStyle method also, not sure about, maybe it obsolete in this Acad version
                    tb.Rows[i].Borders.Horizontal.Margin = rowHeight * 0.1;
                    tb.Rows[i].Borders.Vertical.Margin = rowHeight * 0.1;
                }

                // Align Title text to center
                tb.Rows[0].Alignment = CellAlignment.MiddleCenter;
                tb.Rows[0].ContentColor = Color.FromRgb(255, 200, 36);
                // Populate the contents of the header and data sections
                // int n = 0;
                for (int i = 1; i <= numRows; i++)
                {
                    string[] items = tabledata[i - 1];
                    // tb.Rows[i].Style = "Data";

                    for (int j = 0; j <= numCols - 1; j++)
                    {
                        Cell c = tb.Cells[i, j];
                        c.Contents.Add();
                        c.Contents[0].TextHeight = txtHeight;
                        string txt = items[j];
                        c.Contents[0].TextString = txt;
                        c.Alignment = CellAlignment.MiddleCenter;
                        // Set the vertical margins
                        c.Borders.Top.Margin = verMarg;
                        c.Borders.Bottom.Margin = verMarg;
                        // Set the horizontal margins
                        c.Borders.Left.Margin = horMarg;
                        c.Borders.Right.Margin = horMarg;
                    }
                }
                tb.Rows[1].Alignment = CellAlignment.MiddleCenter;
                tb.InsertRows(1, rowHeight, 2);
                tb.Rows[1].BackgroundColor = Color.FromRgb(226, 214, 187);
                tb.Rows[2].BackgroundColor = Color.FromRgb(226, 214, 187);
               
               CellRange mcells = CellRange.Create(tb, 1, 0, 1, 1);
               tb.MergeCells(mcells);
               Cell mc = tb.Cells[1, 0];
               mc.Contents.Add();
               mc.Contents[0].TextHeight = txtHeight;
               string mtxt = "Merged";
               mc.Contents[0].TextString = mtxt;
               mc.Alignment = CellAlignment.MiddleCenter;


               mcells = CellRange.Create(tb, 2, 1, 2, 2);
               tb.MergeCells(mcells);
                mc = tb.Cells[2, 1];
               mc.Contents.Add();
               mc.Contents[0].TextHeight = txtHeight;
                mtxt = "Merged";
               mc.Contents[0].TextString = mtxt;
               mc.Alignment = CellAlignment.MiddleCenter;

               mcells = CellRange.Create(tb, 1, 3, 2, 3);
               tb.MergeCells(mcells);
               mc = tb.Cells[1, 3];
               mc.Contents.Add();
               mc.Contents[0].TextHeight = txtHeight;
               mtxt = "Merged";
               mc.Contents[0].TextString = mtxt;
               mc.Alignment = CellAlignment.MiddleCenter;

               //tb.Height = tb.Rows.Count * rowHeight; //<-- optional

               tb.Rows[0].Height *=2.0;
                // insert very last row
               tb.InsertRows(tb.Rows.Count, rowHeight, 1);
               tb.Rows[tb.Rows.Count-1].Style = "Data";
                // merge the first 3 cells in row
               mcells = CellRange.Create(tb, tb.Rows.Count-1, 0, tb.Rows.Count-1, 2);
               tb.MergeCells(mcells);
               mc = tb.Cells[tb.Rows.Count-1, 0];
               mc.Contents.Add();
               mc.Contents[0].TextHeight = txtHeight;
               mtxt = "Total:";
               mc.Contents[0].TextString = mtxt;
               mc.Alignment = CellAlignment.MiddleRight;

                // alternate coloring rows
               for (int i = 3; i < tb.Rows.Count-1; i++)
               {
                   if (i % 2 == 0)
                       tb.Rows[i].BackgroundColor = Color.FromRgb(241, 238, 234);
                   else tb.Rows[i].BackgroundColor = Color.FromRgb(233, 241, 246);

               }
               tb.Rows[tb.Rows.Count - 1].BackgroundColor = Color.FromRgb(222, 248, 242);
                tb.GenerateLayout();
                 tb.SuppressRegenerateTable(false); //<-- optional

                 btr.AppendEntity(tb);

                tr.AddNewlyCreatedDBObject(tb, true);
               
                tr.Commit();
                // change lwdisplay to on so the display will be show the table lineweight
                Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("lwdisplay", 1);
               
            }
        }
16
Display / predefined views
« Last post by (gile) on August 14, 2013, 08:21:16 PM »
Hi,

Here's a method to set orthogonal or isometric views.
The zoom is equivalent to a zoom extents plus a zoom 0.8X.

The following code defines also 10 commands to set predefined views with the numpad.

Code: [Select]
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

[assembly: CommandClass(typeof(ViewSample.CommandMethods))]

namespace ViewSample
{
    public class CommandMethods
    {
        enum ViewDirection { Top, Bottom, Front, Back, Left, Right, SeIso, SwIso, NeIso, NwIso }

        private void SetView(ViewDirection vDir)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            Vector3d viewDir = new Vector3d();
            switch (vDir)
            {
                case ViewDirection.Top:
                    viewDir = Vector3d.ZAxis; break;
                case ViewDirection.Bottom:
                    viewDir = Vector3d.ZAxis.Negate(); break;
                case ViewDirection.Front:
                    viewDir = Vector3d.YAxis.Negate(); break;
                case ViewDirection.Back:
                    viewDir = Vector3d.YAxis; break;
                case ViewDirection.Left:
                    viewDir = Vector3d.XAxis.Negate(); break;
                case ViewDirection.Right:
                    viewDir = Vector3d.XAxis; break;
                case ViewDirection.SeIso:
                    viewDir = new Vector3d(1.0, -1.0, 1.0); break;
                case ViewDirection.SwIso:
                    viewDir = new Vector3d(-1.0, -1.0, 1.0); break;
                case ViewDirection.NeIso:
                    viewDir = new Vector3d(1.0, 1.0, 1.0); break;
                case ViewDirection.NwIso:
                    viewDir = new Vector3d(-1.0, 1.0, 1.0); break;
            }

            db.UpdateExt(true);
            Extents3d extents = db.TileMode ?
                new Extents3d(db.Extmin, db.Extmax) :
                (int)Application.GetSystemVariable("CVPORT") == 1 ?
                    new Extents3d(db.Pextmin, db.Pextmax) :
                    new Extents3d(db.Extmin, db.Extmax);

            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (ViewTableRecord view = ed.GetCurrentView())
            {
                Matrix3d viewTransform =
                    Matrix3d.PlaneToWorld(viewDir)
                    .PreMultiplyBy(Matrix3d.Displacement(view.Target - Point3d.Origin))
                    .PreMultiplyBy(Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target))
                    .Inverse();

                extents.TransformBy(viewTransform);

                view.ViewDirection = viewDir;
                view.Width = (extents.MaxPoint.X - extents.MinPoint.X) * 1.25;
                view.Height = (extents.MaxPoint.Y - extents.MinPoint.Y) * 1.25;
                view.CenterPoint = new Point2d(
                    (extents.MinPoint.X + extents.MaxPoint.X) / 2.0,
                    (extents.MinPoint.Y + extents.MaxPoint.Y) / 2.0);
                ed.SetCurrentView(view);
                tr.Commit();
            }
        }

        [CommandMethod("0")]
        public void ViewBottom()
        {
            SetView(ViewDirection.Bottom);
        }

        [CommandMethod("1")]
        public void ViewSouthWestIso()
        {
            SetView(ViewDirection.SwIso);
        }

        [CommandMethod("2")]
        public void ViewFront()
        {
            SetView(ViewDirection.Front);
        }

        [CommandMethod("3")]
        public void ViewSeIso()
        {
            SetView(ViewDirection.SeIso);
        }

        [CommandMethod("4")]
        public void ViewLeft()
        {
            SetView(ViewDirection.Left);
        }

        [CommandMethod("5")]
        public void ViewTop()
        {
            SetView(ViewDirection.Top);
        }

        [CommandMethod("6")]
        public void ViewSouthEastIso()
        {
            SetView(ViewDirection.Right);
        }

        [CommandMethod("7")]
        public void ViewNorthWestIso()
        {
            SetView(ViewDirection.NwIso);
        }

        [CommandMethod("8")]
        public void ViewBack()
        {
            SetView(ViewDirection.Back);
        }

        [CommandMethod("9")]
        public void ViewNorthEastIso()
        {
            SetView(ViewDirection.NeIso);
        }
    }
}
17
AutoCAD talk / Re: AutoCAD Exchange apps now online
« Last post by (gile) on August 14, 2013, 08:15:33 PM »
Hi,

You have to code your own limitation / timeout in your trial app.
18
AutoCAD talk / Re: AutoCAD Exchange apps now online
« Last post by madmat on August 14, 2013, 08:07:13 AM »
Hello,

Do you know how the trial mode works when you publish an app on Autodesk Exchange?
Does it have to be a part of the plugin code? If that's true, is there a anywhere a support about how to do it to be compatible with Exchange?
I haven't found any option about trial in the publishing procedure of the exchange app, only the button to choose trial but no timetrial or limited number of uses...

Regards,
Matthieu
19
Blocks / Write selected blocks to .csv file
« Last post by fixo on July 01, 2013, 08:24:18 PM »
Code: [Select]
        [CommandMethod("BCSV")]
        public static void WriteBlocksToCSV()
        {
            System.Globalization.CultureInfo oldcult = System.Threading.Thread.CurrentThread.CurrentCulture;
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("EN-us");

            Database db = HostApplicationServices.WorkingDatabase;
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            string fname = @"C:\Test\Block_PART.csv";


            // Enter block name to be written
            PromptStringOptions psto = new PromptStringOptions("\nEnter block name: ");
            psto.AllowSpaces = true;
            PromptResult res;
            res = ed.GetString(psto);
            if (res.Status != PromptStatus.OK)
                return;
            string blkname = res.StringResult;

            ed.WriteMessage("\nBlock Name Entered:\t{0}", blkname);

            // put appropriate delimiter here I've used semicolon (it's default delimiter on my local machine)
            string sep = ";";

            Matrix3d mtx = ed.CurrentUserCoordinateSystem;
            List<string> data = new List<string>();
            PromptSelectionOptions pso = new PromptSelectionOptions();
            pso.MessageForRemoval = "\nNothing selected, try again...";
            pso.MessageForAdding = "\nPlease select blocks on screen: ";
            TypedValue[] tv = new TypedValue[] { new TypedValue(0, "insert"), new TypedValue(2, blkname), new TypedValue(66, 1) };
            SelectionFilter filter = new SelectionFilter(tv);
            PromptSelectionResult psr = ed.GetSelection(pso, filter);

            if (psr.Status != PromptStatus.OK)
            {
                ed.WriteMessage("\nSelection Result: {0}", psr.Status);
                return;
            }

            SelectionSet sset = psr.Value;
            ed.WriteMessage("\nSelected blocks: {0}", sset.Count);
            if (sset.Count == 0)
            {
                ed.WriteMessage("\nNothing Selected, exit...");
                return;
            }

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

                try
                {
                    string headers = string.Format("{0}{8}{1:f3}{8}{2:f3}{8}{3:f3}{8}{4:f3}{8}{5:f3}{8}{6:f3}{8}{7:f3}{8}{9}",
                                "HANDLE", "X_Coordinate", "Y_Coordinate", "Z_Coordinate", "Rotation", "X_Scale", "Y_Scale", "Z_Scale", sep, "Attributes >>");
                    data.Add(headers);
                    foreach (SelectedObject sobj in sset)
                    {
                        ObjectId id = sobj.ObjectId;
                        Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                        if (ent == null) return;
                        BlockReference bref = ent as BlockReference;
                        if (bref == null) return;
                        string hdl = bref.Handle.ToString();
                        Point3d pp = bref.Position.TransformBy(Matrix3d.Identity);
                        double rot = bref.Rotation;
                        Scale3d scl = bref.ScaleFactors;
                        AttributeCollection attids = bref.AttributeCollection;
                        string attvalues = sep;
                        foreach (ObjectId attid in attids)
                        {
                            AttributeReference attref = tr.GetObject(attid, OpenMode.ForRead) as AttributeReference;
                            string attval = attref.TextString;
                            // to avoid writing text like 04-01 as "04 Jan." in csv file add single quote at the start
                            if (attval.Contains("-")) attval = string.Format("'{0}", attval);
                            attvalues = attvalues + attval + sep;
                        }
                        attvalues = attvalues.TrimEnd(',');
                        // create delimted text line for every block
                        string strtmp = string.Format("{0}{8}{1:f3}{8}{2:f3}{8}{3:f3}{8}{4:f3}{8}{5:f3}{8}{6:f3}{8}{7:f3}{9}",
                                hdl, pp.X, pp.Y, pp.Z, rot, scl.X, scl.Y, scl.Z, sep, attvalues);

                        data.Add(strtmp);
                    }
                    if (data.Count > 1)
                    {
                        try
                        {
                            if (File.Exists(fname))
                            {
                             // delete existing file
                            File.Delete(fname);// to write always to newly created file
                            }
                            using (StreamWriter sw = new StreamWriter(fname, true, Encoding.Default, 4096))
                            {
                                foreach (string coords in data)
                                {
                                    sw.WriteLine(coords);
                                }

                            }

                        }
                        catch (IOException iex)
                        {
                            ed.WriteMessage("\nError while processing the file.:\n{0}\n", iex.Message);

                        }
                        catch (System.Exception ex)
                        {
                            ed.WriteMessage("\nError writinging data to file.:\n{0}\n", ex.Message);

                        }

                    }

                }
                catch (Autodesk.AutoCAD.Runtime.Exception acex)
                {
                    ed.WriteMessage("\nError occurs in AutoCAD drawing.:\n{0}\n", acex.ToString());
                }
                catch (System.Exception sys)
                {
                    ed.WriteMessage("\nError:\n{0}\n", sys.ToString());
                }
                finally
                {

                    System.Diagnostics.Process.Start(fname);
                    ed.WriteMessage("\n\t---\tDone!\t---\n");
                    System.Threading.Thread.CurrentThread.CurrentCulture = oldcult;
                }
            }
        }
20
Selection sets / Change filtering criteria during the selection
« Last post by (gile) on June 30, 2013, 10:04:34 AM »
This is just a example to show how it is possible to change the filtering criteria during the selection using Editor.SelectionAdded event.

In this example, the selection starts filtering lines and allows the user to change the filtered entities to circles or polylines by specifying keywords.

C#
Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

namespace SelectionSample
{
    public class CommandMethods
    {
        private string keyWord;

        [CommandMethod("Test")]
        public void Test()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            this.keyWord = "LIne";

            PromptSelectionOptions opt = new PromptSelectionOptions();
            opt.SetKeywords("[CIrcle/LIne/POlyline]", "CIrcle LIne POlyline");
            opt.MessageForAdding = "\nSelect objects or " + opt.Keywords.GetDisplayString(true);
            opt.KeywordInput += onKeywordInput;

            ed.SelectionAdded += onSelectionAdded;
            PromptSelectionResult psr = ed.GetSelection(opt);
            ed.SelectionAdded -= onSelectionAdded;
            if (psr.Status == PromptStatus.OK)
                ed.SetImpliedSelection(psr.Value);
        }

        private void onKeywordInput(object sender, SelectionTextInputEventArgs e)
        {
            this.keyWord = e.Input;
        }

        private void onSelectionAdded(object sender, SelectionAddedEventArgs e)
        {
            RXClass rxc;
            switch (this.keyWord)
            {
                case "POlyline": rxc = RXClass.GetClass(typeof(Polyline)); break;
                case "CIrcle": rxc = RXClass.GetClass(typeof(Circle)); break;
                default: rxc = RXClass.GetClass(typeof(Line)); break;
            }
            ObjectId[] ids = e.AddedObjects.GetObjectIds();
            for (int i = 0; i < ids.Length; i++)
            {
                if (ids[i].ObjectClass != rxc)
                    e.Remove(i);
            }
        }
    }
}

VB
Code: [Select]
Imports System.Collections.Generic
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

Namespace SelectionSample

    Public Class CommandMethods

        Private keyWord As String

        <CommandMethod("Test")> _
        Public Sub Test()
            Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

            Me.keyWord = "LIne"

            Dim opt As New PromptSelectionOptions()
            opt.SetKeywords("[CIrcle/LIne/POlyline]", "CIrcle LIne POlyline")
            opt.MessageForAdding = vbLf & "Select objects or " & opt.Keywords.GetDisplayString(True)
            AddHandler opt.KeywordInput, AddressOf onKeywordInput

            AddHandler ed.SelectionAdded, AddressOf onSelectionAdded
            Dim psr As PromptSelectionResult = ed.GetSelection(opt)
            RemoveHandler ed.SelectionAdded, AddressOf onSelectionAdded
            If psr.Status = PromptStatus.OK Then
                ed.SetImpliedSelection(psr.Value)
            End If
        End Sub

        Private Sub onKeywordInput(sender As Object, e As SelectionTextInputEventArgs)
            Me.keyWord = e.Input
        End Sub

        Private Sub onSelectionAdded(sender As Object, e As SelectionAddedEventArgs)
            Dim rxc As RXClass
            Select Case Me.keyWord
                Case "POlyline"
                    rxc = RXClass.GetClass(GetType(Polyline))
                    Exit Select
                Case "CIrcle"
                    rxc = RXClass.GetClass(GetType(Circle))
                    Exit Select
                Case Else
                    rxc = RXClass.GetClass(GetType(Line))
                    Exit Select
            End Select
            Dim ids As ObjectId() = e.AddedObjects.GetObjectIds()
            For i As Integer = 0 To ids.Length - 1
                If ids(i).ObjectClass <> rxc Then
                    e.Remove(i)
                End If
            Next
        End Sub

    End Class

End Namespace

F#
Code: [Select]
module SelectionSample

open System.Collections.Generic
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime

[<CommandMethod("Test")>]
let test () =
    let ed = Application.DocumentManager.MdiActiveDocument.Editor

    let keyWord = ref "LIne"

    let opt = new PromptSelectionOptions()
    opt.SetKeywords("[CIrcle/LIne/POlyline]", "CIrcle LIne POlyline")
    opt.MessageForAdding <- "\nSelect objects or " + opt.Keywords.GetDisplayString(true)
    opt.KeywordInput.Add(fun (e: SelectionTextInputEventArgs) -> keyWord := e.Input)

    let onSelectionAdded =
        new SelectionAddedEventHandler(fun _ e ->
            let rxc =
                RXClass.GetClass(
                    match !keyWord with
                    | "CIrcle"   -> typeof<Circle>
                    | "POlyline" -> typeof<Polyline>
                    | _          -> typeof<Line>)
            e.AddedObjects.GetObjectIds()
            |> Array.iteri(fun i id -> if id.ObjectClass <> rxc then e.Remove(i)))

    ed.SelectionAdded.AddHandler(onSelectionAdded)
    let psr = ed.GetSelection(opt)
    ed.SelectionAdded.RemoveHandler(onSelectionAdded)
    if psr.Status = PromptStatus.OK then
        ed.SetImpliedSelection(psr.Value)
Pages: 1 [2] 3 4 ... 10