Here’s an interesting question that came in from Nick Gilbert via a blog comment:
Is there a simple way to get the geometric extents of the group?
As discussed in this previous post, the Group object in AutoCAD presents itself as a collection of geometric objects (or entities, in ObjectARX-parlance). But a Group, in itself, isn’t a geometric object: it’s an aggregator of objects that are.
So there isn’t – as Nick is clearly aware – a simple GeometricExtents property of the Group object. But we can access the contents of the Group and combine their various GeometricExtents, returning an overall Extents3d for the group.
There’s a few ways I could have done this… I ended up implementing an extension method on the Transaction class to get the extents of an array of ObjectIds. This seemed the most likely to be reusable for other situations. Then we just call the extension method with the selected Group’s contents and report the results.
Here’s the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Collections.Generic;
namespace GroupExtents
{
public static class TransactionExtensions
{
// A simple extension method that aggregates the extents of any entities
// passed in (via their ObjectIds)
public static Extents3d GetExtents(this Transaction tr, ObjectId[] ids)
{
var ext = new Extents3d();
foreach (var id in ids)
{
var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
if (ent != null)
{
ext.AddExtents(ent.GeometricExtents);
}
}
return ext;
}
}
public class Commands
{
[CommandMethod("GE")]
public void GroupExtents()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
using (var tr = db.TransactionManager.StartTransaction())
{
// Get the group dictionary from the drawing
var gd =
(DBDictionary)tr.GetObject(db.GroupDictionaryId, OpenMode.ForRead);
if (gd.Count == 0)
{
ed.WriteMessage("\nNo groups found in drawing.");
}
else
{
// List the groups in the drawing with an index
var groupNames = new List<string>(gd.Count);
ed.WriteMessage("\nGroups:");
int i = 0;
foreach (var entry in gd)
{
i++;
ed.WriteMessage("\n{0}. {1}", i, entry.Key);
groupNames.Add(entry.Key);
}
// Ask the user to select a group number
var pio = new PromptIntegerOptions("\nEnter group index");
pio.AllowNegative = false;
pio.AllowZero = false;
pio.DefaultValue = 1;
pio.LowerLimit = 1;
pio.UpperLimit = i;
var pir = ed.GetInteger(pio);
if (pir.Status == PromptStatus.OK)
{
// Get the selected group
var grp =
tr.GetObject(
(ObjectId)gd[groupNames[pir.Value-1]], OpenMode.ForRead
) as Group;
if (grp != null)
{
// Call our extension method to get the extents of the group's
// referenced objects
var ext = tr.GetExtents(grp.GetAllEntityIds());
// Print the information for the user
ed.WriteMessage(
"\nGroup's extents are from {0} to {1}.",
ext.MinPoint, ext.MaxPoint
);
}
}
}
// Commit the transaction
tr.Commit();
}
}
}
}
I tested it with a fairly large 3D drawing (this contains 6,635 spheres) and there was no perceived delay for the calculation.
Here’s what was reported at the command-line:
Command: GE
Groups:
1. *A1
Enter group index <1>: 1
Group's extents are from (-0.997431989660447,-0.997431989660447,-0.997431989660447) to (0.997431989660447,0.997431989660447,0.997431989660447).
Which for this model is correct (to save people the effort of hand-verifying the results ;-).