.NET

Reply
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 1 of 9 (351 Views)
Accepted Solution

BlockReference Jig

351 Views, 8 Replies
04-02-2014 07:36 AM

I can use EntityJig to move circle dynamicly, the code as follow

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace DragCircleSample
{
    public class CommandMethods
    {
        [CommandMethod("DragCircle")]
        public void DragCircle()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 3.0))
            {
                CircleJig jig = new CircleJig(circle);
                PromptResult pr = ed.Drag(jig);
                if (pr.Status == PromptStatus.OK)
                {
                    BlockTableRecord btr =
                        (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    btr.AppendEntity(circle);
                    tr.AddNewlyCreatedDBObject(circle, true);
                }
                tr.Commit();
            }
        }

        class CircleJig : EntityJig
        {
            Circle circle;
            Point3d center;

            public CircleJig(Circle circle)
                : base(circle)
            {
                this.circle = circle;
                this.center = circle.Center;
            }

            protected override bool Update()
            {
                circle.Center = center;
                return true;
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                PromptPointResult ppr =
                    prompts.AcquirePoint("\nSpecify the circle center: ");
                if (ppr.Value.DistanceTo(center) < Tolerance.Global.EqualPoint)
                    return SamplerStatus.NoChange;
                center = ppr.Value;
                return SamplerStatus.OK;
            }
        }
    }
}

 Now I try to move block reference dynamicly, and it can not run corretly, the code as follow,

  
{
.....
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
 BlockReferenceJig jig = new BlockReferenceJig(bomBlkRef);
PromptResult pr = ed.Drag(jig);
.......
}


    class BlockReferenceJig : EntityJig
    {
        BlockReference blkRef;
        Point3d position;

        public BlockReferenceJig(BlockReference blkRef)
            : base(blkRef)
        {
            this.blkRef = blkRef;
            this.position = blkRef.Position;
        }

        protected override bool Update()
        {
            blkRef.Position = position;
            return true;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            PromptPointResult ppr =
                prompts.AcquirePoint("\nSpecify the insert point: ");
            if (ppr.Value.DistanceTo(position) < Tolerance.Global.EqualPoint)
                return SamplerStatus.NoChange;
            position = ppr.Value;

            Point3d oldPoint = new Point3d(0, 0, 0);
            Vector3d acVec3d = oldPoint.GetVectorTo(position);
            blkRef.TransformBy(Matrix3d.Displacement(acVec3d));
            return SamplerStatus.OK;
        }
    }

 I hope to get help, very thanks

If you're  not  comfortable with anonymous functions or lambda expression you can define a private method and pass it as delegate to the Editor.Drag() method.

 

 private SamplerStatus Callback(Point3d pt, ref Matrix3d xform)
{
if (pt.IsEqualTo(Point3d.Origin))
return SamplerStatus.NoChange;
xform = Matrix3d.Displacement(Point3d.Origin.GetVectorTo(pt));
return SamplerStatus.OK;
}

 But this suppose your base point is Point3d.Origin or you'd have to use a private field to pass the base point to the private method.

This is one intererst of creating a DragCallback instance (with an anonymous or lambda function) within the method the block is inserted, in other words, within the insertion point scope.

 

Anyway, this has nothing to do with you issues.

First, if you don't want the two block reference overlap, don't insert them at the same point (Point3d.Origin) an then, use one of these insertion point as base point for the drag callback function.

Second, if you want the attributes alignment dispaly during dragging, you need to use a jig (more complex but more powerfull) as shown in the BlockAttributeJig example.

 

 [CommandMethod("test4")]
