C#, Get Block at Point

C#, Get Block at Point

DirtyDanLand
Enthusiast Enthusiast
3,805 Views
9 Replies
Message 1 of 10

C#, Get Block at Point

DirtyDanLand
Enthusiast
Enthusiast

In C#, what would be the best way to get a block inserted at a specified point?

I am trying to get attributes from a block inserted at the endpoint of a polyline.  The endpoints of the polyline and the blockname are known.

 

I just can not figure out how to get the block.  Once I get the block I know how to get the attributes.

 

Thanks

Dan

0 Likes
Accepted solutions (1)
3,806 Views
9 Replies
Replies (9)
Message 2 of 10

DirtyDanLand
Enthusiast
Enthusiast
I should mention that I need to be able to do this without having the user select the block.
0 Likes
Message 3 of 10

DirtyDanLand
Enthusiast
Enthusiast

With some help from this site, this is what I came up with...  Wondering, if there is a better way?

 

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

                BlockTable acBlkTble = tr.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

                foreach (ObjectId btrObjId in acBlkTble)
                {
                    BlockTableRecord btr = tr.GetObject(btrObjId, OpenMode.ForRead) as BlockTableRecord;

                    ObjectIdCollection objIdColl = btr.GetBlockReferenceIds(true, true);

                    foreach (ObjectId objId_loopVariable in objIdColl)
                    {
                        BlockReference blk = (BlockReference)tr.GetObject(objId_loopVariable, OpenMode.ForRead);
                        blockName = blk.Name.ToUpper();

                        if (blockName.IndexOf("WIRE-END") != -1)
                        {
                            pntBlockOrigin = blk.Position;
                            if (pntBlockOrigin == pntPolyBeg)
                            {
                                //get the attributes
                                AttributeCollection attCol = blk.AttributeCollection;
                                foreach (ObjectId attId in attCol)
                                {
                                    AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);

                                    switch (attRef.Tag.ToUpper())
                                    {
                                        case "END-ID":
                                            attBegValue[0] = attRef.TextString;
                                            break;
                                        case "END-TERM":
                                            attBegValue[1] = attRef.TextString;
                                            break;
                                    }
                                }
                            }
                            else if (pntBlockOrigin == pntPolyEnd)
                            {
                                //get the attributes
                                AttributeCollection attCol = blk.AttributeCollection;
                                foreach (ObjectId attId in attCol)
                                {
                                    AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);

                                    switch (attRef.Tag.ToUpper())
                                    {
                                        case "END-ID":
                                            attEndValue[0] = attRef.TextString;
                                            break;
                                        case "END-TERM":
                                            attEndValue[1] = attRef.TextString;
                                            break;
                                    }
                                }
                            }

                        }
                    }
                }
                tr.Commit();
            }
0 Likes
Message 4 of 10

fieldguy
Advisor
Advisor

Create a pair of Point3D objects that define a window.  P3D1 will be bottom right, and P3D2 will be top left.  I use the term "aperture" - the last value I used was 20 metres.  This creates a window that is 40 metres square, with your endpoint in the centre.

 

double aperture = 20.0;

Point3d P3D1 = new Point3d(yourpolylineendpoint.X - aperture, yourpolylineendpoint.Y - aperture, 0);
Point3d P3D2 = new Point3d(yourpolylineendpoint.X + aperture, yourpolylineendpoint.Y + aperture, 0);

 

Define a typedvalue and selection filter for "INSERT".

acdb.TypedValue[] values = { new acdb.TypedValue((int)acdb.DxfCode.Start, "INSERT") };
SelectionFilter sf = new SelectionFilter(values);

 

Create a prompt for select crossing window using your new points.
PromptSelectionResult psr = doc.Editor.SelectCrossingWindow(P3D1, P3D2, sf);

 

Check the status and see if there are any inserts within the window.

if (psr.Status == PromptStatus.OK && psr.Value.Count > 0)
{

  acdb.ObjectIdCollection psrobjids = new acdb.ObjectIdCollection(psr.Value.GetObjectIds());
foreach (acdb.ObjectId oid in psrobjids)
{
acdb.BlockReference myblk = (acdb.BlockReference)tx.GetObject(oid, acdb.OpenMode.ForRead);
if (myblk.Name == "the block you are looking for")
{
  // do what you need to do
  // break;
}
}

}

 

 <edit>

I am not sure if this way is any better than your last post.  It looks like that works as well.  Your way will work even if the block is not visible in the editor.  I believe that object selection using window crossing implies that the object is visible in the editor window. If that's correct, your way is better.

</edit> 

0 Likes
Message 5 of 10

DirtyDanLand
Enthusiast
Enthusiast

thanks for the reply... the only problem is I can not have anything else getting selected since my palette and the information it receives is based on a single selected polyline. It would create more of a headache iterating through the selected objects since the polyline needs to stay selected.

0 Likes
Message 6 of 10

fieldguy
Advisor
Advisor

The user selection and your program selection are not the same.  The user is not involved with (and does not see) the crossing window selection. 

0 Likes
Message 7 of 10

DirtyDanLand
Enthusiast
Enthusiast

I did not know that, thanks...

0 Likes
Message 8 of 10

_gile
Consultant
Consultant
Accepted solution

Hi,

 

The GetBlockReferenceIds() route is fine, but your code can be optimized:

- get directly the block table record in the block table using its name instead of scaning the whole block table ;

- exit the foreach loop as soon as a matching position block is found.

 

            using (Transaction tr = acCurDb.TransactionManager.StartTransaction())
            {
                BlockTable acBlkTble = tr.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

                // directly get the record in the table using its name
                BlockTableRecord btr = tr.GetObject(acBlkTble["WIRE-END"], OpenMode.ForRead) as BlockTableRecord;

                foreach (ObjectId objId_loopVariable in btr.GetBlockReferenceIds(true, true))
                {
                    BlockReference blk = (BlockReference)tr.GetObject(objId_loopVariable, OpenMode.ForRead);

                    if (blk.Position == pntPolyBeg)
                    {
                        //get the attributes
                        AttributeCollection attCol = blk.AttributeCollection;
                        foreach (ObjectId attId in attCol)
                        {
                            AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);

                            switch (attRef.Tag.ToUpper())
                            {
                                case "END-ID":
                                    attBegValue[0] = attRef.TextString;
                                    break;
                                case "END-TERM":
                                    attBegValue[1] = attRef.TextString;
                                    break;
                            }
                        }
                        break; // exit the foreach loop as soon as the block is found
                    }
                    else if (blk.Position == pntPolyEnd)
                    {
                        //get the attributes
                        AttributeCollection attCol = blk.AttributeCollection;
                        foreach (ObjectId attId in attCol)
                        {
                            AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);

                            switch (attRef.Tag.ToUpper())
                            {
                                case "END-ID":
                                    attEndValue[0] = attRef.TextString;
                                    break;
                                case "END-TERM":
                                    attEndValue[1] = attRef.TextString;
                                    break;
                            }
                        }
                        break;  // exit the foreach loop as soon as the block is found
                    }
                }
                tr.Commit();
            }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 10

DirtyDanLand
Enthusiast
Enthusiast

thanks for the tip...

0 Likes
Message 10 of 10

Anonymous
Not applicable

Just keep in mind that

btr.GetBlockReferenceIds(true, true)

will return a 0 on a dynamic block.

_gile himself talks about how to fetch dynamic blocks on a more recent post:

https://forums.autodesk.com/t5/net/blockreferenceids-is-sometimes-empty/m-p/7044001#M53047

0 Likes