September 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        










« More fun with F# and AutoCAD: string extraction and manipulation | Main | Metaprogramming with AutoCAD - Part 1 »

November 16, 2007

Getting the total volume of 3D solids in an AutoCAD model using F#

In one of my sessions at this year's AU, "There's More to .DWG Than AutoCAD®", I'll be showing some VB.NET code that goes through and collects information about solids, presenting it in a dialog along with the sum of the various volumes. You can get the code and the results from Part 1 of the session's handout.

Just for fun, I thought I'd write some F# code to add the volumes of the 3D solid objects in the modelspace of the current drawing. I adopt a similar approach to the VB code - not caring about intersecting volumes, for instance - but obviously the code looks quite different.

I won't step through the code line-by-line, as the last post introduced the fundamental concepts that also apply here.

// Use lightweight F# syntax


#light


(* Declare a specific namespace

  and module name

*)


module MyNamespace.MyApplication


// Import managed assemblies


#I @"C:\Program Files\Autodesk\AutoCAD 2008"


#r "acdbmgd.dll"

#r "acmgd.dll"


open System

open System.Collections.Generic

open Autodesk.AutoCAD.Runtime

open Autodesk.AutoCAD.ApplicationServices

open Autodesk.AutoCAD.DatabaseServices


// Now we declare our command


[<CommandMethod("volume")>]

let listWords () =


  // Let's get the usual helpful AutoCAD objects


  let doc =

    Application.DocumentManager.MdiActiveDocument;

  let ed = doc.Editor;

  let db = doc.Database;


  // "use" has the same effect as "using" in C#


  use tr =

    db.TransactionManager.StartTransaction();


  // Get appropriately-typed BlockTable and BTRs


  let bt =

    tr.GetObject

      (db.BlockTableId,OpenMode.ForRead)

    :?> BlockTable

  let ms =

    tr.GetObject

      (bt.[BlockTableRecord.ModelSpace],

      OpenMode.ForRead)

    :?> BlockTableRecord


  // A function that accepts an ObjectId and returns

  // the volume of a 3D solid, if it happens to be one


  // Note the valid use of tr, as it is in scope


  let getVolume (x : ObjectId) =

    let obj = tr.GetObject(x,OpenMode.ForRead);

    match obj with

    | :? Solid3d -> (obj :?> Solid3d).MassProperties.Volume

    | _ -> 0.0


  // Use fold_left in a partial application to find

  // the sum of the contents of a list


  let sum =

    List.fold_left (fun x y -> x+y) 0.0


  // And here's where we plug everything together...


  let vol =

    Seq.untyped_to_list ms |> List.map getVolume |> sum


  ed.WriteMessage("\nTotal volume: " + vol.ToString());


  // As usual, committing is cheaper than aborting


  tr.Commit()

The only tricky thing is the use of fold_left to apply an anonymous (or lambda, for the LISPers out there) addition function across the contents of the list containing the individual volumes of the objects in the modelspace.

Here's what we see when we run the "volume" command:

Command: volume

Total volume: 15275.8711619534

This is the same result as displayed by the previous example (although presented with a few more decimal places).

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200e54f9861108834

Listed below are links to weblogs that reference Getting the total volume of 3D solids in an AutoCAD model using F#:

» Getting the total volume of 3D solids in an Autocad model using F# from CadKicks.com
You've been kicked (a good thing) - Trackback from CadKicks.com [Read More]

blog comments powered by Disqus

Feed/Share

10 Random Posts