public void Test4()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
// if the block table doesn't contain the block, import it
ObjectId blockId = bt.Has("BOM1") ?
bt["BOM1"] :
ImportBlock("BOM1", @"D:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");
if (blockId != ObjectId.Null)
{
BlockTableRecord space =
(BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
BlockReference[] refs = new BlockReference[2]{
InsertBlock(space, blockId, Point3d.Origin, "QTY1", "Description1111111111"),
InsertBlock(space, blockId, new Point3d(0.0, 5.0, 0.0), "QTY1", "Description2222222222") };
ObjectId[] ids = new ObjectId[2] { refs[0].ObjectId, refs[1].ObjectId };
// create a selection set containing the newly inserted bloc
ed.SetImpliedSelection(ids);
PromptSelectionResult psr = ed.SelectImplied();
// drag the selection set
Point3d basePt = refs[0].Position;
DragCallback callback = (Point3d pt, ref Matrix3d xform) =>
{
if (pt.IsEqualTo(basePt))
return SamplerStatus.NoChange;
xform = Matrix3d.Displacement(basePt.GetVectorTo(pt));
return SamplerStatus.OK;
};
PromptPointResult ppr =
ed.Drag(psr.Value, "\nSpecify the insertion point: ", callback);
if (ppr.Status == PromptStatus.OK)
{
foreach (BlockReference br in refs)
{
br.TransformBy(Matrix3d.Displacement(br.Position.GetVectorTo(ppr.Value)));
}
}
else
{
foreach (BlockReference br in refs)
{
br.Erase();
}
}
}
tr.Commit();
}
catch (System.Exception exn)
{
ed.WriteMessage("\nError: " + exn.Message);
}
}
}
private BlockReference InsertBlock(
BlockTableRecord owner,
ObjectId blockId,
Point3d insPt,
string QYTstring,
string DescriptionString)
{
Database db = blockId.Database;
Transaction tr = db.TransactionManager.TopTransaction;
// insert the block
BlockReference blockRef = new BlockReference(insPt, blockId);
owner.AppendEntity(blockRef);
tr.AddNewlyCreatedDBObject(blockRef, true);
// insert attribute references
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead);
RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
foreach (ObjectId id in btr)
{
if (id.ObjectClass == attDefClass)
{
AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
AttributeReference attRef = new AttributeReference();
attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
if (attRef.Tag == "ITEM")
{
attRef.TextString = "X";
}
if (attRef.Tag == "PART")
{
attRef.TextString = "X";
}
if (attRef.Tag == "MATRL")
{
attRef.TextString = "SA-193-B7/SA-194-2H";
}
if (attRef.Tag == "QTY")
{
attRef.TextString = QYTstring;
}
if (attRef.Tag == "DESCRIPTION")
{
attRef.TextString = DescriptionString;
}
blockRef.AttributeCollection.AppendAttribute(attRef);
tr.AddNewlyCreatedDBObject(attRef, true);
}
}
return blockRef;
}
// Import a block definition from a file
private ObjectId ImportBlock(string blockName, string filenName)
{
if (!File.Exists(filenName))
throw new FileNotFoundException("File not found", filenName);
Database targetDb = HostApplicationServices.WorkingDatabase;
ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);
using (Database sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
if (!bt.Has(blockName))
throw new ArgumentException("Block definition not found", blockName);
ObjectIdCollection ids = new ObjectIdCollection();
ObjectId blockId = bt[blockName];
ids.Add(blockId);
IdMapping idMap = new IdMapping();
sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);
return idMap[blockId].Value;
}
}
}

 

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 2 of 9 (329 Views)

Re : BlockReference Jig

04-02-2014 01:07 PM in reply to: HelloWorlddd

Hi,

 

Try after removing this from the code you posted:

Point3d oldPoint = new Point3d(0, 0, 0);
Vector3d acVec3d = oldPoint.GetVectorTo(position);
blkRef.TransformBy(Matrix3d.Displacement(acVec3d));

 

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 3 of 9 (302 Views)

Re : BlockReference Jig

04-03-2014 06:47 AM in reply to: _gile

The program still does not run correctly, I really didn't understand the Jig class,

 

The program will get the block reference  in a specfied drawing, it's will exsit in the D:\SourceDwg folder,
Then, I need to use Jig class to specify the insertion point dynamicly, the function which I want to get is the bock reference will show on the screen follow the cursor dynamicly.

 

Here is my test code

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using System;
using System.IO;

[assembly: CommandClass(typeof(AutocadCommandCollection.Test1))]


