Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - (gile)

Pages: 1 [2]
16
Blocks / Block attributes extraction
« on: November 06, 2011, 10:51:54 AM »
Hi,

Here's a little example for attributes extraction.

I try to write it in a "declarative" style using the Linq extension methods and some others defined in the Extension class (thanks to Thorsten 'kaefer' @ TheSwamp for its nice 'evil' ones).

The extraction is collected in a System.Data.DataTable so that it can be easily converted to an AutoCAD table, an Exel sheet and so on.
The DataTable.WriteXls() extension method uses late binding while interacting with Excel application to avoid version reference dependency.

The BlockAttribute class which defines a new Type which main properties are:
- Block:  the block (effective) name ;
- Attributes: a dictionary for the block attributes where Key is the tag and Value the text string.
The BlockAttributeEqualityComparer class implements the IEqualityComparer<BlockAttribute> interface so that BlockAttribute collections can be used with some Linq extension methods as GroupBy().
Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace AttributeExtraction
{
    public class BlockAttribute
    {
        private string _name;
        private Dictionary<string, string> _atts;

        // Public read only properties
        public string Name
        {
            get { return _name; }
        }

        public Dictionary<string, string> Attributes
        {
            get { return _atts; }
        }

        public string this[string key]
        {
            get { return _atts[key.ToUpper()]; }
        }

        // Constructors
        public BlockAttribute(BlockReference br)
        {
            SetProperties(br);
        }

        public BlockAttribute(ObjectId id)
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                SetProperties(tr.GetObject(id, OpenMode.ForRead) as BlockReference);
            }
        }

        // Public method
        new public string ToString()
        {
            if (_atts != null && _atts.Count > 0)
                return string.Format("{0}: {1}",
                    _name,
                    _atts.Select(a => string.Format("{0}={1}", a.Key, a.Value))
                        .Aggregate((a, b) => string.Format("{0}; {1}", a, b)));
            return _name;
        }

        // Private method
        private void SetProperties(BlockReference br)
        {
            if (br == null) return;
            _name = br.GetEffectiveName();
            _atts = new Dictionary<string, string>();
            br.AttributeCollection
                .GetObjects<AttributeReference>()
                .Iterate(att => _atts.Add(att.Tag.ToUpper(), att.TextString));
        }
    }

    public class BlockAttributeEqualityComparer : IEqualityComparer<BlockAttribute>
    {
        public bool Equals(BlockAttribute x, BlockAttribute y)
        {
            return
                x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase) &&
                x.Attributes.SequenceEqual(y.Attributes);
        }

        public int GetHashCode(BlockAttribute obj)
        {
            return base.GetHashCode();
        }
    }
}

The Extensions class provides extension methods that allows to write code in a more "declarative" style
and methods to build a DataTable from a BlockAttribute collection and convert this DataTable into xls, csv files or AutoCAD Table.
Code: [Select]
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;
using AcDataTable = Autodesk.AutoCAD.DatabaseServices.DataTable;
using Autodesk.AutoCAD.Runtime;

namespace AttributeExtraction
{
    public static class Extensions
    {
        // Thorsten's 'evil' extension methods (thanks again to him)
        public static T GetObject<T>(this ObjectId id) where T : DBObject
        {
            return id.GetObject<T>(OpenMode.ForRead);
        }

        public static T GetObject<T>(this ObjectId id, OpenMode openMode) where T : DBObject
        {
            return id.GetObject(openMode, false, false) as T;
        }

        public static IEnumerable<T> GetObjects<T>(this IEnumerable ids) where T : DBObject
        {
            return ids.GetObjects<T>(OpenMode.ForRead);
        }

        public static IEnumerable<T> GetObjects<T>(this IEnumerable ids, OpenMode openMode) where T : DBObject
        {
            RXClass rxc = RXObject.GetClass(typeof(T));
            return ids
                .Cast<ObjectId>()
                .Where(id => id.ObjectClass == rxc || id.ObjectClass.IsDerivedFrom(rxc))
                .Select(id => (T)id.GetObject(openMode, false, false));
        }

        // Mimics the F# Seq.iter function
        public static void Iterate<T>(this IEnumerable<T> collection, Action<T> action)
        {
            foreach (T item in collection) action(item);
        }

        // Mimics the F# Seq.iteri function
        public static void Iterate<T>(this IEnumerable<T> collection, Action<T, int> action)
        {
            int i = 0;
            foreach (T item in collection) action(item, i++);
        }

        // Gets the block effective name (anonymous dynamic blocs)
        public static string GetEffectiveName(this BlockReference br)
        {
            if (br.IsDynamicBlock)
                return br.DynamicBlockTableRecord.GetObject<BlockTableRecord>().Name;
            return br.Name;
        }

        // Creates a Datatable from a BlockAttribute collection
        public static System.Data.DataTable ToDataTable(this IEnumerable<BlockAttribute> blockAtts, string name)
        {
            System.Data.DataTable dTable = new System.Data.DataTable(name);
            dTable.Columns.Add("Name", typeof(string));
            dTable.Columns.Add("Quantity", typeof(int));
            blockAtts
                .GroupBy(blk => blk, (blk, blks) => new { Block = blk, Count = blks.Count() }, new BlockAttributeEqualityComparer())
                .Iterate(row =>
                {
                    System.Data.DataRow dRow = dTable.Rows.Add(row.Block.Name, row.Count);
                    row.Block.Attributes.Iterate(att =>
                    {
                        if (!dTable.Columns.Contains(att.Key))
                            dTable.Columns.Add(att.Key);
                        dRow[att.Key] = att.Value;
                    });
                });
            return dTable;
        }

