Author Topic: "Wblock Layers", saving the contents of each layer to a separate file  (Read 11408 times)

0 Members and 1 Guest are viewing this topic.

kaefer

  • Guest
Hi All,

this is the continuation of http://www.theswamp.org/index.php?topic=31858.msg405029#msg405029, with many thanks to fixo.

I tried to reduce his function to the bare minmum, that is:
Get the position of a template file (requires a reference to Autodesk.AutoCAD.Interop)
Collect the relevant layers
For each layer, select all ModelSpace objects
Create a new empty database and read the template file into it
WblockClone the selected objects into the new database
Saveas the database and dispose it implicitly; no need for an open transaction in the last four steps

Am I missing anything?

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

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

[<CommandMethod "WBL">]
let copyObjectsOnLayers() =
    // Get the current document and database
    let doc = acApp.DocumentManager.MdiActiveDocument
    let ed = doc.Editor
    let db = doc.Database

    // Get the path to an appropriate template file
    let prefs = acApp.Preferences :?> Autodesk.AutoCAD.Interop.AcadPreferences
    let sTemplatePath =
        System.IO.Path.Combine(prefs.Files.TemplateDwgPath, "acadiso.dwt")

    // Get the current document's path and name without extension
    let currRoot = acApp.GetSystemVariable "DWGPREFIX" :?> string
    let currName =
        acApp.GetSystemVariable "DWGNAME" :?> string
        |> System.IO.Path.GetFileNameWithoutExtension

    let lrcoll = new System.Collections.Generic.List<string>()
       
    // Start a transaction
    use tr = db.TransactionManager.StartTransaction()

    // Collect all unlocked and not xref-dependent layers
    let lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) :?> LayerTable
    for lrid in lt do
        let ltr = tr.GetObject(lrid, OpenMode.ForRead, false) :?> LayerTableRecord
        if not ltr.IsLocked && not(ltr.Name.Contains "|") then
            lrcoll.Add ltr.Name |> ignore

    tr.Commit()

    for lrname in lrcoll do

        let res =
            new SelectionFilter[|
                 new TypedValue(int DxfCode.LayerName, lrname)
                 new TypedValue(int DxfCode.LayoutName, "Model") |]
            |> acApp.DocumentManager.MdiActiveDocument.Editor.SelectAll
       
        if res.Status = PromptStatus.OK && res.Value.Count > 0 then
            let objcoll = new ObjectIdCollection(res.Value.GetObjectIds())
       
            let strFilename =   //<-- build filename as you need here
                System.IO.Path.Combine(
                    currRoot, currName + @"_" + lrname + @".dwg" )

            ed.WriteMessage("\n" + strFilename)

            // Create a new database to copy the objects to
            use newdb = new Database(false, true)

            // Read the template file into it
            newdb.ReadDwgFile(sTemplatePath, System.IO.FileShare.Read, true, "")
   
            // Get the ObjectId of the new ModelSpace BlockTableRecord
            let newbtrId = SymbolUtilityServices.GetBlockModelSpaceId newdb

            // Clone the objects to the new database
            let idmap = new IdMapping()
            db.WblockCloneObjects(
                objcoll, newbtrId, idmap, DuplicateRecordCloning.Ignore, false)

            newdb.SaveAs(strFilename, DwgVersion.Current)

All the best, Thorsten

Jeff H

  • Needs a day job
  • Posts: 6144
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #1 on: October 15, 2010, 08:56:16 AM »
Is that your code posted at Through The Interface

or is there another Thorsten out there who likes F#?

 


kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #2 on: October 15, 2010, 09:15:39 AM »
Is that your code posted at Through The Interface

or is there another Thorsten out there who likes F#?

Hi Jeff,

see if you discover any similarities:
Code: [Select]
    // Late binding Interop workaround, casts obj to binding target
    let (?) (o: obj) prop : 'T  =
        let bf = System.Reflection.BindingFlags.GetProperty
        o.GetType().InvokeMember(prop, bf, null, o, null) :?> 'T

    // Get the path to an appropriate template file
    let sTemplatePath =
        System.IO.Path.Combine(
            acApp.Preferences?Files?TemplateDwgPath, "acadiso.dwt" )

That should help against the Interop reference above, but at the price of making it much more difficult porting it back to C#.

With best wishes, Thorsten

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #3 on: October 15, 2010, 10:14:45 AM »

System.IO.Path.Combine( acApp.Preferences?Files?TemplateDwgPath, "acadiso.dwt" )

? in place of \\    :|

Is that a typo ??
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #4 on: October 15, 2010, 10:56:48 AM »