namespace AutocadCommandCollection
{
    class Test1
    {
        [CommandMethod("test", CommandFlags.UsePickSet)]
        public void Test()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor;
            Transaction acTrans = acCurDb.TransactionManager.StartTransaction();

            using (acTrans)
            {
                ObjectId fiftyOneObjId = ImportBlockReference("BOM1", @"D:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");
                BlockReference BlkRef = acTrans.GetObject(fiftyOneObjId, OpenMode.ForWrite) as BlockReference;
                if (BlkRef != null)
                {
                    Document doc = Application.DocumentManager.MdiActiveDocument;
                    Database db = doc.Database;
                    Editor ed = doc.Editor;

                    BlockReferenceJigTest jig = new BlockReferenceJigTest(BlkRef);
                    PromptResult pr = ed.Drag(jig);
                    Point3d oldPoint = new Point3d(0, 0, 0);
                    if (pr.Status == PromptStatus.OK)
                    {
                        Vector3d acVec3d = oldPoint.GetVectorTo(jig.Position);
                        BlkRef.TransformBy(Matrix3d.Displacement(acVec3d));
                    }
                }
            }

        }

        public static ObjectId ImportBlockReference(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);

            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);

            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);

                    ObjectIdCollection ids = new ObjectIdCollection();

                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead);
                    ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb);
                    ObjectId brefId = new ObjectId();
                    foreach (ObjectId id in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                        if (br.OwnerId == mSpaceId)
                        {
                            ids.Add(id);
                            brefId = id;
                            break;
                        }
                    }
                    if (ids.Count == 0)
                        throw new ArgumentException("Block reference not found", blockName);

                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);

                    return idMap[brefId].Value;
                }
            }
        }
    }

    class BlockReferenceJigTest : EntityJig
    {
        BlockReference blkRef;
        Point3d position;

        public Point3d Position
        {
            get { return position; }
            set { position = value; }
        }

        public BlockReferenceJigTest(BlockReference blkRef)
            : base(blkRef)
        {
            this.blkRef = blkRef;
            this.position = blkRef.Position;
        }

        protected override bool Update()
        {
            blkRef.Position = position;
            return true;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            PromptPointResult ppr =
                prompts.AcquirePoint("\nSpecify the insert point: ");
            if (ppr.Value.DistanceTo(position) < Tolerance.Global.EqualPoint)
                return SamplerStatus.NoChange;

            position = ppr.Value;
            return SamplerStatus.OK;
        }
    }
}

 

If you help me modify the code, it would be great, thank you very much

 

Attachment has the drawing which has the BOM1 block reference.

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 4 of 9 (290 Views)

Re : BlockReference Jig

04-03-2014 10:37 AM in reply to: HelloWorlddd

The jig works but you cannot see it because your block only contains attributes and you do not update their positions during the drag.

You cannot see any result because you do not commit the transaction.

 

Try this:

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.IO;

[assembly: CommandClass(typeof(HelloWorld.Test1))]


