August 2014

Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            








« Blinking Lights and Other Revelations | Main | Filtering lists of AutoCAD entities using LINQ »

January 28, 2013

Performing Boolean operations on AutoCAD solids using .NET

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();

      }

    }

  }

}.

blog comments powered by Disqus

Feed/Share

10 Random Posts