        // Converts a Datatble into a two dimensional object array
        public static object[,] ToArray(this System.Data.DataTable dTable)
        {
            int numRows = dTable.Rows.Count;
            int numColoumns = dTable.Columns.Count;
            object[,] result = new object[numRows + 1, numColoumns];
            string[] colNames = dTable.GetColumnNames().ToArray();
            for (int i = 0; i < numColoumns; i++)
            {
                result[0, i] = colNames[i];
            }
            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColoumns; j++)
                {
                    result[i + 1, j] = dTable.Rows[i][j];
                }
            }
            return result;
        }

        // Gets the column names collection of the Datatable
        public static IEnumerable<string> GetColumnNames(this System.Data.DataTable dataTbl)
        {
            return dataTbl.Columns.Cast<System.Data.DataColumn>().Select(col => col.ColumnName);
        }

        // Writes a xls file from the datatable
        public static void WriteXls(this System.Data.DataTable dataTbl, string filename, string sheetName, bool visible)
        {
            object mis = Type.Missing;
            object xlApp = LateBinding.GetOrCreateInstance("Excel.Application");
            xlApp.Set("DisplayAlerts", false);
            object workbooks = xlApp.Get("Workbooks");
            object workbook, worksheet;
            if (File.Exists(filename))
                workbook = workbooks.Invoke("Open", filename);
            else
                workbook = workbooks.Invoke("Add", mis);
            if (string.IsNullOrEmpty(sheetName))
                worksheet = workbook.Get("Activesheet");
            else
            {
                object worksheets = workbook.Get("Worksheets");
                try
                {
                    worksheet = worksheets.Get("Item", sheetName);
                    worksheet.Get("Cells").Invoke("Clear");
                }
                catch
                {
                    worksheet = worksheets.Invoke("Add", mis);
                    worksheet.Set("Name", sheetName);
                }
            }
            object range = worksheet.Get("Range",
                worksheet.Get("Cells", 1, 1),
                worksheet.Get("Cells", dataTbl.Rows.Count + 1, dataTbl.Columns.Count));
            range.Set("NumberFormat", "@");
            range.Set("Value2", dataTbl.ToArray());
            xlApp.Set("DisplayAlerts", true);
            if (visible)
            {
                xlApp.Set("Visible", true);
            }
            else
            {
                if (File.Exists(filename))
                    workbook.Invoke("Save");
                else
                {
                    int fileFormat =
                        string.Compare("11.0", (string)xlApp.Get("Version")) < 0 &&
                        filename.EndsWith(".xlsx", StringComparison.CurrentCultureIgnoreCase) ?
                        51 : -4143;
                    workbook.Invoke("Saveas", filename, fileFormat, string.Empty, string.Empty, false, false, 1, 1);
                }
                workbook.Invoke("Close");
                workbook = null;
                xlApp.Invoke("Quit");
                xlApp.ReleaseInstance();
                xlApp = null;
            }
        }

        // Writes a csv file from the datatable
        public static void WriteCsv(this System.Data.DataTable dataTbl, string filename)
        {
            using (StreamWriter writer = new StreamWriter(filename))
            {
                writer.WriteLine(dataTbl.GetColumnNames().Aggregate((s1, s2) => string.Format("{0},{1}", s1, s2)));
                dataTbl.Rows
                    .Cast<DataRow>()
                    .Select(row => row.ItemArray.Aggregate((s1, s2) => string.Format("{0},{1}", s1, s2)))
                    .Iterate(line => writer.WriteLine(line));
            }
        }

        // Creates an AutoCAD Table from the datatable
        public static Table ToAcadTable(this System.Data.DataTable dataTbl, double rowHeight, double columnWidth)
        {
            Table tbl = new Table();
            tbl.Rows[0].Height = rowHeight;
            tbl.Columns[0].Width = columnWidth;
            tbl.InsertColumns(0, columnWidth, dataTbl.Columns.Count - 1);
            tbl.InsertRows(0, rowHeight, dataTbl.Rows.Count + 1);
            tbl.Cells[0, 0].Value = dataTbl.TableName;
            dataTbl.GetColumnNames()
                .Iterate((name, i) => tbl.Cells[1, i].Value = name);
            dataTbl.Rows
                .Cast<DataRow>()
                .Iterate((row, i) =>
                    row.ItemArray.Iterate((item, j) =>
                        tbl.Cells[i + 2, j].Value = item));
            return tbl;
        }
    }
}

The LateBinding class provides helpers to write late binding instructions in a more friendly style (thanks to Thorsten and Tony T).
Code: [Select]
using BF = System.Reflection.BindingFlags;

namespace AttributeExtraction
{
    public static class LateBinding
    {
        public static object GetInstance(string appName)
        {
            return System.Runtime.InteropServices.Marshal.GetActiveObject(appName);
        }

        public static object CreateInstance(string appName)
        {
            return System.Activator.CreateInstance(System.Type.GetTypeFromProgID(appName));
        }

        public static object GetOrCreateInstance(string appName)
        {
            try { return GetInstance(appName); }
            catch { return CreateInstance(appName); }
        }

        public static object Get(this object obj, string propName, params object[] parameter)
        {
            return obj.GetType().InvokeMember(propName, BF.GetProperty, null, obj, parameter);
        }

        public static void Set(this object obj, string propName, params object[] parameter)
        {
            obj.GetType().InvokeMember(propName, BF.SetProperty, null, obj, parameter);
        }

        public static object Invoke(this object obj, string methName, params object[] parameter)
        {
            return obj.GetType().InvokeMember(methName, BF.InvokeMethod, null, obj, parameter);
        }

        public static void ReleaseInstance(this object obj)
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        }
    }
}

A testing command
Code: [Select]
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace AttributeExtraction
{
    public class Commands
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = { new TypedValue(0, "INSERT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            PromptPointResult ppr = ed.GetPoint("\nInsertion point: ");
            if (ppr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                System.Data.DataTable dataTable = psr.Value.GetObjectIds()
                    .Select(id => new BlockAttribute(id.GetObject<BlockReference>()))
                    .ToDataTable("Extraction");
                Table tbl = dataTable.ToAcadTable(9.0, 40.0);
                tbl.Position = ppr.Value.TransformBy(ed.CurrentUserCoordinateSystem);
                BlockTableRecord btr = db.CurrentSpaceId.GetObject<BlockTableRecord>(OpenMode.ForWrite);
                btr.AppendEntity(tbl);
                tr.AddNewlyCreatedDBObject(tbl, true);
                try
                {
                    string filename = (string)AcAp.GetSystemVariable("dwgprefix") + "Extraction.xls";
                    dataTable.WriteXls(filename, null, true);
                }
                catch
                {
                    AcAp.ShowAlertDialog("Failed to open Excel");
                }
                tr.Commit();
            }
        }
    }
}

17
.NET newbies / New AutoCAD .NET Training
« on: May 07, 2011, 10:49:08 AM »
Hi,

Autodesk provides a new 'AutoCAD .NET Training' for A2011 and A2012 (usable with Visual Studio 2008 or 2010).

Anouncement on Kean's blog: Through the Interface.

Download on Autodesk Developer Center.

18
Math and Geometry / Convex Hull
« on: April 16, 2011, 04:43:08 PM »
Here're a C# and a F# implementation of the 'Graham's scan' algorythm to get the convex hull of a 2d points collection.

[EDIT: added a C# implementation using Linq]

C# (targeting NET Framework 2.0 which is the default for A2007 -> A2009).
Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace ConvexHull
{
    public class Commands
    {
        private Point2d _p0;

        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
        {
            return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-9;
        }

        private int ComparePoints(Point2d p1, Point2d p2)
        {
            if (p1.IsEqualTo(p2)) return 0;
            double d1 = _p0.GetDistanceTo(p1);
            double d2 = _p0.GetDistanceTo(p2);
            if (d1 == 0.0) return -1;
            if (d2 == 0.0) return 1;
            double cos = (p2.X - _p0.X) / d2 - (p1.X - _p0.X) / d1;
            if (cos < -1e-9) return -1;
            if (cos > 1e-9) return 1;
            return d1.CompareTo(d2);
        }

        private List<Point2d> ConvexHull(List<Point2d> pts)
        {
            _p0 = pts[0];
            for (int i = 1; i < pts.Count; i++)
            {
                Point2d pt = pts[i];
                if (pt.Y < _p0.Y || (pt.Y == _p0.Y && pt.X < _p0.X))
                    _p0 = pt;
            }
            pts.Sort(ComparePoints);
            for (int i = 1; i < pts.Count - 1; i++)
            {
                while (i > 0 && Clockwise(pts[i - 1], pts[i], pts[i + 1]))
                {
                    pts.RemoveAt(i);
                    i--;
                }
            }
            return pts;
        }

        [CommandMethod("ch", CommandFlags.UsePickSet)]
        public void testCh()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "POINT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Polyline pline = new Polyline())
            {
                List<Point2d> pts = new List<Point2d>();
                foreach (SelectedObject so in psr.Value)
                {
                    DBPoint dbPt = (DBPoint)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
                }
                for (int i = 0; i < ConvexHull(pts).Count; i++)
                {
                    pline.AddVertexAt(i, pts[i], 0.0, 0.0, 0.0);
                }
                pline.Closed = true;
                pline.SetDatabaseDefaults();
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                btr.AppendEntity(pline);
                tr.AddNewlyCreatedDBObject(pline, true);
                tr.Commit();
            }
        }
    }
}