namespace HelloWorld
{
    public class Test1
    {
        [CommandMethod("test")]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                    ObjectId fiftyOneObjId = ImportBlockReference("BOM1", @"F:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");
                    if (fiftyOneObjId != ObjectId.Null)
                    {
                        BlockReference BlkRef = tr.GetObject(fiftyOneObjId, OpenMode.ForWrite) as BlockReference;
                        BlockAttribJig jig = new BlockAttribJig(BlkRef, GetAttributesTextInfos(BlkRef));
                        PromptResult pr = ed.Drag(jig);
                        if (pr.Status != PromptStatus.OK)
                        {
                            BlkRef.Position = Point3d.Origin;
                        }
                    }
                    tr.Commit();
                }
                catch(System.Exception exn)
                {
                    ed.WriteMessage("nError: " + exn.Message);
                }
            }
        }

        private Dictionary<string, TextInfo> GetAttributesTextInfos(BlockReference br)
        {
            Dictionary<string, TextInfo> rtn = new Dictionary<string, TextInfo>();
            BlockTableRecord btr = (BlockTableRecord)br.BlockTableRecord.GetObject(OpenMode.ForRead);
            RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass == attDefClass)
                {
                    AttributeDefinition attDef = (AttributeDefinition)id.GetObject(OpenMode.ForRead);
                    rtn.Add(
                        attDef.Tag, 
                        new TextInfo(
                            attDef.Position,
                            attDef.AlignmentPoint,
                            attDef.Justify != AttachmentPoint.BaseLeft,
                            attDef.Rotation));
                }
            }
            return rtn;
        }

        private ObjectId ImportBlockReference(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);

            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);

            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);

                    ObjectIdCollection ids = new ObjectIdCollection();

                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead);
                    ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb);
                    ObjectId brefId = new ObjectId();
                    foreach (ObjectId id in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                        if (br.OwnerId == mSpaceId)
                        {
                            ids.Add(id);
                            brefId = id;
                            break;
                        }
                    }
                    if (ids.Count == 0)
                        throw new ArgumentException("Block reference not found", blockName);

                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);

                    return idMap[brefId].Value;
                }
            }
        }
    }

    public class TextInfo
    {
        public Point3d Position { get; private set; }

        public Point3d Alignment { get; private set; }

        public bool IsAligned { get; private set; }

        public double Rotation { get; private set; }

        public TextInfo(Point3d position, Point3d alignment, bool aligned, double rotation)
        {
            Position = position;
            Alignment = alignment;
            IsAligned = aligned;
            Rotation = rotation;
        }
    }

    public class BlockAttribJig : EntityJig
    {
        BlockReference br;
        Dictionary<string, TextInfo> attInfos;
        Database db;
        Transaction tr;

        public Point3d Position { get; private set; }

        public BlockAttribJig(BlockReference br, Dictionary<string, TextInfo> attInfos)
            : base(br)
        {
            this.br = br;
            this.Position = br.Position;
            this.attInfos = attInfos;
            this.db = br.Database;
            this.tr = db.TransactionManager.TopTransaction;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            PromptPointResult ppr =
                prompts.AcquirePoint("\nSpecify the insert point: ");
            if (ppr.Value.DistanceTo(Position) < Tolerance.Global.EqualPoint)
                return SamplerStatus.NoChange;

            Position = ppr.Value;
            return SamplerStatus.OK;
        }

        protected override bool Update()
        {
            br.Position = Position;
            foreach (ObjectId id in br.AttributeCollection)
            {
                AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                string tag = att.Tag.ToUpper();
                if (attInfos.ContainsKey(tag))
                {
                    TextInfo ti = attInfos[tag];
                    att.Position = ti.Position.TransformBy(br.BlockTransform);
                    if (ti.IsAligned)
                    {
                        att.AlignmentPoint =
                            ti.Alignment.TransformBy(br.BlockTransform);
                        att.AdjustAlignment(br.Database);
                    }
                    if (att.IsMTextAttribute)
                    {
                        att.UpdateMTextAttribute();
                    }
                }
            }
            return true;
        }
    }
}

 

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 5 of 9 (274 Views)

Re : BlockReference Jig

04-04-2014 07:19 AM in reply to: _gile

Hi _gile,

 

Thanks for your help again, your code has ahieved my goal which the bock reference will show on the screen follow the cursor dynamicly, but I found three problems that need to improve, it's difficult to solve them by myslef. The Jig class is friend to user, but not to me  : (

 

The first question, if press ESC when the command is executed, it need to cancel the insert operation, rather than the block reference is still inserted into the mouse's current point.

 

The second problem, I do not want to display two block reference, I mean, there is a redundant block reference shows at the origin when the code executeing,  I just only need to keep the one that  follow the cursor dynamicly.

 

The third problem, it's too much trouble, in fact, my program maybe insert more than one BOM1 block reference and their contents is not the same, the function that I would like to achieve is to execute the command, and then ask the user to enter the insertion point, there are some block references, they may be one or more than one, the way they appear is from top to bottom, and they will show on the screen follow the cursor dynamicly, they will be inserted into the drawing together after enter the insertion point.