System.IO.Path.Combine( acApp.Preferences?Files?TemplateDwgPath, "acadiso.dwt" )

? in place of \\    :|

Is that a typo ??

Hi Kerry,

nope. Read ? in place of .

The ?-operator is an underdocumented feature of the latest F#-compiler. Its main use is endorsed by the gurus at MS research as a replacement for the FrameworkElement.FindName method in WPF. That's why I thought I could borrow this for my little late binding exercise. The orig was:
Code: [Select]
   // Get the path to an appropriate template file
    let prefs = acApp.Preferences :?> Autodesk.AutoCAD.Interop.AcadPreferences
    let sTemplatePath =
        System.IO.Path.Combine(prefs.Files.TemplateDwgPath, "acadiso.dwt")

Regards, Thorsten

« Last Edit: October 15, 2010, 11:01:13 AM by kaefer »

Jeff H

  • Needs a day job
  • Posts: 6144
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #5 on: October 17, 2010, 10:09:09 AM »
Hi Jeff,
see if you discover any similarities:

Sorry Thorsten I do not understand the question


I tried to reduce his function to the bare minmum, that is:

Here is another idea I hope this helps

This is Fixo's code that obtains the entities ObjectId a different way.

1. It uses a dictionary and does one loop through model space adding each entity to the dictionary

2. Tries to create new drawing for each layer from the template "Fart.dwt" ---- Did this so it would fail and use default template

3. Save in same folder as layer Name

Not sure if this will help reduce the function a little more or is not efficient enough.

Here is the Code

************Edited************
Added a couple of comments in the code
************Edited************

Code: [Select]
using System;
using System.Collections;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;


[assembly: CommandClass(typeof(WblockLayers.MyCommands))]

namespace WblockLayers
{   
    public class MyCommands
    {       


        // Dictionary to Store the Layer Name and the Entites that are on the Layer
        Dictionary<string, ObjectIdCollection> entFileDict = new Dictionary<string, ObjectIdCollection>();
           
 
        [CommandMethod("WblockLayers")]
        public void WblockLayers()
        {


            // Get the folder that the current drawing is in
            string dwgDialog = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGPREFIX") as string;

            Document doc = Application.DocumentManager.MdiActiveDocument;
            DocumentCollection docMgr = Application.DocumentManager;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                BlockTableRecord btrMs = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;               
                ObjectIdCollection entIds = null;



                // For each entity in Model Space it checks if the Dictiony contains the layer name
                // If it does it adds the Entities Object Id to the value
                //If not it creates a new entry
                foreach (ObjectId entID in btrMs)
                {
                    Entity ent = entID.GetObject(OpenMode.ForRead) as Entity;
                    string lyrName = ent.Layer;                   
                    if (entFileDict.TryGetValue(lyrName, out entIds))
                    {
                        entIds.Add(entID);
                    }
                    else
                    {
                        ObjectIdCollection entObjIds = new ObjectIdCollection();
                        entObjIds.Add(entID);
                        entFileDict.Add(lyrName, entObjIds);
                    }
                }



                // Loop through the dictionary using the key values which are the layer names
                // Create new drawing add the entites on that layer
                // Save drawing in current drawing folder as the layer name and close drawing
                foreach (string lyrName in entFileDict.Keys)
                {
                    using (Document newDoc = docMgr.Add("Fart.dwt"))
                    {
                        using (DocumentLock newLoc = newDoc.LockDocument())
                        {
                            using (Transaction newTrx = newDoc.Database.TransactionManager.StartTransaction())
                            {
                                BlockTable newBt = newDoc.Database.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                                BlockTableRecord newBtrMs = newBt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;
                                IdMapping map = new IdMapping();
                                ObjectIdCollection newEntIds = null;
                                if (entFileDict.TryGetValue(lyrName, out newEntIds))
                                {
                                    db.WblockCloneObjects(newEntIds, newBtrMs.Id, map, DuplicateRecordCloning.Replace, false);
                                }
                                else
                                {
                                    continue;
                                }
                                newTrx.Commit();
                                newDoc.Database.SaveAs(dwgDialog +  lyrName + ".dwg", DwgVersion.Current);
                            }                           
                        }
                        newDoc.CloseAndDiscard();
                    }                   
                }
                trx.Commit();
            }
        }
    }

}

 
     
   
Thanks Fixo for the cool idea and code.
Thanks Thorsten for the F# code.



« Last Edit: October 17, 2010, 10:22:04 AM by Jeff H »

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #6 on: October 18, 2010, 02:56:30 AM »
Hi Jeff,
see if you discover any similarities:

Sorry Thorsten I do not understand the question

