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

Cant get position of nested entity within xreference

5 REPLIES 5
SOLVED
Reply
Message 1 of 6
js75CAD
276 Views, 5 Replies

Cant get position of nested entity within xreference

Hi All,

 

I am trying to determine if a line crosses an entity within an xreference, but my understanding of Matrix3d is obviously shot! The first thing I did was grab the Blocktablerecord origin and calculate the displacement to the inserted BlockReference (Xref). In this instance I inserted it at 100,100. 

disp = block.Position.TransformBy(ucs).GetVectorTo(XrefBlocktableRecord.Origin.TransformBy(ucs))

That worked. Now if the entity inside the block was a circle or a line, hey, no problem, I moved the entity by the displacement and got the intersection point. As long as the rotation of the Xref was 0.

oXrefEntity.TransformBy(Matrix3d.Displacement(disp))

If the entity was a block I had to start dealing with that, so I started iterating all of the entities and had to move them to account for the position of the block in the Actual Xref drawing, so not only is the Xref displaced by 100, 100, now I had to move the block as well.

Dim subBlockreference As BlockReference = CType(SubEntity, BlockReference)
					Dim SubBlockBtr As BlockTableRecord = TryCast(tr.GetObject(subBlockreference .BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                                For Each btriD As ObjectId In SubBlockBtr
                                    Dim subEnt As Entity = TryCast(tr.GetObject(btriD, OpenMode.ForWrite, False), Entity)
                                    If subEnt.Visible = True Then
                                        Dim newdisp As Vector3d = XrefBlockTableRecord.Origin.TransformBy(ucs).GetVectorTo(subBlockreference .Position.TransformBy(ucs))
                                        subEnt.TransformBy(Matrix3d.Displacement(newdisp))
                                        subEnt.IntersectWith(oPolyline, Intersect.OnBothOperands, points, New IntPtr(0), New IntPtr(0))
                                        If points.Count <> 0 Then Exit For
                                    End If
                                Next

 

And that sort of worked.... But the minute any rotation got involved, it all goes to ... well you know.

 

So I tried moving my polyline to align with the Xreference position. I can see my xreference is moved from 0,0 to 100,100 and the rotation is 10 degrees. BUT, when I run my calc, my displacement comes out at -100,-100 (which is what I assume to be correct), but when I type this line :

 

oPolyline.TransformBy(Matrix3d.Displacement(disp))

 

It keeps moving the line by a distance 200 in both axis! 

 

At one point I was able to iterate the xref and catch the block and nested line, but the minute I rotated it, it all went to hell.

 

All I want is to be able to check if the Polyline in my drawing clashes with any item in the xref. If the item is a block reference I then try to iterate each record, but it won't work. I am so frustrated. Does anyone have a clue how to account for entites within an xreference being moved AND rotated and then if that entity is a block, how to deal with that rotation and displacement?

 

Does anyone have any input that might see me on the right path here?

 

Thanks in advance

 

 

 

5 REPLIES 5
Message 2 of 6
ActivistInvestor
in reply to: js75CAD

You use the BlockReference.BlockTransform matrix to transform entities in a block's definition into the coordinate system of an insertion of the block reference or visa-verse.

 

If you need to test many objects in a block's definition against a single object in the same space as an insertion of the block, then it would make sense to transform the object into the block definition's MCS (using the Inverse() of the BlockTransform property), and test against entities in the block definition. That requires only one transformation to test all objects in the block's definition, verses one transformation for each of them.

Message 3 of 6
js75CAD
in reply to: ActivistInvestor

Thanks Activist. I did try block transform, but I have never seen or used it before so I think my understanding of it is a bit shabby.

 

Would you have an example where you have used it before? Not asking for the whole thing just an example of how you used it.

 

Thanks.

Message 4 of 6
ActivistInvestor
in reply to: js75CAD

Deleted: I found a more-recent version of the example. See the next post for it.

 

 

 

Message 5 of 6
ActivistInvestor
in reply to: js75CAD

I searched my old code base and found an example that uses the BlockTransform property to add selected objects to a block definition. It clones and transforms the selected entities (in the same space as the insertion of the block) to the block definition 's WCS, using the block insertion's BlockTransform property. 

 

Unfortunately, that's the closest I have to an example of what you need to do.

 

public static class AddToBlockExample
{ 
   /// <summary>
   /// Shows how to transform an entity into the
   /// WCS of a block definition.
   /// 
   /// This example prompts for a selection of objects 
   /// and a block reference, and adds the selected 
   /// objects to the selected block reference's block 
   /// definition.
   /// 
   /// The example also shows how to check the selection
   /// for cyclical references and disallow adding objects 
   /// that would result in a self-referencing block.
   /// </summary>

   [CommandMethod("ADDTOBLOCK", CommandFlags.NoBlockEditor)]
   public static void ExampleAddToBlock()
   {
      Document doc = Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      using(var tr = doc.TransactionManager.StartTransaction())
      {
         PromptSelectionOptions pso = new PromptSelectionOptions();
         var psr = ed.GetSelection();
         if(psr.Status != PromptStatus.OK)
            return;
         var per = ed.GetEntity<BlockReference>("\nSelect insertion: ");
         if(per.Status != PromptStatus.OK || psr.Value.Count == 0)
            return;
         ObjectId insert = per.ObjectId;
         ObjectId[] idArray = psr.Value.GetObjectIds();
         ObjectIdCollection ids = new ObjectIdCollection(idArray);
         BlockReference blkref = (BlockReference)
            tr.GetObject(insert, OpenMode.ForRead);
         var btr = (BlockTableRecord)tr.GetObject(
            blkref.DynamicBlockTableRecord, 
            OpenMode.ForRead);

         /// Check for and reject selections that
         /// would result in a self-referencing block:
         if(btr.IsReferencedBy(idArray))
         {
            ed.WriteMessage("\nInvalid selection: One or more "
               + "selected objects reference the selected block.");
            tr.Commit();
            return;
         }
         Database db = btr.Database;
         IdMapping map = new IdMapping();
         db.DeepCloneObjects(ids, btr.ObjectId, map, false);
         var newIds = map.Cast<IdPair>()
            .Where(p => p.IsPrimary && p.IsCloned)
            .Select(p => p.Value);
         /// Transform cloned objects to the block definition's WCS:
         Matrix3d transform = blkref.BlockTransform.Inverse();
         foreach(ObjectId id in newIds)
         {
            Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
            ent.TransformBy(transform);
         }
         tr.Commit();
         ed.Regen();
         Autodesk.AutoCAD.Internal.CoreUtils.SetUndoRequiresRegen(db);
      }
   }

   /// <summary>
   /// Returns a value indicating if one or more elements in the 
   /// argument is or contains a reference to the BlockTableRecord 
   /// the method is invoked on.
   /// </summary>
   /// <param name="btr"></param>
   /// <param name="entities"></param>
   /// <returns></returns>
   /// <exception cref="ArgumentNullException"></exception>

   static bool IsReferencedBy(this BlockTableRecord btr, IEnumerable<ObjectId> entities)
   {
      if(btr == null || btr.IsDisposed)
         throw new ArgumentNullException(nameof(btr));
      if(entities == null)
         throw new ArgumentNullException(nameof(entities));
      var ids = btr.GetBlockReferenceIds(false, true);
      HashSet<ObjectId> set = new HashSet<ObjectId>(ids.Cast<ObjectId>());
      foreach(ObjectId id in entities)
      {
         if(set.Contains(id))
            return true;
      }
      return false;
   }

   public static PromptEntityResult GetEntity<T>(this Editor ed, 
         string message,
         bool readOnly = true)
      where T : Entity
   {
      return ed.GetEntity<T>(new PromptEntityOptions(message));
   }

   public static PromptEntityResult GetEntity<T>(this Editor ed, 
         PromptEntityOptions options, 
         bool readOnly = true)
      where T : Entity
   {
      RXClass rxclass = RXObject.GetClass(typeof(T));
      string name = rxclass.DxfName;
      if(string.IsNullOrEmpty(name))
         name = rxclass.Name;
      options.SetRejectMessage($"\nInvalid selection. Requires a {name},");
      options.AddAllowedClass(typeof(T), false);
      if(readOnly)
         options.AllowObjectOnLockedLayer = true;
      return ed.GetEntity(options);
   }
}

 

Message 6 of 6
js75CAD
in reply to: ActivistInvestor

Thank you very much! While not the 'Solution', it is an excellent example and shows me the missing piece where you got the matrix3D from the inverse. Brilliant!

 

This is precisely what I needed. Not the answer but something that shows me where to start.

 

Much appreciated Activist!

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

Post to forums  

Technology Administrators


Autodesk Design & Make Report