I feel the dynamic effects are consistent with move or copy multiple graphics objects. This idea is very simple, but I think a lot of places in the code needs to be modified, even I do not know how to modify.


The way they will show one the screen as follow:

capture.PNG


I actually found Jig class is really troublesome, it just makes the command more user-friendly, but does not change the actual function. And the only thing I can do is keep asking and learning.

Best wishes to you

 

Regards

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 6 of 9 (262 Views)

Re : BlockReference Jig

04-04-2014 01:36 PM in reply to: HelloWorlddd

If you're not comfortable with jigs, you can drag a selection set.

 

1.  you have to manage the PromptPointResult.Status (if not OK, erase the block reference.

2. I don't know why the block reference still displays at origin during dragging (this doesn't happen if you import the block definiton rather than the block reference as I recommand you in another thread)

3. dragging a selection set as shown below allows to easily drag multiple entities.

 

        [CommandMethod("test2")]
        public void Test2()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            try
            {
                ObjectId fiftyOneObjId = ImportBlockReference(
                    "BOM1", @"D:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");
                if (fiftyOneObjId != ObjectId.Null)
                {
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        // create a selection set containing the newly inserted bloc
                        BlockReference BlkRef =
                            (BlockReference)tr.GetObject(fiftyOneObjId, OpenMode.ForWrite);
                        PromptSelectionResult psr = ed.SelectLast();

                        // drag the selection set
                        Point3d basePt = BlkRef.Position;
                        DragCallback callback = delegate (Point3d pt, ref Matrix3d xform)
                        {
                            if (pt.IsEqualTo(basePt))
                                return SamplerStatus.NoChange;
                            xform = Matrix3d.Displacement(basePt.GetVectorTo(pt));
                            return SamplerStatus.OK;
                        };
                        PromptPointResult ppr =
                            ed.Drag(psr.Value, "\nSpecify the insertion point: ", callback);
                        if (ppr.Status == PromptStatus.OK)
                        {
                            BlkRef.TransformBy(Matrix3d.Displacement(
                                Point3d.Origin.GetVectorTo(ppr.Value)));
                        }
                        else
                        {
                            BlkRef.Erase();
                        }
                        tr.Commit();
                    }
                }
            }
            catch (System.Exception exn)
            {
                ed.WriteMessage("nError: " + exn.Message);
            }
        }

        private ObjectId ImportBlockReference(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);

            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);

            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);

                    ObjectIdCollection ids = new ObjectIdCollection();

                    BlockTableRecord btr = 
(BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead); ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb); ObjectId brefId = new ObjectId(); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); if (br.OwnerId == mSpaceId) { ids.Add(id); brefId = id; break; } } if (ids.Count == 0) throw new ArgumentException("Block reference not found", blockName); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(
ids, owner, idMap, DuplicateRecordCloning.Replace, false); return idMap[brefId].Value; } } }

 

 As I said, I'd rather import the BlockTableRecord than the BlockReference form the file:

        [CommandMethod("test3")]
        public void Test3()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

                    // if the block table doesn't contain the block, import it
                    ObjectId blockId = bt.Has("BOM1") ?
                        bt["BOM1"] :
                        ImportBlock("BOM1", @"F:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");

                    if (blockId != ObjectId.Null)
                    {
                        BlockTableRecord space =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                        // insert the block
                        BlockReference blockRef = new BlockReference(Point3d.Origin, blockId);
                        ObjectId brId = space.AppendEntity(blockRef);
                        tr.AddNewlyCreatedDBObject(blockRef, true);

                        // insert attribute references
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead);
                        RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
                        foreach (ObjectId id in btr)
                        {
                            if (id.ObjectClass == attDefClass)
                            {
                                AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                                AttributeReference attRef = new AttributeReference();
                                attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
                                blockRef.AttributeCollection.AppendAttribute(attRef);
                                tr.AddNewlyCreatedDBObject(attRef, true);
                            }
                        }

                        // create a selection set containing the newly inserted bloc
                        ObjectId[] ss = new ObjectId[1] { brId };
                        ed.SetImpliedSelection(ss);
                        PromptSelectionResult psr = ed.SelectImplied();
                        //PromptSelectionResult psr = ed.SelectLast();

                        // drag the selection set
                        Point3d basePt  = blockRef.Position;
                        DragCallback callback = (Point3d pt, ref Matrix3d xform) =>
                        {
                            if (pt.IsEqualTo(basePt))
                                return SamplerStatus.NoChange;
                            xform = Matrix3d.Displacement(basePt.GetVectorTo(pt));
                            return SamplerStatus.OK;
                        };
                        PromptPointResult ppr = 
                            ed.Drag(psr.Value, "\nSpecify the insertion point: ", callback);
                        if (ppr.Status == PromptStatus.OK)
                        {
                            blockRef.TransformBy(Matrix3d.Displacement(basePt.GetVectorTo(ppr.Value)));
                        }
                        else
                        {
                            blockRef.Erase();
                        }
                    }
                    tr.Commit();
                }
                catch (System.Exception exn)
                {
                    ed.WriteMessage("\nError: " + exn.Message);
                }
            }
        }

        // Import a block definition from a file
        private ObjectId ImportBlock(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);

            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);

            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);

                    ObjectIdCollection ids = new ObjectIdCollection();
                    ObjectId blockId = bt[blockName];
                    ids.Add(blockId);
                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);

                    return idMap[blockId].Value;
                }
            }
        }

 

 

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 7 of 9 (243 Views)

