Author Topic: Recursive?  (Read 2744 times)

0 Members and 1 Guest are viewing this topic.

Bryco

  • Water Moccasin
  • Posts: 1883
Recursive?
« on: August 10, 2010, 05:34:37 PM »
I needed to list the level of nesting in a block and wrote something that seems to work ok, but is there a nice recursive way of doing this or a better way.
Code: [Select]
public static bool Nesting(string Blockname, out string sNested)
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            sNested = "";
            List<string> Nested=new List<string>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                if (!bt.Has(Blockname)) return false;
                Nested.Add(Blockname);
                for (int i = 0; i < Nested.Count; i++)
                {         
                    Blockname = Nested[i];
                    BlockTableRecord btr = tr.GetObject(bt[Blockname], OpenMode.ForRead) as BlockTableRecord;
                    foreach (ObjectId id in btr)
                    {
                        if (id.ObjectClass.DxfName == "INSERT")
                        {
                            BlockReference br = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
                            if (!Nested.Contains(br.Name))
                                Nested.Add(br.Name);
                        }
                    }
                }//next i

                tr.Commit();       
                Nested.Sort();
                for (int i = 0; i < Nested.Count; i++)
                    sNested+=Nested[i]+",";

                sNested = sNested.Remove(sNested.Length - 1);

            }
            return Nested.Count>0;

        } //end Nesting

kaefer

  • Guest
Re: Recursive?
« Reply #1 on: August 11, 2010, 07:27:43 AM »
I needed to list the level of nesting in a block and wrote something that seems to work ok, but is there a nice recursive way of doing this or a better way.

Hi Bryco, can't see no nesting in your code. You're iterating the blocks contained in bt.[blockname], just one level deep, right?

As for recursion, see enclosed /functional/ solution in dreaded F#. Not just recursion, but folding as well, to gather the list of processed block names.
That would be much easier with an imperative approach.

Code: [Select]
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

let Nesting blockname =
    let doc = acApp.DocumentManager.MdiActiveDocument
    let db = doc.Database
   
    use tr = db.TransactionManager.StartTransaction()
    let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
   
    let rec nest' (blockname': string) =
        if bt.Has blockname' then
            (tr.GetObject(bt.[blockname'], OpenMode.ForRead)
                :?> BlockTableRecord )
            |> Seq.cast<_>
            |> Seq.choose
                (fun oid ->
                    // Filter for "INSERT", returning string option
                    match tr.GetObject(oid, OpenMode.ForRead) with
                    | :? BlockReference as br -> Some br.Name
                    | _ -> None )
            |> Set.ofSeq    // distinct
            |> Set.fold
                (fun (s: Set<_>) n ->
                    // Recurse if yet unhandled blockname encountered
                    if s.Contains n then s else nest' n |> Set.union s)
                (Set.singleton blockname')
        else Set.empty

    let res =
        nest' blockname
        |> Seq.fold (fun s t -> s + "," + t) ""
        |> fun str -> if str.Length > 0 then str.[1..] else ""
    tr.Commit()
    res
   
[<Autodesk.AutoCAD.Runtime.CommandMethod "test">]
let test() =
    let doc = acApp.DocumentManager.MdiActiveDocument
    let ed = doc.Editor
    let psr = ed.GetString "\nEnter block name: "
    match psr.Status with
    | PromptStatus.OK ->
        ed.WriteMessage("\n{0} ", psr.StringResult |> Nesting)
    | _ -> ()

Cheers, Thorsten.

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Recursive?
« Reply #2 on: August 11, 2010, 09:39:41 AM »
Thanks Thorsten.
I'll have to have at least 2 cups of coffee to try and figure out the F#.
I haven't heard of folding as well.
My code does get all the nested blocks as it dynamically adds to the list and so blockname  is new when a nesting occurs.
I see both methods use one transaction which is good.

kaefer

  • Guest
Re: Recursive?
« Reply #3 on: August 11, 2010, 11:36:23 AM »
I'll have to have at least 2 cups of coffee to try and figure out the F#.
I haven't heard of folding as well.

You speak Linq? Think of it as IEnumerable.Aggregate...

My code does get all the nested blocks as it dynamically adds to the list and so blockname  is new when a nesting occurs.

Ah, I see the light now. Changing a collection while iterating over it has always been anathema to me,  but in this instance it seems to be quite safe. You're only appending to the end of the list and Nested.Count is evaluated anew on each iteration. What's the real gain you could have if you replace this loop with class member recursion?

Cheers, Thorsten.