I looked back and couldn’t find a post covering this particular topic and so decided to put something together. It may well have been covered elsewhere (I admit to not having looked) but I felt like throwing some code together, either way. :-)
To perform a Boolean operation between Solid3d objects inside AutoCAD, you can use Solid3d.BooleanOperation() on the primary Solid3d, passing in the secondary one.
We want to implement commands for Unite (or Union), Intersect (Intersection) and Subtract (Subtraction). Only the last of these needs us to select a primary object explicitly – as the other two operations are associative – but we’ll go ahead and implement a generic function that takes a separate primary object as an argument. In the case of Unite and Intersect, we’ll simply take the first element of the selected solids and pass that in as the primary object (being sure to remove it from the “secondary” list we pass in).
That’s really all there is to it. Here’s the C# code that defined USOLS, ISOLS and SSOLS command (for union, intersection and subtraction respectively).
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Linq;
namespace BooleanSolids
{
public class Commands
{
[CommandMethod("USOLS")]
static public void UniteSolids()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var psr =
SelectSolids(
doc.Editor,
"\nSelect solid objects to unite"
);
if (psr.Status != PromptStatus.OK)
return;
if (psr.Value.Count > 1)
{
BooleanSolids(
doc, psr.Value[0].ObjectId, AllButFirst(psr),
BooleanOperationType.BoolUnite
);
}
}
[CommandMethod("ISOLS")]
static public void IntersectSolids()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var psr =
SelectSolids(
doc.Editor,
"\nSelect solid objects to intersect"
);
if (psr.Status != PromptStatus.OK)
return;
if (psr.Value.Count > 1)
{
BooleanSolids(
doc, psr.Value[0].ObjectId, AllButFirst(psr),
BooleanOperationType.BoolIntersect
);
}
}
[CommandMethod("SSOLS")]
static public void SubtractSolids()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var first = SelectSingleSolid(ed, "\nSelect primary solid");
if (first == ObjectId.Null)
return;
var psr = SelectSolids(ed, "\nSelect solids to subtract");
if (psr.Status != PromptStatus.OK)
return;
if (psr.Value.Count > 0)
{
BooleanSolids(
doc, first, psr.Value.GetObjectIds(),
BooleanOperationType.BoolSubtract
);
}
}
private static ObjectId SelectSingleSolid(
Editor ed, string prompt
)
{
var peo = new PromptEntityOptions(prompt);
peo.SetRejectMessage("\nMust be a 3D solid");
peo.AddAllowedClass(typeof(Solid3d), false);
var per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return ObjectId.Null;
return per.ObjectId;
}
private static ObjectId[] AllButFirst(PromptSelectionResult psr)
{
// Use LINQ to skip the first item in the IEnumerable
// and then return the results as an ObjectId array
return
psr.Value.Cast<SelectedObject>().Skip(1).
Select(o => { return o.ObjectId; }).ToArray();
}
private static PromptSelectionResult SelectSolids(
Editor ed, string prompt
)
{
// Set up our selection to only select 3D solids
var pso = new PromptSelectionOptions();
pso.MessageForAdding = prompt;
var sf =
new SelectionFilter(
new TypedValue[]
{
new TypedValue((int)DxfCode.Start, "3DSOLID")
}
);
return ed.GetSelection(pso, sf);
}
private static void BooleanSolids(
Document doc, ObjectId first, ObjectId[] others,
BooleanOperationType op
)
{
var tr = doc.TransactionManager.StartTransaction();
using (tr)
{
var sol =
tr.GetObject(first, OpenMode.ForWrite) as Solid3d;
if (sol != null)
{
foreach (ObjectId id in others)
{
var sol2 =
tr.GetObject(id, OpenMode.ForWrite) as Solid3d;
if (sol2 != null)
{
sol.BooleanOperation(op, sol2);
}
}
}
tr.Commit();
}
}
}
}.