Re : BlockReference Jig

04-05-2014 04:25 AM in reply to: _gile

Hi _gile,

 

Very thanks, you are an amazing person, too much powerful.

 

According to your code, I do some modify, the program has realized the main function, now only two issues need to be solved, then it will be finished!

 

The first problem is, I try to make the program dynamically displays two block reference and select one insertion point only once in the test code, but now they are re-posted displayed. My goal is two block reference from top to bottom with their Y coordinate difference 4 during running time and result.
Since I do not understand your lambda expressions and I rarely use lambda expressions, I do not know how to modify, maybe you can get it done, well, some trouble for you

 

The second problem is, I found that once I reassigned the original TextSting of the AttributeReference, then the TextSting won't display as original alignment style during running time, but the result will be correct, it's weird.

 

Pictrue as follow:

 捕获.PNG

The code be modified by me as follow:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.IO;

[assembly: CommandClass(typeof(HelloWorld.Test3))]


namespace HelloWorld
{
    public class Test3
    {
        [CommandMethod("test3")]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                   
                    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

                    // if the block table doesn't contain the block, import it
                    ObjectId blockId = bt.Has("BOM1") ?
                        bt["BOM1"] :
                        ImportBlock("BOM1", @"D:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");

                    List<ObjectId> objIdList = new List<ObjectId>();