That was a reference to the ?-operator in F#, which allows unquoted string literals. Let's change the note now.

Quote
1. It uses a dictionary and does one loop through model space adding each entity to the dictionary

This idea is pretty snappy. I'll borrow it, may I?

Quote
2. Tries to create new drawing for each layer from the template "Fart.dwt" ---- Did this so it would fail and use default template
This is cool and useful behaviour, since the fallback default seems to be either the last one used or it's based on the current drawing; it's not coming from QNEW settings, those are empty here.

Quote
Not sure if this will help reduce the function a little more or is not efficient enough.
Reduction: check. Efficiency: not sure, for large numbers of files the document manager is really slow.

Maybe it's the way to go if you want to run your code in the Session context.

Backport to C#, incorporates your dict, but takes the template from Preferences:
Code: [Select]
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;

using acApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace WblockLayers
{
    public class MyCommands
    {
        [CommandMethod("WblockLayersC")]
        public static void WblockLayers()
        {
            Database db = acApp.DocumentManager.MdiActiveDocument.Database;
            Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;

            // Dictionary to store the Layer Name and the Entites that are on the Layer
            Dictionary<string, ObjectIdCollection> entFileDict = new Dictionary<string, ObjectIdCollection>();

            // Get the folder that the current drawing is in
            string dwgDialog = acApp.GetSystemVariable("DWGPREFIX") as string;

            // Get the template folder from the preferences
            string sTemplatePath = get(get(acApp.Preferences, "Files"), "TemplateDwgPath") as string;
            string sTemplateFile = sTemplatePath + @"\acadiso.dwt";
           
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                BlockTableRecord btrMs =
                    bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;
               
                // For each entity in Model Space it checks if the Dictiony contains the layer name
                // If it does it adds the Entities Object Id to the value
                //If not it creates a new entry
                foreach (ObjectId entID in btrMs)
                {
                    Entity ent = entID.GetObject(OpenMode.ForRead) as Entity;
                    string lyrName = ent.Layer;
                    if (!entFileDict.ContainsKey(lyrName))
                        entFileDict.Add(lyrName, new ObjectIdCollection());
                    entFileDict[lyrName].Add(entID);
                }
                tr.Commit();
            }
            // Loop through the dictionary using the key values which are the layer names
            // Create new drawing add the entites on that layer
            // Save drawing in current drawing folder as the layer name and close drawing
            foreach (KeyValuePair<string,ObjectIdCollection>entry in entFileDict)
            {
                using (Database newDb = new Database(false, true))
                {
                    newDb.ReadDwgFile(sTemplateFile, System.IO.FileShare.Read, true, "");
                    IdMapping map = new IdMapping();
                    db.WblockCloneObjects(
                        entry.Value,
                        SymbolUtilityServices.GetBlockModelSpaceId(newDb),
                        map, DuplicateRecordCloning.Replace, false);
                    newDb.SaveAs(dwgDialog + entry.Key + ".dwg", DwgVersion.Current);
                }
            }
        }
        static Object get(Object o, string prop)
        {
            return o.GetType().InvokeMember(prop, System.Reflection.BindingFlags.GetProperty, null, o, null);
        }
    }
}
Cheers, Thorsten

Jeff H

  • Needs a day job
  • Posts: 6144
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #7 on: October 18, 2010, 01:11:44 PM »
Quote
This idea is pretty snappy. I'll borrow it, may I?

Gladly I know I have picked up alot ideas from your post, wish I could I return the favour more often.


I like the way you did your code in the previous post. It is alot easier to read then mine.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #8 on: October 18, 2010, 06:17:04 PM »

System.IO.Path.Combine( acApp.Preferences?Files?TemplateDwgPath, "acadiso.dwt" )

? in place of \\    :|

Is that a typo ??

Hi Kerry,

nope. Read ? in place of .

The ?-operator is an underdocumented feature of the latest F#-compiler. Its main use is endorsed by the gurus at MS research as a replacement for the FrameworkElement.FindName method in WPF. That's why I thought I could borrow this for my little late binding exercise. The orig was:
Code: [Select]
   // Get the path to an appropriate template file
    let prefs = acApp.Preferences :?> Autodesk.AutoCAD.Interop.AcadPreferences
    let sTemplatePath =
        System.IO.Path.Combine(prefs.Files.TemplateDwgPath, "acadiso.dwt")

Regards, Thorsten



Thanks.
I'd planned on working through "Expert F# 2.0" (Styme et al) but decided I don't have the time or energy.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #9 on: October 19, 2010, 05:45:35 AM »
This makes a huge difference from my earlier post by changing the last foreach loop.