C# (using Linq, NET Framework 3 or upper required)
Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace LinqConvexHull
{
    public class Commands
    {
        private Point2d _p0;

        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
        {
            return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-9;
        }

        private double Cosine(Point2d pt)
        {
            double d = _p0.GetDistanceTo(pt);
            return d == 0.0 ? 1.0 : Math.Round((pt.X - _p0.X) / d, 9);
        }

        private List<Point2d> ConvexHull(List<Point2d> pts)
        {
            _p0 = pts.OrderBy(p => p.Y).ThenBy(p => p.X).First();
            pts = pts.OrderByDescending(p => Cosine(p)).ThenBy(p => _p0.GetDistanceTo(p)).ToList();
            for (int i = 1; i < pts.Count - 1; i++)
            {
                while (i > 0 && Clockwise(pts[i - 1], pts[i], pts[i + 1]))
                {
                    pts.RemoveAt(i);
                    i--;
                }
            }
            return pts;
        }

        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "POINT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Polyline pline = new Polyline())
            {
                List<Point2d> pts = new List<Point2d>();
                foreach (SelectedObject so in psr.Value)
                {
                    DBPoint dbPt = (DBPoint)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
                }
                pts = ConvexHull(pts);
                for (int i = 0; i < pts.Count; i++)
                {
                    pline.AddVertexAt(i, pts[i], 0.0, 0.0, 0.0);
                }
                pline.Closed = true;
                pline.SetDatabaseDefaults();
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                btr.AppendEntity(pline);
                tr.AddNewlyCreatedDBObject(pline, true);
                tr.Commit();
            }
        }
    }
}

F#
Code: [Select]
module ConvexHull

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

type AcAp = Autodesk.AutoCAD.ApplicationServices.Application

let clockwise (p1:Point2d) (p2:Point2d) (p3:Point2d) =
    (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X) < 1e-9
   
let convexHull (pts : Point2d seq) =
    let rec fill acc pt =
        match acc with
        | a :: b :: _ when clockwise b a pt -> fill acc.Tail pt
        | _ -> pt :: acc
    let p0 = pts
             |> Seq.reduce (fun p1 p2 ->
                if p2.Y < p1.Y || (p1.Y = p2.Y && p2.X < p1.X) then p2 else p1)
    pts
    |> List.ofSeq
    |> List.sortBy (fun p ->
        let d = p0.GetDistanceTo(p)
        (Math.Round((p0.X - p.X) / d, 8), d))
    |> List.fold fill []
    |> List.rev

[<CommandMethod("ch")>]
let Test() =
    let doc = AcAp.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    let psr = ed.GetSelection(new SelectionFilter([| new TypedValue(0, "POINT") |]))
    if psr.Status = PromptStatus.OK then
        use tr = db.TransactionManager.StartTransaction()
        use pl = new Polyline()
        psr.Value
        |> Seq.cast<_>
        |> Seq.map (fun (so : SelectedObject) ->
            let pt = tr.GetObject(so.ObjectId, OpenMode.ForRead) :?> DBPoint
            new Point2d(pt.Position.X, pt.Position.Y))
        |> convexHull
        |> List.fold(fun i p ->  pl.AddVertexAt(i, p, 0.0, 0.0, 0.0); i + 1) 0
        |> ignore
        pl.Closed <- true
        pl.SetDatabaseDefaults()
        let btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
        btr.AppendEntity(pl) |> ignore
        tr.AddNewlyCreatedDBObject(pl, true)
        tr.Commit()

target audience:{advanced}

19
Blocks / Get block references in layouts only
« on: March 24, 2011, 11:05:28 PM »
Hi

The BlockTableRecord.GetBlockReferencesIds() method returns all inserted references, even nested in other blocks.

A way to get only references inserted in layout is to filter the ObjectIdCollection returned by GetBlockReferencesIds() with the reference owner.

The following F# and C# snippets define a function/method which require as arguments the database and the block name.
They return respectively an ObjectId array and an ObjectIdCollection which contain all block references directly inserted in layouts (even dynamic/anonymous blocks).