                    if (blockId != ObjectId.Null)
                    {
                        objIdList = getBlkRefIdList(db, tr, blockId, "QTY1", "Description1111111111", objIdList);
                        objIdList = getBlkRefIdList(db, tr, blockId, "QTY2", "Description2222222222", objIdList);
                        dragSelection(ed, objIdList,tr);
                    }
                    tr.Commit();
                }
                catch (System.Exception exn)
                {
                    ed.WriteMessage("\nError: " + exn.Message);
                }
            }
        }

        private static List<ObjectId> getBlkRefIdList(Database db, Transaction tr, ObjectId blockId, string QYTstring, string DescriptionString, List<ObjectId> objIdList)
        {
            BlockTableRecord space =
                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

            // insert the block
            BlockReference blockRef = new BlockReference(Point3d.Origin, blockId);

            ObjectId brId = space.AppendEntity(blockRef);
            tr.AddNewlyCreatedDBObject(blockRef, true);

            // insert attribute references
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead);
            RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass == attDefClass)
                {
                    AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                    AttributeReference attRef = new AttributeReference();
                    attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
                    if (attRef.Tag == "ITEM")
                    {
                        attRef.TextString = "X";
                    }
                    if (attRef.Tag == "PART")
                    {
                        attRef.TextString = "X";
                    }
                    if (attRef.Tag == "MATRL")
                    {
                        attRef.TextString = "SA-193-B7/SA-194-2H";
                    }
                    if (attRef.Tag == "QTY")
                    {
                        attRef.TextString = QYTstring;
                    }
                    if (attRef.Tag == "DESCRIPTION")
                    {
                        attRef.TextString = DescriptionString;
                    }
                    blockRef.AttributeCollection.AppendAttribute(attRef);
                    tr.AddNewlyCreatedDBObject(attRef, true);
                }
            }
            objIdList.Add(brId);
            return objIdList;
        }

        private static void dragSelection(Editor ed, List<ObjectId> objIdList, Transaction tr)
        {
            // create a selection set containing the newly inserted bloc
            ObjectId[] ss = objIdList.ToArray();
            int offset = 0;
            
            ed.SetImpliedSelection(ss);
            PromptSelectionResult psr = ed.SelectImplied();

            // drag the selection set
            Point3d basePt = Point3d.Origin;
            DragCallback callback = (Point3d pt, ref Matrix3d xform) =>
            {
                if (pt.IsEqualTo(basePt))
                    return SamplerStatus.NoChange;
                xform = Matrix3d.Displacement(basePt.GetVectorTo(new Point3d(pt.X, pt.Y - offset, 0)));
                return SamplerStatus.OK;
            };
            PromptPointResult ppr =
                ed.Drag(psr.Value, "\nSpecify the insertion point: ", callback);

            foreach (ObjectId Id in objIdList)
            {

                BlockReference blkRef = tr.GetObject(Id, OpenMode.ForRead) as BlockReference;
               
                if (blkRef != null)
                {
                    //PromptSelectionResult psr = ed.SelectLast();

                    if (ppr.Status == PromptStatus.OK)
                    {
                        blkRef.TransformBy(Matrix3d.Displacement(basePt.GetVectorTo(new Point3d(ppr.Value.X, ppr.Value.Y - offset, 0))));
                    }
                    else
                    {
                        blkRef.Erase();
                    }
                }
                offset = offset + 4;
            }
        }

        // Import a block definition from a file
        private ObjectId ImportBlock(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);

            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);

            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);

                    ObjectIdCollection ids = new ObjectIdCollection();
                    ObjectId blockId = bt[blockName];
                    ids.Add(blockId);
                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);

                    return idMap[blockId].Value;
                }
            }
        }

    }

 
}

 

Thank you as always.

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 8 of 9 (235 Views)

Re : BlockReference Jig

04-05-2014 08:24 AM in reply to: HelloWorlddd

If you're  not  comfortable with anonymous functions or lambda expression you can define a private method and pass it as delegate to the Editor.Drag() method.

 

        private SamplerStatus Callback(Point3d pt, ref Matrix3d xform)
        {
            if (pt.IsEqualTo(Point3d.Origin))
                return SamplerStatus.NoChange;
            xform = Matrix3d.Displacement(Point3d.Origin.GetVectorTo(pt));
            return SamplerStatus.OK;
        }

 But this suppose your base point is Point3d.Origin or you'd have to use a private field to pass the base point to the private method.

This is one intererst of creating a DragCallback instance (with an anonymous or lambda function) within the method the block is inserted, in other words, within the insertion point scope.

 

Anyway, this has nothing to do with you issues.

First, if you don't want the two block reference overlap, don't insert them at the same point (Point3d.Origin) an then, use one of these insertion point as base point for the drag callback function.

