Jigging Block Properties

A few days ago, I noticed a post on the AutoDesk Forums, asking for a way to edit a block property, immediately after inserting the block.

I bet that there is more than one way to handle this kind of action, but I’ll describe how I’d do it.

There are a few steps to do, before you can do this action.

First, to insert a Block and Jig it, you need to insert the block into the drawing. Next step is to position the block with a Jig. And then use a Jig that controls some properties of the Jig.
In my case I will use a Jig that controls the rotation of the block, and the length-property.

Note that this could be easily mimicked by just a regular rectangle, but you’ll get the point. I believe that being creative with this technique can lead to powerful, very user-friendly mechanisms.

To the code: Setting up the basics first, as these will happen exactly as in my last post, I will not include these in the code samples. Complete files of the code can be found on Google Code. Just go to the tab ‘Source’, click on ‘Browse’, expand the trunk and choose ‘BlockPropertyDrag’.

The first thing we need to do, is to set everything up. So basically, insert a block.

   1: Database db = doc.Database;
   2: BlockTable blockTable = t.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
   4: // first, create the block reference in memory
   5: ObjectId blockDefinitionId = blockTable["dummy"];
   6: BlockReference blockReference = new BlockReference(
   7:     new Point3d(0, 0, 0), blockDefinitionId);
   9: // first append the block
  10: BlockTableRecord modelSpace = t.GetObject(
  11:     blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false) as BlockTableRecord;
  13: modelSpace.AppendEntity(blockReference);
  15: t.AddNewlyCreatedDBObject(blockReference, true);

Then we will first call the ‘place-the-block-into-position’-Jig:

   1: // allow user to move the block around with the InsertBlockJig
   2: InsertBlockJig insertBlockJig = new InsertBlockJig(blockReference);
   4: if (ed.Drag(insertBlockJig).Status != PromptStatus.OK)
   5:     return;

And then we call the property-drag Jig:

   1: // do the property drag jig on the block
   2: BlockPropertyDragJig dragJig = new BlockPropertyDragJig(blockReference);
   4: if (ed.Drag(dragJig).Status != PromptStatus.OK)
   5:     return;
   7: t.Commit();

So far for the command. Of course, the real action is in the jigs. I’ll only show the Update() methods, the rest of the code is very default, and again, can be found on Google Code.

I did add 2 readonly properties to the Jigs: CurrentPosition and JiggedBlockReference. These properties basically just cast the protected Entity to BlockReference and return its position.

Our InsertBlockJig Update() method is very simple, we simply add the resulting Vector the the Block’s Position.

   1: protected override bool Update()
   2: {
   3:     JiggedBlockReference.Position = JiggedBlockReference.Position.Add(currentVector);
   4:     return true;
   5: }

That’s it for positioning. The currentVector variable is a global variable, set in the Sampler() Method. It just holds the Vector from the current Block’s Position and the registered mouse position in Sampler(). This is also how I did it in my last post on post on jigging multiple entities.

Now, for the BlockPropertyDragJig, where we will be updating the block properties, we need to fill in the Update() as follows:

   1: protected override bool Update()
   2: {
   4:     // only 2d
   5:     Point2d oldPosition = new Point2d(CurrentPosition.X, CurrentPosition.Y);
   6:     Point2d newPosition = new Point2d(lastMousePosition.X, lastMousePosition.Y);
   8:     JiggedBlockReference.Rotation = oldPosition.GetVectorTo(newPosition).Angle - Math.PI/2;
  10:     // loop properties to find the ones we need
  11:     foreach (DynamicBlockReferenceProperty prop in JiggedBlockReference.DynamicBlockReferencePropertyCollection)
  12:     {
  13:         if (prop.PropertyName.ToUpper() == "LENGTH")
  14:         {
  15:             prop.Value = oldPosition.GetDistanceTo(newPosition);
  16:         }
  17:     }
  19:     return true;
  20: }

Basically, we’re calculating 2 things here: the distance and the angle from the mouse position to the Block’s position (which is his Insertion Point).

The angle is controlling the rotation of the Block. The distance is controlling the Length property.

So that’s all there is to it. Full code on Google Code.

One more thing, I personally find working with Blocks in the AutoCad API very inefficient and cumbersome. I can only suggest that you create a Wrapper for your Blocks, and service classes that provide all the needed functionality for you. If you’ll decide to create all your Block-Handling code on-the-fly, you’ll most likely have a very error-prone process and lots of duplicate code.

Posted by Bert Vanpeteghem

4 reacties:

Mark said...


I occasionally wondered in what situations a jig might be useful. Your example is a very good primer on how and when to use a jig.

Keep on writing :)

Bert Vanpeteghem said...

Jigs are very useful for giving the user some kind of visual feedback on an operation. You can show the results of his movements before he even confirms the command. You can also control his action, or make his actions more practical. While some things can be achieved by using dynamic blocks, when using jigs you, as a developer, have complete control.

I'm thinking on how to provide a simple example, but I'd need some field to work it out. If you would have any suggestions, or something that you'd like to see, please let me know and I might work something out...

Mark said...

Is a jig the only way to attach an entity to the crosshair ?

Bert Vanpeteghem said...

Hi Mark,

As far as I know, yes that is the only way. There might be others, but this is a very practical and powerful approach so I'm not looking any further :).

You might want to ask this in the Autodesk discussion forums, where others could have a different view on this.

Do keep me posted if you learn more over there, please :)