C#
Code: [Select]
        private ObjectIdCollection GetReferences(Database db, string bName)
        {
            ObjectIdCollection result = new ObjectIdCollection();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt =
                    (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(bName))
                {
                    BlockTableRecord btr =
                        (BlockTableRecord)tr.GetObject(bt[bName], OpenMode.ForRead);
                    foreach (ObjectId refId in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br =
                            (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
                        BlockTableRecord owner =
                            (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
                        if (owner.IsLayout)
                            result.Add(br.ObjectId);
                    }
                    foreach (ObjectId id in btr.GetAnonymousBlockIds())
                    {
                        BlockTableRecord anon =
                            (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                        foreach (ObjectId refId in anon.GetBlockReferenceIds(true, false))
                        {
                            BlockReference br =
                                (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
                            BlockTableRecord owner =
                                (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
                            if (owner.IsLayout)
                                result.Add(br.ObjectId);
                        }
                    }
                }
                tr.Commit();
            }
            return result;
        }

F#
Code: [Select]
let GetBlockReferences (db : Database) (bName : string) =
    use tr = db.TransactionManager.StartTransaction()
    let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
    if bt.Has(bName) then
        let btr = tr.GetObject(bt.[bName], OpenMode.ForRead) :?> BlockTableRecord
        btr.GetAnonymousBlockIds()
        |> Seq.cast<_>
        |> Seq.map (fun id -> tr.GetObject(id, OpenMode.ForRead) :?> BlockTableRecord)
        |> Seq.append (Seq.singleton btr)
        |> Seq.collect (fun b ->
            b.GetBlockReferenceIds(true, false)
            |> Seq.cast<_>
            |> Seq.filter (fun id ->
                let br = tr.GetObject(id, OpenMode.ForRead)
                let owner = tr.GetObject(br.OwnerId, OpenMode.ForRead) :?> BlockTableRecord
                owner.IsLayout))
        |> Seq.toArray
    else Array.empty

20
AutoCAD talk / LispFunction with autoCAD 2008
« on: December 06, 2010, 08:34:11 PM »
Hi,

A .NET defined LISP function (with the LispFunction attribute) can return any type of value available in LISP : string, int, double,Point3d,  SelectionSet, ObjectId (ename), TypedValue (T or nil), ResultBuffer (list)...

But it seems there's a bug with AutoCAD 2008 which only allows .NET defined LISP functions to return a ResulBuffer (a list or nil).

21
Selection sets / Selection Set Filters
« on: December 04, 2010, 10:24:53 PM »
In the .NET environment, a SelectionFilter is constructed with a TypedValue array.
A TypedValue can contain various Objects types in its Value property. The Object type is defined in the TypeCode property as an integer (or a DxfCode enum integer) which corresponds to the DXF group code of the Value.
For those who know AutoLISP, a TypedValue looks like a DXF dotted pair (even it is not the same thing, a dotted pair is a LISP specific data).
For the Values which type is String as entity type (DxfCode.Start = 0) or layer (DxfCode.Layer = 8), the Value can contain many patterns separted by commas and use wildcard patterns.
The filter can contain relational tests for the numerical values and logical grouping.

The more complete documentation in the AutoCAD Developer's Help for building sofisticated SelectionFilters is in the AutoLISP Help:
AutoLISP developer's Guide > Using the AutoLISP Language > Using AutoLISP to Manipulate AutoCAD Objects > Selection Set Handling > Selection Set Filter Lists
And the DXF group codes can be found in DXF Reference.

Here's an example to select closed polylines (lw, 2d and 3d) and closed ellipses on layers BASE and CONSTRUCTION

Code: [Select]
TypedValue[] filter =
            {   new TypedValue(-4, "<OR"),
                new TypedValue(-4, "<AND"),
                new TypedValue(0, "*POLYLINE"), // LWPOLYLINE and POLYLINE
                new TypedValue(-4, "&"),
                new TypedValue(70, 1), // Closed
                new TypedValue(-4, "<NOT"),
                new TypedValue(-4, "&"),
                new TypedValue(70, 112),  // Avoid meshes (bit codes: 16 + 32 + 64)
                new TypedValue(-4, "NOT>"),
                new TypedValue(-4, "AND>"),
                new TypedValue(-4, "<AND"),
                new TypedValue(0, "ELLIPSE"),
                new TypedValue(-4, "="),
                new TypedValue(41, 0.0), // Start parameter
                new TypedValue(-4, "="),
                new TypedValue(42, 6.283185307179586), // End parameter
                new TypedValue(-4, "AND>"),
                new TypedValue(-4, "OR>"),
                new TypedValue(8, "BASE,CONSTRUCTION")};
SelectionFilter = new SelectionFilter(filter);

target audience:{beginner}

22
Display / Zoom Objects
« on: December 04, 2010, 12:47:34 AM »
Hi,

Here's a little sample to make a Zoom on selected objects

<Edit: removed some unusefull statements>

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

namespace ZoomObjectSample
{
    public class Zoom
    {
        [CommandMethod("ZO")]
        public void ZO()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptSelectionResult psr = ed.GetSelection();
            if (psr.Status != PromptStatus.OK)
                return;
            ObjectIdCollection idCol = new ObjectIdCollection(psr.Value.GetObjectIds());
            ZoomObjects(idCol);
        }

        private void ZoomObjects(ObjectIdCollection idCol)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (ViewTableRecord view = ed.GetCurrentView())
            {
                Matrix3d WCS2DCS = Matrix3d.PlaneToWorld(view.ViewDirection);
                WCS2DCS = Matrix3d.Displacement(view.Target - Point3d.Origin) * WCS2DCS;
                WCS2DCS = Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * WCS2DCS;
                WCS2DCS = WCS2DCS.Inverse();
                Entity ent = (Entity)tr.GetObject(idCol[0], OpenMode.ForRead);
                Extents3d ext = ent.GeometricExtents;
                for (int i = 1; i < idCol.Count; i++)
                {
                    ent = (Entity)tr.GetObject(idCol[i], OpenMode.ForRead);
                    Extents3d tmp = ent.GeometricExtents;
                    ext.AddExtents(tmp);
                }
                ext.TransformBy(WCS2DCS);
                view.Width = ext.MaxPoint.X - ext.MinPoint.X;
                view.Height = ext.MaxPoint.Y - ext.MinPoint.Y;
                view.CenterPoint =
                    new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0);
                ed.SetCurrentView(view);
                tr.Commit();
            }
        }
    }
}

F#
Code: [Select]
module ZoomObjects

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

let zoomObjects (ids : ObjectId[]) =
    let doc = Application.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    use tr = db.TransactionManager.StartTransaction()
    use view = ed.GetCurrentView()
   
    let getEnt id = tr.GetObject(id, OpenMode.ForRead) :?> Entity
   
    let addExts (ext : Extents3d) id =
        ext.AddExtents((getEnt id).GeometricExtents)
        ext
       
    let ext = ids |> Array.fold addExts (getEnt ids.[0]).GeometricExtents
    let WCS2DCS =  Matrix3d
                    .PlaneToWorld(view.ViewDirection)
                    .PreMultiplyBy(Matrix3d.Displacement(view.Target - Point3d.Origin))
                    .PreMultiplyBy(Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target))
                    .Inverse()
    ext.TransformBy(WCS2DCS)
    view.Width <- ext.MaxPoint.X - ext.MinPoint.X
    view.Height <- ext.MaxPoint.Y - ext.MinPoint.Y
    view.CenterPoint <- new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0)
    ed.SetCurrentView(view)
    tr.Commit();

[<CommandMethod("ZO")>]
let zo() =
    let ed = Application.DocumentManager.MdiActiveDocument.Editor
    let psr = ed.GetSelection()
    if psr.Status = PromptStatus.OK then
        psr.Value.GetObjectIds() |> zoomObjects

VB
Code: [Select]
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Runtime

Namespace ZoomObjectSample
Public Class Zoom
<CommandMethod("ZO")> _
Public Sub ZO()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim psr As PromptSelectionResult = ed.GetSelection()
If psr.Status <> PromptStatus.OK Then
Return
End If
Dim idCol As New ObjectIdCollection(psr.Value.GetObjectIds())
ZoomObjects(idCol)
End Sub

Private Sub ZoomObjects(idCol As ObjectIdCollection)
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Using tr As Transaction = db.TransactionManager.StartTransaction()
Using view As ViewTableRecord = ed.GetCurrentView()
Dim WCS2DCS As Matrix3d = Matrix3d.PlaneToWorld(view.ViewDirection)
WCS2DCS = Matrix3d.Displacement(view.Target - Point3d.Origin) * WCS2DCS
WCS2DCS = Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * WCS2DCS
WCS2DCS = WCS2DCS.Inverse()
Dim ent As Entity = DirectCast(tr.GetObject(idCol(0), OpenMode.ForRead), Entity)
Dim ext As Extents3d = ent.GeometricExtents
For i As Integer = 1 To idCol.Count - 1
ent = DirectCast(tr.GetObject(idCol(i), OpenMode.ForRead), Entity)
Dim tmp As Extents3d = ent.GeometricExtents
ext.AddExtents(tmp)
Next
ext.TransformBy(WCS2DCS)
view.Width = ext.MaxPoint.X - ext.MinPoint.X
view.Height = ext.MaxPoint.Y - ext.MinPoint.Y
view.CenterPoint = New Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0)
ed.SetCurrentView(view)
tr.Commit()
End Using
End Using
End Sub
End Class
End Namespace