Second, if you want the attributes alignment dispaly during dragging, you need to use a jig (more complex but more powerfull) as shown in the BlockAttributeJig example.

 

        [CommandMethod("test4")]
        public void Test4()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {

                    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                    // if the block table doesn't contain the block, import it
                    ObjectId blockId = bt.Has("BOM1") ?
                        bt["BOM1"] :
                        ImportBlock("BOM1", @"D:\AutocadCommandCollectionNew\Data\Drawing\BOM1.dwg");
                    if (blockId != ObjectId.Null)
                    {
                        BlockTableRecord space =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        BlockReference[] refs = new BlockReference[2]{
                            InsertBlock(space, blockId, Point3d.Origin, "QTY1", "Description1111111111"),
                            InsertBlock(space, blockId, new Point3d(0.0, 5.0, 0.0), "QTY1", "Description2222222222") };
                        ObjectId[] ids = new ObjectId[2] { refs[0].ObjectId, refs[1].ObjectId };
                        // create a selection set containing the newly inserted bloc
                        ed.SetImpliedSelection(ids);
                        PromptSelectionResult psr = ed.SelectImplied();
                        // drag the selection set
                        Point3d basePt = refs[0].Position;
                        DragCallback callback = (Point3d pt, ref Matrix3d xform) =>
                        {
                            if (pt.IsEqualTo(basePt))
                                return SamplerStatus.NoChange;
                            xform = Matrix3d.Displacement(basePt.GetVectorTo(pt));
                            return SamplerStatus.OK;
                        };
                        PromptPointResult ppr =
                            ed.Drag(psr.Value, "\nSpecify the insertion point: ", callback);
                        if (ppr.Status == PromptStatus.OK)
                        {
                            foreach (BlockReference br in refs)
                            {
                                br.TransformBy(Matrix3d.Displacement(br.Position.GetVectorTo(ppr.Value)));
                            }
                        }
                        else
                        {
                            foreach (BlockReference br in refs)
                            {
                                br.Erase();
                            } 
                        }
                    }
                    tr.Commit();
                }
                catch (System.Exception exn)
                {
                    ed.WriteMessage("\nError: " + exn.Message);
                }
            }
        }

        private BlockReference InsertBlock(
            BlockTableRecord owner,
            ObjectId blockId,
            Point3d insPt,
            string QYTstring,
            string DescriptionString)
        {
            Database db = blockId.Database;
            Transaction tr = db.TransactionManager.TopTransaction;

            // insert the block
            BlockReference blockRef = new BlockReference(insPt, blockId);
            owner.AppendEntity(blockRef);
            tr.AddNewlyCreatedDBObject(blockRef, true);
            // insert attribute references
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead);
            RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));
            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass == attDefClass)
                {
                    AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                    AttributeReference attRef = new AttributeReference();
                    attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
                    if (attRef.Tag == "ITEM")
                    {
                        attRef.TextString = "X";
                    }
                    if (attRef.Tag == "PART")
                    {
                        attRef.TextString = "X";
                    }
                    if (attRef.Tag == "MATRL")
                    {
                        attRef.TextString = "SA-193-B7/SA-194-2H";
                    }
                    if (attRef.Tag == "QTY")
                    {
                        attRef.TextString = QYTstring;
                    }
                    if (attRef.Tag == "DESCRIPTION")
                    {
                        attRef.TextString = DescriptionString;
                    }
                    blockRef.AttributeCollection.AppendAttribute(attRef);
                    tr.AddNewlyCreatedDBObject(attRef, true);
                }
            }
            return blockRef;
        }

        // Import a block definition from a file
        private ObjectId ImportBlock(string blockName, string filenName)
        {
            if (!File.Exists(filenName))
                throw new FileNotFoundException("File not found", filenName);
            Database targetDb = HostApplicationServices.WorkingDatabase;
            ObjectId owner = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);
            using (Database sourceDb = new Database(false, true))
            {
                sourceDb.ReadDwgFile(filenName, FileShare.ReadWrite, false, "");
                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    if (!bt.Has(blockName))
                        throw new ArgumentException("Block definition not found", blockName);
                    ObjectIdCollection ids = new ObjectIdCollection();
                    ObjectId blockId = bt[blockName];
                    ids.Add(blockId);
                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Ignore, false);
                    return idMap[blockId].Value;
                }
            }
        }

 

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 9 of 9 (229 Views)

Re : BlockReference Jig

04-05-2014 09:41 AM in reply to: _gile

According to your suggestion, I have solved the first problem, the second question will only effect the display affect during draging  and it does not effect the final result, I intend to using this method that dragging a selection set.
I think it really should be celebrated, Anyway, thank you very much, best wishes to you : )

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.