Setting the the first argument to true in the Database constructor
From docs
Quote
specifying whether or not to build an empty object

Code: [Select]
foreach (KeyValuePair<string, ObjectIdCollection> entry in entFileDict)
                {
                    using (Database newDb = new Database(true, false))
                    using (Transaction newTrx = newDb.TransactionManager.StartTransaction())
                    {       
                        BlockTable newBt = newDb.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                        BlockTableRecord newBtrMs = newBt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;
                        IdMapping map = new IdMapping();                       
                        db.WblockCloneObjects(entry.Value, newBtrMs.Id, map, DuplicateRecordCloning.Replace, false);                       
                        newTrx.Commit();
                        newDb.SaveAs(dwgDialog + entry.Key + ".dwg", DwgVersion.Current);
                        //newDb.CloseInput(true);
                    }
                }             

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #10 on: October 19, 2010, 06:03:53 AM »
This makes a huge difference from my earlier post by changing the last foreach loop.
Thanks for your patience with this one.

Quote
Setting the the first argument to true in the Database constructor
From docs
Quote
specifying whether or not to build an empty object

BTDT. That's where the imperial units came from. To use the Database.ReadDwgFile method, it has to be set to false.
Quote
...memory leaks, or worse, will result.

Sincerely, Thorsten


Glenn R

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #11 on: October 19, 2010, 05:24:40 PM »
A slightly different approach for the Dictionary and it's population. It's a pity that the SymbolTables don't implement standard/generic collections or their interfaces.

Code: [Select]
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    LayerTable lt = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForRead);
    IEnumerable<ObjectId> layerIds = lt.Cast<ObjectId>();

    // get the count for collection initialisation
    int layerCount = layerIds.Count();

    // init our collection to predefined size to avoid overhead
    // of resizing. Also, we use ObjectId as the key for easy comparison/lookup
    Dictionary<ObjectId, ObjectIdCollection> layerMap = new Dictionary<ObjectId, ObjectIdCollection>(layerCount);

    // construct collection for easy access. We know layers are unique, so their
    // objectid's will be, which is perfect for keys
    layerIds.ForEach(id => layerMap.Add(id, new ObjectIdCollection()));

    // grab MS
    BlockTable bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
    BlockTableRecord msBtr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead);

    // loop it
    msBtr.Cast<ObjectId>().ForEach(entId =>
        {
            Entity msEnt = (Entity)entId.GetObject(OpenMode.ForRead);
            layerMap[msEnt.LayerId].Add(entId);
        }
    );

    tr.Commit();
}

Jeff H

  • Needs a day job
  • Posts: 6144
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #12 on: October 19, 2010, 05:57:24 PM »
Nice.
Thank you Glenn R very much for posting that.
It is nice to see how the pro's do it.

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #13 on: October 21, 2010, 03:36:58 AM »
A slightly different approach for the Dictionary and it's population. It's a pity that the SymbolTables don't implement standard/generic collections or their interfaces.

Hi Glenn!

Wow, that's as functional as it gets.

Minor quibble: wouldn't it be advisable to check the IsDependent property of each LayerTableRecord, to avoid empty ObjectIdCollections for xref layers?

Same function in F# (as always); the dict keyword by the way returns an immutable (i.e. read-only) dictionary..
Code: [Select]
        use tr = db.TransactionManager.StartTransaction()
        let layerMap =
            db.LayerTableId.GetObject OpenMode.ForRead :?> LayerTable
            |> Seq.cast<ObjectId>
            |> Seq.filter(fun ltid -> not (ltid.GetObject OpenMode.ForRead :?> LayerTableRecord).IsDependent)
            |> Seq.map(fun ltid -> ltid, new ObjectIdCollection())
            |> dict
   
        (SymbolUtilityServices.GetBlockModelSpaceId db).GetObject OpenMode.ForRead :?> BlockTableRecord
        |> Seq.cast<ObjectId>
        |> Seq.iter
            (fun entId ->
                let msEnt = entId.GetObject OpenMode.ForRead :?> Entity
                layerMap.[msEnt.LayerId].Add entId |> ignore )
   
        tr.Commit()
Regards, Thorsten

Glenn R

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #14 on: October 21, 2010, 05:16:02 AM »
Minor quibble: wouldn't it be advisable to check the IsDependent property of each LayerTableRecord, to avoid empty ObjectIdCollections for xref layers?

Minor reposte: Yes, of course it would, however it wasn't listed as a requirement; nobody else was doing it; and I was just showing a possible way of doing it - people could figure out the details themselves.