target audience:{intermediate}

23
F# language / Expert F#, chapter 3
« on: November 28, 2010, 08:55:47 AM »
You can download the Chapter3 of "Expert F#" (Don Syme, Adam Granicz, Antonio Cisternino) called: "Introducing Functional Programming".

24
F# language / An Introduction to Microsoft F#
« on: November 28, 2010, 12:06:50 AM »
Another video of Luca Bolognese here which explains the basics of F# with a succulent Italian accent.


target audience:{beginner}

25
Windows forms / Osnap Palette
« on: November 21, 2010, 11:00:48 PM »
Hi,

The _osnap dialog box as a palette



The 'OsPalette' class where the OSPALETTE command (to show the palette) is defined.
Code: [Select]
    using System;
    using Autodesk.AutoCAD.Runtime;
    using Autodesk.AutoCAD.Windows;

    namespace OsnapPalette
    {
        public class OsPalette
        {
            static PaletteSet ps;
            internal static OsmodeControl osmCtrl;

            public OsPalette()
            {
                osmCtrl = new OsmodeControl();
            }

            public void Show()
            {
                if (ps == null)
                {
                    ps = new PaletteSet("OSPALETTE", new Guid("{379AD059-A26C-4a3b-A05C-313A799D48CA}"));
                    ps.Style =
                      PaletteSetStyles.ShowPropertiesMenu |
                      PaletteSetStyles.ShowAutoHideButton |
                      PaletteSetStyles.ShowCloseButton;
                    ps.Name = "Accrochages aux objets";
                    ps.MinimumSize = new System.Drawing.Size(300, 340);
                    ps.Add("Accrobj", osmCtrl);
                }
                ps.Visible = true;
            }

            [CommandMethod("OSPALETTE")]
            public void Accobj()
            {
                this.Show();
            }
        }
    }

The 'OsmodeControl' class
Code: [Select]
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using Autodesk.AutoCAD.ApplicationServices;
    using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
    using AcAs = Autodesk.AutoCAD.ApplicationServices;

    namespace OsnapPalette
    {
        public partial class OsmodeControl : UserControl
        {
            private Dictionary<int, CheckBox> modes = new Dictionary<int, CheckBox>();

            public OsmodeControl()
            {
                InitializeComponent();
                modes.Add(1, this.chkEnd);
                modes.Add(2, this.chkMid);
                modes.Add(4, this.chkCen);
                modes.Add(8, this.chkNod);
                modes.Add(16, this.chkQua);
                modes.Add(32, this.chkInt);
                modes.Add(64, this.chkIns);
                modes.Add(128, this.chkPer);
                modes.Add(256, this.chkTan);
                modes.Add(512, this.chkNea);
                modes.Add(2048, this.chkPrj);
                modes.Add(4096, this.chkExt);
                modes.Add(8192, this.chkPar);
                InitCheckBoxes();
                AcAp.SystemVariableChanged +=
                    new AcAs.SystemVariableChangedEventHandler(AcAp_SysvarChanged);
            }

            void AcAp_SysvarChanged(object sender, AcAs.SystemVariableChangedEventArgs e)
            {
                if (e.Name == "OSMODE" || e.Name == "AUTOSNAP")
                    InitCheckBoxes();
            }

            private void InitCheckBoxes()
            {
                short osmode = (short)AcAp.GetSystemVariable("OSMODE");
                foreach (KeyValuePair<int, CheckBox> pair in modes)
                {
                    pair.Value.Checked = (osmode & pair.Key) == pair.Key;
                }
                this.chkF3.Checked = (osmode & 16384) == 0;
                this.chkF11.Checked = (((short)AcAp.GetSystemVariable("AUTOSNAP")) & 16) == 16;
            }

            private void cmdAll_Click(object sender, EventArgs e)
            {
                foreach (KeyValuePair<int,CheckBox> pair in modes)
                {
                    pair.Value.Checked = true;
                }
            }

            private void cmdNone_Click(object sender, EventArgs e)
            {
                foreach (KeyValuePair<int, CheckBox> pair in modes)
                {
                    pair.Value.Checked = false;
                }
            }

            private void OsmodeControl_MouseLeave(object sender, EventArgs e)
            {
                Document doc = AcAp.DocumentManager.MdiActiveDocument;
                int autosnap = (short)AcAp.GetSystemVariable("AUTOSNAP");
                autosnap = chkF11.Checked ? autosnap | 16 : autosnap - (autosnap & 16);
                int osmode = 0;
                foreach (KeyValuePair<int,CheckBox> pair in modes)
                {
                    if (pair.Value.Checked)
                        osmode += pair.Key;
                }
                if (!chkF3.Checked)
                    osmode += 16384;
                using (DocumentLock docLock = doc.LockDocument())
                {
                    AcAp.SetSystemVariable("OSMODE", osmode);
                    AcAp.SetSystemVariable("AUTOSNAP", autosnap);
                }
            }
        }
    }

target audience:{intermediate}

26
Polylines / Add vertex
« on: November 21, 2010, 10:43:47 PM »
Hi,

The AVX command allows to add vertices to a polyline.
The `Jig' allows a dynamic preview of the new segment(s).
The command works whatever the polyline construction plane (`dynamic UCS' behavior while the polyline plane is different from the current UCS).
A DVX command allows to remove vertices

It deals with osnaps...


It deals with non constant widthes...


It deals with arc segments and with start and end points.


