July 06, 2007

Applying a gradient fill to an AutoCAD hatch using .NET

So, back in the saddle after an eventful week off, back in the UK. Aside from the extremely changeable weather (even by British standards) and the heightened security at UK airports, the week went swimmingly... :-)

It's now Friday night, and disappointingly I've spent nearly two days regaining control of my inbox. I really wanted to make a quick post before the weekend, so rather than diving into the issue I'd planned on tackling (Palettes), I decided to take a shot at a request I'd received by email a few weeks ago: to show how to create a gradient fill using .NET.

I started by reusing the code from this previous post: so much of the code I needed was there already, it had to be easy to adjust the hatch to use a gradient fill, right? Well, no - it took me much longer than I'd expected to work this one out. Maybe I should have stuck with Palettes, after all...

I decided to use a spherical gradient fill of two colours (the default colours used when you create a two-tone gradient fill using the UI), as this shows one of the trickier parts of the API, that of specifying the colours themselves. One other call it took me a while to work out was to set the HatchObjectType property - if you don't do that then you'll get an eAmbiguousOutput exception.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Colors;

namespace HatchGradient

{

publicclassCommands

{

[CommandMethod("GFH")]

staticpublicvoid GradientFillHatch()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Editor ed = doc.Editor;

// Ask the user to select a hatch boundary

PromptEntityOptions opt =

newPromptEntityOptions(

"\nSelect boundary: "

);

opt.SetRejectMessage("\nObject must be a curve.");

opt.AddAllowedClass(typeof(Curve), false);

PromptEntityResult res =

ed.GetEntity(opt);

if (res.Status == PromptStatus.OK)

{

Transaction tr =

doc.TransactionManager.StartTransaction();

using (tr)

{

// Check the entity is a closed curve

DBObject obj =

tr.GetObject(

res.ObjectId,

OpenMode.ForRead

);

Curve cur = obj asCurve;

if (cur != null && cur.Closed == false)

{

ed.WriteMessage("\nLoop must be a closed curve.");

}

else

{

// We'll add the hatch to the model space

BlockTable bt =

(BlockTable)tr.GetObject(

doc.Database.BlockTableId,

OpenMode.ForRead

);

BlockTableRecord btr =

(BlockTableRecord)tr.GetObject(

bt[BlockTableRecord.ModelSpace],

OpenMode.ForWrite

);

Hatch hat = newHatch();

hat.SetDatabaseDefaults();

// Firstly make it clear we want a gradient fill

hat.HatchObjectType =

HatchObjectType.GradientObject;

// Let's use the pre-defined spherical gradient

hat.SetGradient(

GradientPatternType.PreDefinedGradient,

"SPHERICAL");

// We're defining two colours

hat.GradientOneColorMode = false;

GradientColor[] gcs = newGradientColor[2];

gcs[0] =

newGradientColor(

Color.FromRgb(0, 0, 255),

0 // First colour must have value of 0

);

gcs[1] =

newGradientColor(

Color.FromRgb(255, 255, 153),

1 // Second colour must have value of 1

);

hat.SetGradientColors(gcs);

// Add the hatch to the model space

// and the transaction

ObjectId hatId = btr.AppendEntity(hat);

tr.AddNewlyCreatedDBObject(hat, true);

// Add the hatch loop and complete the hatch

ObjectIdCollection ids =

newObjectIdCollection();

ids.Add(res.ObjectId);

hat.Associative = true;

hat.AppendLoop(

HatchLoopTypes.Default,

ids

);

hat.EvaluateHatch(true);

tr.Commit();

}

}

}

}

}

}

Here's what you get when you run the GFH command and select a polyline boundary you've created previously: