.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to capture the real point of a line within a block?

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
NayaraFJ
719 Views, 10 Replies

How to capture the real point of a line within a block?

How to capture the real point of a line within a block?

I used the following method to captured some entities  from a block.

I need the point of the entities, to redesign a dimension.

But if I move the original block, and then run my program. The dimension is redesigned in the original location of the block.

 

Basically the code looks like this:

 

 private void FilterDimension()
        {
            TypedValue[] typedValue = new TypedValue[2];
            typedValue.SetValue(new TypedValue((int)DxfCode.Start, "INSERT"), 0);
            typedValue.SetValue(new TypedValue((int)DxfCode.LayerName, "Dimension"), 1);
            SelectionFilter selectionFilter = new SelectionFilter(typedValue);
            ObjectId[] objectIdList = editor.SelectAll(selectionFilter).Value.GetObjectIds();
            for (int i = 0; i < objectIdList.Length; i++)
            {
                ObjectId objectId = objectIdList[i];
                BlockReference blockReference = (BlockReference)objectId.GetObject(OpenMode.ForRead);
                BlockTableRecord blockTableRecord = (BlockTableRecord)blockReference.BlockTableRecord.GetObject(OpenMode.ForRead);

                //Listas de objetos
                List<Line> lineList = new List<Line>();
                List<DBText> dBTextList = new List<DBText>();
                List<Arc> arcList = new List<Arc>();
                List<Hatch> hatchList = new List<Hatch>();

                foreach (ObjectId item in blockTableRecord)
                {
                    DBObject dBObject = (DBObject)item.GetObject(OpenMode.ForRead);
                    if (dBObject.GetType() == typeof(Line))
                    {
                        lineList.Add((Line)dBObject);
                    }
                    else if (dBObject.GetType() == typeof(DBText))
                    {
                        dBTextList.Add((DBText)dBObject);
                    }
                    else if (dBObject.GetType() == typeof(Arc))
                    {
                        arcList.Add((Arc)dBObject);
                    }
                    else if (dBObject.GetType() == typeof(Hatch))
                    {
                        hatchList.Add((Hatch)dBObject);
                    }
                }
            }
}

 But if I use use the End / Start Point captured in "LineList" for example, he did not return the value if the block was moved.

 

How could I fix it?
Now, thanks!

 

Smiley Tongue

10 REPLIES 10
Message 2 of 11
norman.yuan
in reply to: NayaraFJ

The entities you collected in the Lists is from Block definition (BlockTablerecord), so the geometric references of these entities are defined in relationship with the Block definition's insertion point as base point (0,0,0). Since you actually want is goemetric reerences of entities in BlockReference, so you need to transform the geometric references obtained from the entities iin BlockTableRecord according to position of BlockReference.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 11
NayaraFJ
in reply to: norman.yuan

It has examples of how to do?

Message 4 of 11
norman.yuan
in reply to: NayaraFJ

It is fairly simple to calculate points based on the diference (Vector3d) between Block definition base point (0,0,0) and BlockReference's insertion point. Here is the code sample I quickly assemled:

 

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

[assembly: CommandClass(typeof(EntPositionInBlk.MyCommands))]

namespace EntPositionInBlk
{
    public class MyCommands 
    {
        [CommandMethod("EntInBlk")]
        public void GetEntityPositionInBlock1()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ObjectId blkId = PickBlock(ed);
            if (blkId == ObjectId.Null)
            {
                ed.WriteMessage("\n*cancel*\n");
                return;
            }

            ShowEntitiesInBlock(blkId, doc);
        }

        #region private methods

        private ObjectId PickBlock(Editor ed)
        {
            ObjectId blk = ObjectId.Null;

            PromptEntityOptions opt = new PromptEntityOptions("\nPick a block: ");
            opt.SetRejectMessage("Not a block reference!");
            opt.AddAllowedClass(typeof(BlockReference), true);

            PromptEntityResult res = ed.GetEntity(opt);
            if (res.Status == PromptStatus.OK)
            {
                blk = res.ObjectId;
            }

            return blk;
        }

        private void ShowEntitiesInBlock(ObjectId id, Document dwg)
        {
            using (Transaction tran = dwg.Database.TransactionManager.StartTransaction())
            {
                BlockReference bRef = (BlockReference)tran.GetObject(id, OpenMode.ForRead);
                BlockTableRecord br = 
                    (BlockTableRecord)tran.GetObject(bRef.BlockTableRecord, OpenMode.ForRead);

                //BlockRefernece's insertion point
                Point3d insPt = bRef.Position;

                foreach (ObjectId entId in br)
                {
                    //for smplicity, only list Line entity in the block
                    Line line = tran.GetObject(entId, OpenMode.ForRead) as Line;
                    if (line != null)
                    {
                        //Line's StartPoint in block definition
                        Point3d pt = line.StartPoint;

                        //Block definition base point
                        Point3d p = new Point3d(0.0,0.0,0.0);

                        //Actual StartPoint in the BlockReference
                        Point3d point = pt.Add(p.GetVectorTo(insPt));

                        dwg.Editor.WriteMessage(
                            "\nStart point: x={0}, y={1}, z={2}", point.X, point.Y, point.Z);
                    }
                }

                tran.Commit();
            }

            dwg.Editor.WriteMessage("\n");
        }