Code: [Select]
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace PolylineEdit
{
    public class AddVertex
    {
        Editor ed = acadApp.DocumentManager.MdiActiveDocument.Editor;
        Database db = HostApplicationServices.WorkingDatabase;

        class VertexJig : EntityJig
        {
            Polyline m_pline;
            Point3d m_point;
            int m_index;
            Vector3d m_vector;
            double m_bulge;
            double m_sWidth;
            double m_eWidth;

            public VertexJig(Polyline pline, Point3d point, int index, Vector3d vector, double bulge, double sWidth, double eWidth)
                : base(pline)
            {
                m_pline = pline;
                m_point = point;
                m_index = index;
                m_vector = vector;
                m_bulge = bulge;
                m_sWidth = sWidth;
                m_eWidth = eWidth;
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                JigPromptPointOptions jppo = new JigPromptPointOptions("\nSpecify the new vertex: ");
                jppo.UserInputControls = (UserInputControls.Accept3dCoordinates);
                PromptPointResult ppr = prompts.AcquirePoint(jppo);
                if (ppr.Status == PromptStatus.OK)
                {
                    if (ppr.Value.IsEqualTo(m_point))
                        return SamplerStatus.NoChange;
                    else
                    {
                        m_point = ppr.Value;
                        return SamplerStatus.OK;
                    }
                }
                return SamplerStatus.Cancel;
            }

            protected override bool Update()
            {
                if (m_pline.NumberOfVertices == 3)
                {
                    Point3d transPt = m_point.TransformBy(Matrix3d.WorldToPlane(m_pline.Normal));
                    Point2d pt = new Point2d(transPt.X, transPt.Y);
                    double length = m_pline.GetDistanceAtParameter(2);
                    double dist1 = m_pline.GetDistanceAtParameter(1);
                    double dist2 = length - dist1;
                    double width = m_sWidth < m_eWidth ?
                        ((dist1 * (m_eWidth - m_sWidth)) / length) + m_sWidth :
                        ((dist2 * (m_sWidth - m_eWidth)) / length) + m_eWidth;
                    double angle = Math.Atan(m_bulge);
                    m_pline.SetPointAt(m_index, pt);
                    m_pline.SetEndWidthAt(0, width);
                    m_pline.SetStartWidthAt(1, width);
                    m_pline.SetBulgeAt(0, Math.Tan(angle * (dist1 / length)));
                    m_pline.SetBulgeAt(1, Math.Tan(angle * (dist2 / length)));
                }
                else if (m_index == 0)
                {
                    Point3d transPt = m_point.TransformBy(Matrix3d.WorldToPlane(m_pline.Normal));
                    Point2d pt = new Point2d(transPt.X, transPt.Y);
                    m_pline.SetPointAt(m_index, pt);
                    if (m_bulge != 0.0)
                    {
                        Vector3d vec = m_point.GetVectorTo(m_pline.GetPoint3dAt(1));
                        double ang = vec.GetAngleTo(m_vector, m_pline.Normal);
                        double bulge = Math.Tan(ang / 2.0);
                        m_pline.SetBulgeAt(0, bulge);
                    }
                }
                else
                {
                    Point3d transPt = m_point.TransformBy(Matrix3d.WorldToPlane(m_pline.Normal));
                    Point2d pt = new Point2d(transPt.X, transPt.Y);
                    m_pline.SetPointAt(m_index, pt);
                    if (m_bulge != 0.0)
                    {
                        Vector3d vec = m_pline.GetPoint3dAt(0).GetVectorTo(m_point);
                        double ang = m_vector.GetAngleTo(vec, m_pline.Normal);
                        double bulge = Math.Tan(ang / 2.0);
                        m_pline.SetBulgeAt(0, bulge);
                    }
                }
                return true;
            }

            public Point3d GetPoint()
            {
                return m_point;
            }
        }

        [CommandMethod("AVX")]
        public void Avx()
        {
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a segment where to add a vertex: ");
            peo.SetRejectMessage("\nIncorrect entity");
            peo.AllowNone = false;
            peo.AllowObjectOnLockedLayer = false;
            peo.AddAllowedClass(typeof(Polyline), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status == PromptStatus.OK)
            {
                Matrix3d UCS = ed.CurrentUserCoordinateSystem;
                ObjectId objId = per.ObjectId;
                try
                {
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        Polyline pline = tr.GetObject(objId, OpenMode.ForRead, false) as Polyline;
                        if (pline != null)
                        {
                            Point3d pickPt = pickPointOnPline(pline, per.PickedPoint);
                            double param = pline.GetParameterAtPoint(pickPt);
                            int index = (int)param;

                            Matrix3d OCS = Matrix3d.PlaneToWorld(pline.Normal);
                            Point3d transPt = pickPt.TransformBy(OCS);

                            if (!OCS.CoordinateSystem3d.Zaxis.IsEqualTo(UCS.CoordinateSystem3d.Zaxis))
                            {
                                ed.CurrentUserCoordinateSystem = plineUCS(pline, index);
                            }

                            Int16 aperture = (Int16)acadApp.GetSystemVariable("APERTURE");
                            double viewsize = (double)acadApp.GetSystemVariable("VIEWSIZE");
                            Point2d screensize = (Point2d)acadApp.GetSystemVariable("SCREENSIZE");
                            double tol = 2 * aperture * viewsize / screensize.Y;
                            Tolerance tolerance = new Tolerance(tol, tol);

                            int endParam = pline.Closed == true ? pline.NumberOfVertices : pline.NumberOfVertices - 1;
                            Vector3d vec;

                            using (Polyline ghost = new Polyline())
                            {
                                ghost.ColorIndex = 7;

                                if ((pline.Closed == false) && pickPt.IsEqualTo(pline.GetPoint3dAt(0), tolerance))
                                {
                                    vec = pline.GetFirstDerivative(0);
                                    double bulge = pline.GetBulgeAt(0);
                                    double width = pline.GetStartWidthAt(0);
                                    Point2d p0 = new Point2d(transPt.X, transPt.Y);
                                    Point2d p1 = pline.GetPoint2dAt(0);

                                    ghost.AddVertexAt(0, p0, bulge, width, width);
                                    ghost.AddVertexAt(1, p1, bulge, width, width);
                                    ghost.Normal = pline.Normal;
                                    ghost.Elevation = pline.Elevation;

                                    VertexJig jig = new VertexJig(ghost, pickPt, 0, vec, bulge, width, width);

                                    PromptResult res = ed.Drag(jig);
                                    if (res.Status == PromptStatus.OK)
                                    {
                                        pline.UpgradeOpen();
                                        pline.AddVertexAt(index, ghost.GetPoint2dAt(0), ghost.GetBulgeAt(0), width, width);
                                    }
                                }
                                else if ((pline.Closed == false) && pickPt.IsEqualTo(pline.GetPoint3dAt(endParam), tolerance))
                                {
                                    vec = pline.GetFirstDerivative(endParam);
                                    double bulge = pline.GetBulgeAt(index);
                                    double width = pline.GetEndWidthAt(endParam);
                                    Point2d p0 = pline.GetPoint2dAt(endParam);
                                    Point2d p1 = new Point2d(transPt.X, transPt.Y);

                                    ghost.AddVertexAt(0, p0, bulge, width, width);
                                    ghost.AddVertexAt(1, p1, bulge, width, width);
                                    ghost.Normal = pline.Normal;
                                    ghost.Elevation = pline.Elevation;

                                    VertexJig jig = new VertexJig(ghost, pickPt, 1, vec, bulge, width, width);

                                    PromptResult res = ed.Drag(jig);
                                    if (res.Status == PromptStatus.OK)
                                    {
                                        pline.UpgradeOpen();
                                        pline.AddVertexAt(endParam + 1, ghost.GetPoint2dAt(1), ghost.GetBulgeAt(0), width, width);
                                        pline.SetBulgeAt(endParam, ghost.GetBulgeAt(0));
                                    }
                                }

                                else
                                {
                                    double bulge = pline.GetBulgeAt(index);
                                    double sWidth = pline.GetStartWidthAt(index);
                                    double eWidth = pline.GetEndWidthAt(index);
                                    Point2d p0 = pline.GetPoint2dAt(index);
                                    Point2d p1 = new Point2d(transPt.X, transPt.Y);
                                    Point2d p2;
                                    if (pline.Closed == false)
                                        p2 = pline.GetPoint2dAt(index + 1);
                                    else
                                    {
                                        try { p2 = pline.GetPoint2dAt(index + 1); }
                                        catch { p2 = pline.GetPoint2dAt(0); }
                                    }

                                    ghost.AddVertexAt(0, p0, bulge, sWidth, 0.0);
                                    ghost.AddVertexAt(1, p1, bulge, 0.0, eWidth);
                                    ghost.AddVertexAt(2, p2, 0.0, 0.0, 0.0);
                                    ghost.Normal = pline.Normal;
                                    ghost.Elevation = pline.Elevation;

                                    VertexJig jig = new VertexJig(ghost, pickPt, 1, vec, bulge, sWidth, eWidth);

                                    PromptResult res = ed.Drag(jig);
                                    if (res.Status == PromptStatus.OK)
                                    {
                                        pline.UpgradeOpen();
                                        pline.SetEndWidthAt(index, ghost.GetStartWidthAt(1));
                                        pline.AddVertexAt(index + 1, ghost.GetPoint2dAt(1), ghost.GetBulgeAt(1), ghost.GetStartWidthAt(1), eWidth);
                                        pline.SetBulgeAt(index, ghost.GetBulgeAt(0));
                                    }
                                }
                            }
                            ed.CurrentUserCoordinateSystem = UCS;
                        }
                        tr.Commit();
                    }
                }
                catch (System.Exception ex)
                {
                    ed.CurrentUserCoordinateSystem = UCS;
                    ed.WriteMessage("Error: " + ex.Message);
                }
            }
        }

        [CommandMethod("DVX")]
        public void Dvx()
        {
            PromptEntityOptions peo = new PromptEntityOptions("\nSelact the vertex to remove: ");
            peo.SetRejectMessage("\nIncorrect entity");
            peo.AllowNone = false;
            peo.AllowObjectOnLockedLayer = false;
            peo.AddAllowedClass(typeof(Polyline), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status == PromptStatus.OK)
            {
                ObjectId objId = per.ObjectId;
                try
                {
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        Polyline pline = tr.GetObject(objId, OpenMode.ForWrite, false) as Polyline;
                        if (pline != null)
                        {
                            if (pline.NumberOfVertices > 2)
                            {
                                Point3d pickPt = pickPointOnPline(pline, per.PickedPoint);
                                double param = pline.GetParameterAtPoint(pickPt);
                                int index = (int)param;
                                if ((param - Math.Truncate(param)) > 0.5)
                                    index += 1;
                                pline.RemoveVertexAt(index);
                            }
                            else
                                ed.WriteMessage("\nOnly two vertices left");
                        }
                        tr.Commit();
                    }
                }
                catch (System.Exception ex)
                {
                    ed.WriteMessage("Error: " + ex.Message);
                }
            }
        }

        private Point3d pickPointOnPline(Polyline pl, Point3d pt)
        {
            pt = pt.TransformBy(ed.CurrentUserCoordinateSystem);
            Vector3d vdir = ed.GetCurrentView().ViewDirection;
            pt = pt.Project(pl.GetPlane(), vdir);
            return pl.GetClosestPointTo(pt, false);
        }

        private Matrix3d plineUCS(Polyline pline, int param)
        {
            Point3d origin = pline.GetPoint3dAt(param);
            Vector3d xDir = origin.GetVectorTo(pline.GetPoint3dAt(param + 1)).GetNormal();
            Vector3d zDir = pline.Normal;
            Vector3d yDir = zDir.CrossProduct(xDir).GetNormal();
            return new Matrix3d(new double[16]{
                xDir.X, yDir.X, zDir.X, origin.X,
                xDir.Y, yDir.Y, zDir.Y, origin.Y,
                xDir.Z, yDir.Z, zDir.Z, origin.Z,
                0, 0, 0, 1});
        }
    }
}

target audience:{advanced}

27
Text / Strip Mtext
« on: November 21, 2010, 09:57:29 PM »
Hi,

This code was inspired by a Tony Tanzillo's one using the Mtext.ExplodeFragments() method to remove all Mtext formatting.

A command: STRIPMT to unformat all selected Mtexts
A LISP function: gc-GetStrippedMtextString to return the unformated text string of the mtext which ename is passed as argument to the function

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

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace StripMtextSample
{
    public class StripMtext
    {
        private StringBuilder m_sb = null;

        private string GetStrippedMtextContents(MText mt)
        {
            m_sb = new StringBuilder();
            mt.ExplodeFragments(new MTextFragmentCallback(FragmentCallback));
            return m_sb.ToString();
        }

        private MTextFragmentCallbackStatus FragmentCallback(MTextFragment fragment, object obj)
        {
            m_sb.Append(fragment.Text);
            return MTextFragmentCallbackStatus.Continue;
        }

        [CommandMethod("STRIPMT", CommandFlags.Modal | CommandFlags.UsePickSet)]
        public void StripSelSet()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            SelectionFilter filter = new SelectionFilter(new TypedValue[] { new TypedValue(0, "MTEXT") });
            ed.WriteMessage("\nSelect mtexts (or type 'Enter' for 'all').");
            PromptSelectionResult psr = ed.GetSelection(filter);
            if (psr.Status == PromptStatus.Error)
                psr = ed.SelectAll(filter);
            if (psr.Status != PromptStatus.OK)
                return;
            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    foreach (ObjectId id in psr.Value.GetObjectIds())
                    {
                        MText mt = (MText)tr.GetObject(id, OpenMode.ForWrite);
                        mt.Contents = GetStrippedMtextContents(mt);
                    }
                    tr.Commit();
                }
            }
            catch (System.Exception e)
            {
                ed.WriteMessage(string.Format("\nError: {0}\n", e.Message));
            }
        }

        [LispFunction("gc-GetStrippedMtextString")]
        public string GetStrippedMtextString(ResultBuffer resbuf)
        {
            try
            {
                if (resbuf == null)
                    throw new LispException("to few arguments");
                TypedValue[] arg = resbuf.AsArray();
                if (arg.Length > 1)
                    throw new LispException("to many arguments");
                if (arg[0].TypeCode != (short)LispDataType.ObjectId)
                    throw new LispException(string.Format("incorrect argument type: lentityp: {0}", arg[0].Value));
                Database db = HostApplicationServices.WorkingDatabase;
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    MText mt = tr.GetObject(((ObjectId)arg[0].Value), OpenMode.ForRead) as MText;
                    if (mt == null)
                        throw new LispException("incorrect argument type: not a mtext");
                    return GetStrippedMtextContents(mt);
                }
            }
            catch (LispException e)
            {
                AcAp.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nError: {0}\n", e.Message);
                return null;
            }
        }
    }

    class LispException : System.Exception
    {
        public LispException(string message)
            : base(message)
        {
        }
    }
}

target audience:{intermediate}

28
Math and Geometry / Geometry extensions
« on: November 19, 2010, 04:01:42 PM »
Hi,

I already posted this at TheSwamp.
It will be my contribution to give a start to this new website.

These are some geometry extensions methods for Point2d, Point3d, CircularArc2d, Polyline and Polyline2d classes and two little classes: Triangle2d, Triangle3d.
I hope someones find them usefull and expect it shows a little basic OOP concepts as the creation of new types and the extension of already existing ones.

All these classes work together and have to be compiled in a single DLL.

The extension methods requires to reference System.Core (.NET Framework 3.5) and are available for these objects as native methods while GeometryExtensions.dll is referenced:
Code: [Select]
using GeometryExtensions;