You'll also notice I'm not using any error checking either - shame on me.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #15 on: October 21, 2010, 05:23:45 AM »
< .. >
You'll also notice I'm not using any error checking either - shame on me.

Naughty, naughty.

not sure what to recommend as punishment   :|

masochist says 'whip me', sadist answers 'no' ...
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #16 on: October 21, 2010, 05:40:04 AM »
hehe...oldy but a goody. Actually, wouldn't the sadist say 'maybe' :D

G'day Kerry.

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #17 on: October 21, 2010, 06:30:47 AM »
You'll also notice I'm not using any error checking either - shame on me.

Not at all. What could possibly go wrong?

And even if anything does go wrong, either the .NET unhandled exception handler kicks in and informs you that an "unhandled exception has occurred in a component in your application", or you're toast anyway. Wrapping the code in a try-catch block doesn't really buy anything.

Now checking for error codes, status indications and the like is an entirely different matter.

Cheers, Thorsten

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #18 on: November 20, 2010, 04:32:40 PM »
Hi,

I'm still trying to understand some F# so I read the old threads where I can find some understandable code (for me).

This one make me think about a way to avoid using the Autodesk.AutoCAD.Interop to get the Template path by readin in the registry.
So I tried to write a little function.

Code: [Select]
let GetTemplatePath() = 
    let openKey key = Registry.CurrentUser.OpenSubKey(key)
    let getPath sub next key = key + "\\" + (openKey(key).GetValue(sub) :?> string) + next   
    ("Software\\Autodesk\\AutoCAD"
    |> getPath "CurVer" ""
    |> getPath "CurVer" "\\Profiles"
    |> getPath "" "\\General"
    |> openKey).GetValue("TemplatePath") :?> string

Or, more 'generic'

Code: [Select]
let CurProfileRegKey() =
    let openKey key = Registry.CurrentUser.OpenSubKey(key)
    let getPath sub key = key + "\\" + (openKey(key).GetValue(sub) :?> string)
    ("Software\\Autodesk\\AutoCAD" |> getPath "CurVer" |> getPath "CurVer") + "\\Profiles"
    |> getPath "" |> openKey

CurProfileRegKey().OpenSubKey("General").GetValue("TemplatePath")
« Last Edit: November 20, 2010, 05:50:16 PM by gile »
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #19 on: November 21, 2010, 04:11:46 AM »
May be no need to build so many functions.

Code: [Select]
let sTemplatePath =
    let getPath sub key =
        key + "\\" + (Registry.CurrentUser.OpenSubKey(key).GetValue(sub) :?> string)   
    ((("Software\\Autodesk\\AutoCAD" |> getPath "CurVer" |> getPath "CurVer") + "\\Profiles"
    |> getPath "") + "\\General"
    |> Registry.CurrentUser.OpenSubKey).GetValue("TemplatePath") :?> string + "\\acadiso.dwt"
Speaking English as a French Frog

kaefer

  • Guest
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #20 on: November 21, 2010, 05:34:15 AM »
May be no need to build so many functions.

The head hurts and there's fierce need...

You could get around the downcasts to string by supplying an explicit type parameter, which is resolved by inference.
Code: [Select]
module Reg =
    let substKey<'T> sub key = (Microsoft.Win32.Registry.CurrentUser.OpenSubKey key).GetValue sub :?> 'T
    let getPath sub key = key + "\\" + substKey<_> sub key

let curVer = "Software\\Autodesk\\AutoCAD" |> Reg.getPath "CurVer" |> Reg.getPath "CurVer"
let sTemplatePath =
    ((curVer + "\\Profiles" |> Reg.getPath "") + "\\General" |> Reg.substKey<_> "TemplatePath") + "\\acadiso.dwt"

Or if you're planning to do this a lot, go the whole mile and define custom operators. These here have the same precedence and associativity as to get rid of the ugly parentheses.
Code: [Select]
let openKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey
let (+&) key sub = (openKey key).GetValue sub
let (+/) key sub = key + "\\" + (key +& sub :?> string)
let templatePath() =
    "Software\\Autodesk\\AutoCAD"
    +/ "CurVer"
    +/ "CurVer"
    + "\\Profiles"
    +/ ""
    + "\\General"
    +& "TemplatePath"
    :?> string
    + "\\acadiso.dwt"

Take care, Thorsten

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: "Wblock Layers", saving the contents of each layer to a separate file
« Reply #21 on: November 21, 2010, 07:11:11 AM »
Thank you very much kaefer.
I'll study all this...

Quote
the ugly parentheses
I'am comming from LISP, parentheses reassure me.
« Last Edit: November 21, 2010, 07:16:28 AM by gile »
Speaking English as a French Frog