Screencast on fluent interfaces

Ever since I’ve used Fluent NHibernate I’ve become a big fan of Fluent interfaces. There is something very sexy, but more important, literally ‘fluent’ about using them.

Within possibilities I have been trying to implement the technique in my own coding & frameworks. While doing that, I found that it is really important to have a clear strategy, before starting to create all types of methods returning the ‘this’ object.

For example, when creating wrapper classes for selections in AutoCad, the Fluent styles seem very appropriate. (Note to self: blogpost ;).

Anyway, there is a great screencast up on Dimecasts about creating Fluent Interfaces. The screencast is not very extensive, but gives a nice overview and strategy on creating them.

Posted by Bert Vanpeteghem 0 reacties

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

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;
   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);
   5: if (result.Status != PromptStatus.OK)
   6:     return;
   8: // Iterate results to find polylines (I know filters are smarter..)
   9: List<Polyline> polylines = new List<Polyline>();
  11: foreach (ObjectId oid in result.Value.GetObjectIds())
  12: {
  13:     DBObject ent = t.GetObject(oid, OpenMode.ForWrite);
  15:     Polyline p = ent as Polyline;
  17:     if (p == null)
  18:         continue;
  20:     polylines.Add(p);
  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);
   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);
   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;
   5: public SimpleGeometryJig(IList<Polyline> polylines, Point3d referencePoint)
   6: {
   7:     this.polylines = polylines;
   9:     // use first point in polyline collection as reference point
  10:     currentPosition = referencePoint;
  12:     // init current vector as 0,0,0
  13:     currentVector = new Vector2d(0, 0);
  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;
   7:     PromptPointResult res = prompts.AcquirePoint(jigOpt);
   9:     if (res.Status != PromptStatus.OK)
  10:         return SamplerStatus.Cancel;
  12:     // compare points
  13:     if (res.Value.IsEqualTo(currentPosition, new Tolerance(0.1, 0.1)))
  14:         return SamplerStatus.NoChange;
  16:     // get vector to current position
  17:     Vector3d v3d = currentPosition.GetVectorTo(res.Value);
  18:     currentVector = new Vector2d(v3d.X, v3d.Y);
  21:     // reset current position
  22:     currentPosition = res.Value;
  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:     {
   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:             }
  15:             draw.Geometry.Draw(pl);
  17:         }
  23:     }
  24:     catch (System.Exception)
  25:     {
  26:         return false;
  27:     }
  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

New test with Live Writer and Code snippet plugin

   1: public Document OpenDocument(string filePath, FileAccess access, bool outsideSession)
   2: {
   3:     return = Application.DocumentManager.Open(filePath, access == FileAccess.Read);    return document;
   4: }

This is a test with Live Writer and a Code Snippet plugin.

Updated: There seems to be an extra <br/> bug in this plugin,  but it can be fixed by using HTML in stead of XHTML as Markup Style.

Much better :)

Posted by Bert Vanpeteghem 0 reacties

Test on code formatting

I really want code formatting to work on this blog. Until I move it to a better system, that is :)

So a first test:

public class CupOCadNetBlog
public bool CanDoCodeFormattingProperly()
return true; // hopefully??? :)

Posted by Bert Vanpeteghem 0 reacties

Editing block properties performance issue

When working with dynamic blocks, I can imagine that the functionality most used are
- Block Properties
- Block Attributes
- Maybe some Extension Dictionary editing.

At least, that is what we worked with most in our last project. It was pretty much based on positioning and editing Dynamic Blocks.
At the time, we had noticed some performance issues when we were inserting or editing a lot of blocks. This actually became annoying when we were doing operations that changed 40 or more blocks.

At first, we thought that the problem was in our calculation and processing. We had a pretty intense Processing engine for the blocks and our reaction was that we were processing things too much.

When we started investigating what caused the performance lag, we actually found that our processing was quite fast, but that the problem was editing a lot of Blocks. So, the problem was not our code; the timely operation was, waiting for AutoCAD operations to complete.

So we isolated the functionality of accessing and editing blocks to see what exactly went wrong.

We tried:
- using less transactions (all can be done in one single transaction), no luck.
- rewriting our code, so there would be less loops, no luck.

As we investigated a little further, with timers on each operation we did, we finally found out that it were actually the block properties that were the slowness factor...

The results were quite remarkable, as a reference:

Inserting 100 blocks with 4 attributes and 4 properties takes us: 1000ms, so 1 second.

In this second we have:

Code overhead: 62ms
Inserting block: 32ms
Set attributes: 47ms
Set properties: 859ms

This means that setting the properties takes more than 85% of complete operation time.

Now, you can say that, since this all still happens in one second, that there isn't a big performance issue. However, our blocks easily had 8-10 properties. So spending 85% of your time in updating properties is in fact a lot.

Next time, we'll look in how to get around this issue.

Posted by Bert Vanpeteghem 3 reacties