Showing posts with label jigs. Show all posts
Showing posts with label jigs. Show all posts

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;
   3:  
   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);
   8:  
   9: // first append the block
  10: BlockTableRecord modelSpace = t.GetObject(
  11:     blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false) as BlockTableRecord;
  12:  
  13: modelSpace.AppendEntity(blockReference);
  14:  
  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);
   3:  
   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);
   3:  
   4: if (ed.Drag(dragJig).Status != PromptStatus.OK)
   5:     return;
   6:  
   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: {
   3:  
   4:     // only 2d
   5:     Point2d oldPosition = new Point2d(CurrentPosition.X, CurrentPosition.Y);
   6:     Point2d newPosition = new Point2d(lastMousePosition.X, lastMousePosition.Y);
   7:  
   8:     JiggedBlockReference.Rotation = oldPosition.GetVectorTo(newPosition).Angle - Math.PI/2;
   9:  
  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:     }
  18:         
  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

Jigging multiple entities with the DrawJig

Today I’m giving a simple example of how to use a Jig on multiple entities.

There are 2 kinds of jigs (as far as I know, maybe there are new types in the newer API’s):

  • EntityJig
  • DrawJig

The EntityJig only allows us to jig one entity at the time, so the type we need here is the DrawJig.

This example is very simple, and by no means exploits full potential of jigging, but it might be something to get you going.

We create a command called ccnSimpleJig (ccn for Cup of Code .Net). The point of this command is to select some polylines, and then use a Jig on them to achieve a similar affect to te MOVE command.

We start by creating the command:

   1: [CommandMethod("ccnSimpleJig")]
   2: public void SimpleGeometryJig()
   3: {
   4:     Document doc = Application.DocumentManager.MdiActiveDocument;
   5:     Editor ed = doc.Editor;
   6:  
   7:     using (Transaction t = doc.TransactionManager.StartTransaction())
   8:     {
   9: ...

All goes nicely in a transaction. I’m not using a nice Try Catch Finally pattern, because the point here isthe jig.


Next, we select some entities and filter out the Polylines:



   1: // select some polylines
   2: PromptSelectionOptions promptSelection = new PromptSelectionOptions();
   3: PromptSelectionResult result = ed.GetSelection(promptSelection);
   4:  
   5: if (result.Status != PromptStatus.OK)
   6:     return;
   7:  
   8: // Iterate results to find polylines (I know filters are smarter..)
   9: List<Polyline> polylines = new List<Polyline>();
  10:  
  11: foreach (ObjectId oid in result.Value.GetObjectIds())
  12: {
  13:     DBObject ent = t.GetObject(oid, OpenMode.ForWrite);
  14:  
  15:     Polyline p = ent as Polyline;
  16:  
  17:     if (p == null)
  18:         continue;
  19:  
  20:     polylines.Add(p);
  21:  
  22: }

Then we prompt for a base or reference point:



   1: // prompt refernce point
   2: PromptPointOptions promptPoint = new PromptPointOptions("select reference point");
   3: PromptPointResult promptPointResult = ed.GetPoint(promptPoint);
   4:  
   5: if (promptPointResult.Status != PromptStatus.OK)
   6:     return;


Now that we have all this, we can start the Jig, and don’t forget to commit the transaction.



   1: // Jig It.
   2: SimpleGeometryJig jig = new SimpleGeometryJig(polylines, promptPointResult.Value);
   3: PromptResult res = ed.Drag(jig);
   4:  
   5: // Commit transaction to commit the moves we did.
   6: t.Commit();

The Jig itself is a class inheriting from the AutoCAD DrawJig class.
When inheriting the DrawJig, you must override (CTRL+ALT+F10 is your friend) 2 Methods: Sampler and WorldDraw.
Sampler simply tells the Jig to sample the needed data, and check if anything needs a redraw.
In WorldDraw, you can then update the entities so that the changes detected in the Sampler method are shown on the screen.


But, first things first, our SimpleGeometryJig Class. In the constructor of this class, we take in a collection of Polylines and a reference point (wich we specified in the command):



   1: private IList<Polyline> polylines;
   2: private Point3d currentPosition;
   3: private Vector2d currentVector;
   4:  
   5: public SimpleGeometryJig(IList<Polyline> polylines, Point3d referencePoint)
   6: {
   7:     this.polylines = polylines;
   8:  
   9:     // use first point in polyline collection as reference point
  10:     currentPosition = referencePoint;
  11:  
  12:     // init current vector as 0,0,0
  13:     currentVector = new Vector2d(0, 0);
  14:     
  15: }


Notice that we also use a global Vector2d. This is for tracking the movements, and makes it easy to update the polylines.


So, now our Sample method. Here we are looking for the current mouse position, and we will remember the difference of the current position with the new position. We are also returning Sampler States matching the outcome of the current Prompt (NoChange, OK, Cancel)



   1: protected override SamplerStatus Sampler(JigPrompts prompts)
   2: {
   3:     JigPromptPointOptions jigOpt = new JigPromptPointOptions("select insertion point");
   4:     jigOpt.UserInputControls = UserInputControls.Accept3dCoordinates;
   5:  
   6:  
   7:     PromptPointResult res = prompts.AcquirePoint(jigOpt);
   8:  
   9:     if (res.Status != PromptStatus.OK)
  10:         return SamplerStatus.Cancel;
  11:  
  12:     // compare points
  13:     if (res.Value.IsEqualTo(currentPosition, new Tolerance(0.1, 0.1)))
  14:         return SamplerStatus.NoChange;
  15:  
  16:     // get vector to current position
  17:     Vector3d v3d = currentPosition.GetVectorTo(res.Value);
  18:     currentVector = new Vector2d(v3d.X, v3d.Y);
  19:         
  20:  
  21:     // reset current position
  22:     currentPosition = res.Value;
  23:     
  24:  
  25:     return SamplerStatus.OK;
  26: }


In the WorldDraw function, we can now edit the polylines with the calculated vector and draw these changes to the screen.



   1: protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
   2: {
   3:     try
   4:     {
   5:  
   6:         // add vector to all points of all polylines
   7:         foreach (var pl in polylines)
   8:         {
   9:             for (int i = 0; i < pl.NumberOfVertices; i++)
  10:             {
  11:                 // add vector to point
  12:                 pl.SetPointAt(i, pl.GetPoint2dAt(i).Add(currentVector));
  13:             }
  14:  
  15:             draw.Geometry.Draw(pl);
  16:  
  17:         }
  18:  
  19:         
  20:  
  21:         
  22:  
  23:     }
  24:     catch (System.Exception)
  25:     {
  26:         return false;
  27:     }
  28:  
  29:     return true;
  30: }

Voila, Jig is finished.
This is all the code we need, and we have a simple Jig that can move selected entities around.
For more useful and interesting jigs, you should take a look at Kean's site, filtered on the jig-category


Oh, and the code for this article can be found on my samples (first sample for now) page on Google Code. (More specifcally under simpledrawjig)

Posted by Bert Vanpeteghem 5 reacties