Point3d p1 = new Point3d(10.0, 20.0, 0.0);
Point3d p2 = p1.Polar(Math.PI / 4.0, 10.0);
p2 coordinates are: (17.0710678118655,27.0710678118655,0)

The GeomExt class, contains the following extension methods:

Matrix3d Editor.UCS2WCS()
Matrix3d Editor.WCS2UCS()
Matrix3d Editor.DCS2WCS()
Matrix3d Editor.WCS2DCS()
Matrix3d Editor.DCS2PSDCS()
Matrix3d Editor.PSDCS2DCS()

Matrix3d Viewport.DCS2WCS()
Matrix3d Viewport.WCS2DCS()
Matrix3d Viewport.PSDCS2DCS()
Matrix3d Viewport.DCS2PSDCS()

Point3d Point2d.Convert3d()
Point3d Point2d.Convert3d(Plane plane)
Point3d Point2d.Convert3d(Vector3d normal, double elevation)
Point2d Point2d.Flatten(Vector3d normal)
bool IsBetween(Point2d p1, Point2d p2)
bool IsBetween(Point2d p1, Point2d p2, Tolerance tol)
Point2d Point2d.Polar(double angle, double distance)

Point3d Point3d.Convert2d()
Point3d Point3d.Flatten()
bool IsBetween(Point3d p1, Point3d p2)
bool IsBetween(Point3d p1, Point3d p2, Tolerance tol)
Point3d Point3d.Polar(double angle, double distance)
Point3d Point3d.Trans(CoordSystem from, CoordSystem to)
Point3d Point3d.Trans(Editor ed, CoordSystem from, CoordSystem to)

Vector3d Vector3d .Flatten()

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

double CircularArc2d.AlgebricArea()
Point2d CircularArc2d.Centroid()

Point2d Polyline.Centroid2d()
Point3d Polyline.Centroid()
Polyline Polyline.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline.GetOrthoProjectedPolyline(Plane plane)

Point3d Polyline2d.Centroid()
CircularArc3d Polyline2d.GetArcSegmentAt(int index)
CircularArc2d Polyline2d.GetArcSegment2dAt(int index)
LineSegment3d Polyline2d.GetLineSegmentAt(int index)
LineSegment2d Polyline2d.GetLineSegment2dAt(int index)
Polyline Polyline2d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline2d.GetOrthoProjectedPolyline(Plane plane)
List<Vertex2d> Polyline2d.GetVertices()

Polyline Polyline3d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline3d.GetOrthoProjectedPolyline(Plane plane)

Point3d Region.Centroid()

Point3d Spline.Centroid()

Polyline Ellipse.ToPolyline()


Triangle<T> abstract class

Constructors
Triangle()
Triangle(T[] pts)
Triangle(T a, T b, T c)

Indexor
T Item

Methods
T Inverse()
void Set(T[] pts)
void Set(T a, T b, T c)
T[] ToArray()


Triangle2d : Triangle<Point2d> class

Constructors
Triangle2d() : base()
Triangle2d(Point2d[] pts) : base(pts)
Triangle2d(Point2d a, Point2d b, Point2d c) : base(a, b, c)
Triangle2d(Point2d org, Vector2d v1, Vector2d v2)

Properties
double AlgebricArea
Point2d Centroid
CircularArc2d CircumscribedCircle
CircularArc2d InscribedCircle
bool IsClockwise

Methods
Triangle3d Convert3d(Plane plane)
Triangle3d Convert3d(Vector3d normal, double elevation)
double GetAngleAt(int index)
LineSegment2d GetSegmentAt(int index)
List<Point2d> IntersectWith(LinearEntity2d le2d)
List<Point2d> IntersectWith(LinearEntity2d le2d, Tolerance tol)
bool IsEqualTo(Triangle2d t2d)
bool IsEqualTo(Triangle2d t2d, Tolerance tol)
bool IsPointInside(Point2d pt)
bool IsPointOn(Point2d pt)
void Set(Point2d org, Vector2d v1, Vector2d v2)
Triangle2d TransformBy(Matrix2d mat)


Triangle3d : Triangle<Point3d> class

Constructors
Triangle3d() : base()
Triangle3d(Point3d[] pts) : base(pts)
Triangle3d(Point3d a, Point3d b, Point3d c) : base(a, b, c)
Triangle3d(Point3d org, Vector3d v1, Vector3d v2)

Properties
double Area
Point3d Centroid
CircularArc3d CircumscribedCircle
double Elevation
Vector3d GreatestSlope
Vector3d Horizontal
CircularArc3d InscribedCircle
bool IsHorizontal
Vector3d Normal
double SlopePerCent
Matrix3d SlopeUCS

Methods
Triangle2d Convert2d()
Triangle2d Flatten()
double GetAngleAt(int index)
BoundedPlane GetBoundedPlane()
Plane GetPlane()
LineSegment3d GetSegmentAt(int index)
bool IsEqualTo(Triangle3d t3d)
bool IsEqualTo(Triangle3d t3d, Tolerance tol)
bool IsPointInside(Point3d pt)
bool IsPointOn(Point3d pt)
void Set(Point3d org, Vector3d v1, Vector3d v2)
Triangle3d Transformby(Matrix3d mat)


PolylineSegment class

Constructors

PolylineSegment(Point2d startPoint, Point2d endPoint)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double constantWidth)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
PolylineSegment(Line2dSegment line)
PolylineSegment(CircularArc2d arc)

Properties

double Bulge
Point2d EndPoint
double EndWidth
bool IsLinear
Point2d StartPoint
double StartWidth

Methods

bool Equals(object obj)
int GetHashCode()
double GetParameterOf(Point3d pt)
void Inverse()
CircularArc2d ToCircularArc()
Curve2d ToCurve2d()
LineSegment2d ToLineSegment()
string ToString()


PolylineSegmentCollection : IList<PolylineSegment> class

Constructors

PolylineSegmentCollection()
PolylineSegmentCollection(Circle circle)
PolylineSegmentCollection(Ellipse ellipse)
PolylineSegmentCollection(Polyline pline)
PolylineSegmentCollection(Polyline2d pline)
PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)

Methods

void Add(PolylineSegment segment)
void AddRange(IEnumerable<PolylineSegment> range)
void Clear()
bool Contains(PolylineSegment segment)
int FinIindex(Predicate<PolylineSegment> match)
int GetClosestSegmentTo(Point2d pt)
IEnumerator<PolylineSegment> GetEnumerator()
int IndexOf(PolylineSegment item)
void Insert(int index, PolylineSegment item)
void InsertRange(int index, IEnumerable<PolylineSegment> collection)
List<PolylineSegmentCollection> Join()
List<PolylineSegmentCollection> Join(Tolerance tol)
bool Remove(PolylineSegment item)
void RemoveAt(int index)
public void RemoveRange(int index, int count)
Polyline ToPolyline()

For more information, see the updated documentation.

GeometryExtensions(1.5).zip contains the C# source code files and the GeometryExtensions_18.dll (AutoCAD 2010-2012) and GeometryExtensions_19.dll (AutoCAD 2013)

<EDIT: version 1.5>


target audience:{intermediate}

Pages: 1 [2]