        #endregion
    }
}

 Pay attention to the comments made in ShowEntitiesInBlock() method.

 

HTH

Norman Yuan

Drive CAD With Code

EESignature

Message 5 of 11

But that will only provide a translation, ignoring any possible rotation, scaling, or mirroring, so why not skip that and use the BlockTransform from the BlockReference?  That's what I would do.  (don't really have time at this moment to work up a sample)

Dave O.                                                                  Sig-Logos32.png
Message 6 of 11

You are rignt, using TransformBy would make the code simpler, like this:

 

private void ShowEntitiesInBlock_A(ObjectId id, Document dwg)
{
    using (Transaction tran = dwg.Database.TransactionManager.StartTransaction())
    {
        BlockReference bRef = (BlockReference)tran.GetObject(id, OpenMode.ForRead);
        BlockTableRecord br =
            (BlockTableRecord)tran.GetObject(bRef.BlockTableRecord, OpenMode.ForRead);

        Matrix3d mat = bRef.BlockTransform;

        foreach (ObjectId entId in br)
        {
            //for smplicity, only list Line entity in the block
            Line line = tran.GetObject(entId, OpenMode.ForRead) as Line;
            if (line != null)
            {
                Point3d pt = line.StartPoint;
                Point3d point = pt.TransformBy(mat);

                dwg.Editor.WriteMessage(
                    "\nStart point: x={0}, y={1}, z={2}", point.X, point.Y, point.Z);
            }
        }

        tran.Commit();
    }

    dwg.Editor.WriteMessage("\n");
}

I was simply show the OP with quick code that the geometric references in BlockTableRecord is not what he wants.

 

However, if the BlockReference could be rotated/mirrored, the just using BlockReference.BlcokTransform would not enough. One has do Point3d.TransformedBy(Matrix3d) futher according to how the rotating/mirroring was done (rotating/mirroring base point/line, rotating angle... Since BlockReference itself does not keeps track where rotating base point is if it was rotated, it is simply not possible to construct a Matrix3d to transform the points of the line.

 

This leads to another (more reliable) solution: one can explode the BlockReference (which only create a set entities in the same location as the blockrefeence), then loop through these entities to obtain wanted geometric references, and finally erased those entities from BlockReference explosion.

Norman Yuan

Drive CAD With Code

EESignature

Message 7 of 11

No disrespect Norman, but I disagree.  I have a number of functions using the BlockTransform in exactly this manner, and it accounts for everything.  The BlockTransform is a combined matrix which covers rotation, displacement, mirroring and scaling, and ultimately the basepoint used for any of those operations is irrelevant.  (You could think of it as the BlockTransform that AutoCAD stores in the BlockReference has been Normalized to the Block's Insertion point, though I think that may be over-simplifying what actually happens behind the curtain)

 

One example that comes to mind is one of my Overrules which adds a second Grip to the "Endpoint" of a block.  This particular block can be rotated (even rotated in 3d, Normal.Z < 1), is Always scaled non-uniformly, and could be mirrored, but all I do is transform the known BlockTableRecord Point3d by the BlockTransform and the grip always comes in at the right place.

 

And, yes, I also thought of the option of exploding the block, but I would only resort to that if it were absolutely necessary, and in this case I don't believe it is.  I just don't like creating and erasing all those temporary entities when there is an easier way.

Dave O.                                                                  Sig-Logos32.png
Message 8 of 11

Hi CBC,

 

You're correct that the BlockTransform matrix is the accumulation of every tranformation applied to the BlockReference. That is all you should need to translate from the block coordinate system to the world coordinate system. And, of course, you need to iteratively apply the block transform matrices for nested blocks.

 

I'm replying to this post because I have a recollection that you also have to account for the possibility that BlockTableRecord.Origin may not be (0,0,0) - which is an additional translation you may have to apply. Its rare, but I have come across drawings where this is the case.

Cheers,

Stephen Preston
Autodesk Developer Network
Message 9 of 11

A good point I had not thought of, Stephen.  My Overrules (and pretty much all of my other code) are dealing with blocks that my code creates, so I never encountered that problem.  Maybe something I should look at to make some of my base helper functions that much more robust, just in case.

 

And Norman, regardless of the BlockTransform discussion, thanks for posting the example, I really didn't have time to mess with it today.  (which by now was actually yesterday. it's 2:00 AM my time)

Dave O.                                                                  Sig-Logos32.png
Message 10 of 11
NayaraFJ
in reply to: norman.yuan

Thanks guys! I will test here. Smiley Tongue

Message 11 of 11
NayaraFJ
in reply to: NayaraFJ

Sorry to be posting below, I could not edit my answer.

 

Thank you! It worked. I had a small problem if the block has been rotated. Why use the angle of the existing text, I use the points of the line parallel to the text to find the slope.

 

Thank you all helped a lot! Robot tongue

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost