Author Topic: .NET LAYER Routines  (Read 11002 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11653
  • class keyThumper<T>:ILazy<T>
.NET LAYER Routines
« on: January 27, 2010, 03:03:52 am »
LIBRARY THREAD for  AutoCAD LAYERS
 Members are encouraged to post any functions, methods, snips regarding
AutoCAD LAYERS in .NET : C# ,  VB , F# , Python , etc

Feel free to include comments, descriptive notes, limitations,  and images to document your post.

Please post questions in a regular thread.
« Last Edit: January 27, 2010, 03:11:52 am by Kerry Brown »
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

Bryco

  • Water Moccasin
  • Posts: 1806
Re: .NET LAYER Routines
« Reply #1 on: January 27, 2010, 07:31:36 am »
I use this to find the layer picked for isolating, freezing, turning off.
It works better than the acad versions as you end up turning off the layer you see not the layer of the block.
Code: [Select]
        public string GetSubEntityLayer(string Msg )

            //1)Layer "0" and defpoints may be in a standard block
            //2) in an x-ref or within a block within an x-ref
            //layer "0" and defpoints in an x-ref dont get "|"
            //3) blocks within an x-ref have the name x-ref.name | blockname
            //4) owner doesnt have a layer property
           
        {
     
            Document doc=acadApp.DocumentManager.MdiActiveDocument;
            Editor ed=doc.Editor;
            PromptNestedEntityOptions pno=new PromptNestedEntityOptions ("\n" + Msg);
            PromptNestedEntityResult pnr=ed.GetNestedEntity(pno);
            if(pnr.Status!=PromptStatus.OK) return "";
            ObjectId[] cons= pnr.GetContainers();

            using (Transaction tr=doc.TransactionManager.StartTransaction())
            {
                Entity ent=tr.GetObject( pnr.ObjectId,OpenMode.ForRead) as Entity;   
                if(Msg =="Select objects")ent.Highlight ();     
                string sLayer = ent.Layer;
                if(string.Compare(sLayer,"0",false)==0
                    |string.Compare(sLayer,"defpoints",false)==0)
                {
                    if(cons.Length==0) return ent.Layer;
                        //ent is not nested, user wanted this layer
                    Entity owner=tr.GetObject(cons[0],OpenMode.ForRead) as Entity;
                    if(owner.GetType()==typeof(BlockReference))
                    {
                        if(owner.Layer!="0")
                            return owner.Layer;
                        else
                        {
                            for (int i = 0; i < cons.Length; i++)
                            {
                                owner=tr.GetObject(cons[i],OpenMode.ForRead)as Entity;
                                if(owner.GetType()==typeof(BlockReference))
                                {
                                    sLayer = owner.Layer;
                                    if( sLayer!= "0") break;
                                }
                            }
                        }
                    }
                   
                }
                           
                return sLayer;

            }
                           
        } //end GetSubEntityLayer

huiz

  • Swamp Rat
  • Posts: 775
  • Certified Prof C3D
Re: .NET LAYER Routines
« Reply #2 on: January 27, 2010, 07:53:21 am »
A function to return Current Layer in VB:

Code: [Select]
    ' A function to return the current Layer, you can get properties as name and id from the returned object.
    ' Ex: hzGetCurrentLayer.Name
    Shared Function hzGetCurrentLayer() As LayerTableRecord
      ' Get the current document and database
      Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
      Dim acCurDb As Database = acDoc.Database
      Dim acLayer As LayerTableRecord

      ' Start a transaction
      Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
        acLayer = CType(acTrans.GetObject(acCurDb.Clayer, OpenMode.ForRead), LayerTableRecord)
        ' Close transaction
        acTrans.Dispose()
      End Using

      Return acLayer

    End Function

The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11653
  • class keyThumper<T>:ILazy<T>
Re: .NET LAYER Routines
« Reply #3 on: January 27, 2010, 09:06:18 am »

getting the Current Layer from System Variables   < similar to lisp statement (getvar "CLAYER") >

Code: [Select]
string m_layer = (string)Application.GetSystemVariable("clayer");

This method is applicable to all Autocad System variables.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

Draftek

  • Water Moccasin
  • Posts: 1501
Re: .NET LAYER Routines
« Reply #4 on: January 27, 2010, 10:22:11 am »
^ Great idea!
Soli Deo Gloria

T.Willey

  • Needs a day job
  • Posts: 5189
Re: .NET LAYER Routines
« Reply #5 on: January 29, 2010, 12:30:42 pm »
My edit layer by selection code is here.

[ http://www.theswamp.org/index.php?topic=25698.0 ]
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

huiz

  • Swamp Rat
  • Posts: 775
  • Certified Prof C3D
Re: .NET LAYER Routines
« Reply #6 on: January 31, 2010, 08:09:14 am »
Indeed and I'll keep this in mind, but with my code you get the layer object instead of just a string.

But it is refreshing to see a very simple method I didn't think of, and if I only need a string, I'll use your solution :-)




getting the Current Layer from System Variables   < similar to lisp statement (getvar "CLAYER") >

Code: [Select]
string m_layer = (string)Application.GetSystemVariable("clayer");

This method is applicable to all Autocad System variables.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Bryco

  • Water Moccasin
  • Posts: 1806
Re: .NET LAYER Routines
« Reply #7 on: January 31, 2010, 12:06:00 pm »
Standard layer functions C#
Code: [Select]
        public static void setCurrentLayer(string sLayer)
        {//Kerry Brown http://www.theswamp.org/index.php?topic=7766.msg98575#msg98575
            if (sLayer == "") return;
            Database db=HostApplicationServices.WorkingDatabase;
            ObjectId layerId=ObjectId.Null;
            using(Transaction tr=db.TransactionManager.StartTransaction())
            {
                LayerTable pLayerTable = (LayerTable)tr.GetObject
                    (db.LayerTableId, OpenMode.ForRead);
                if (pLayerTable.Has(sLayer))
                {
                    layerId = pLayerTable[sLayer];
                    if (layerId.IsErased)
                    {
                        LayerTableRecord pExLtr = (LayerTableRecord)tr.GetObject
                            (layerId, OpenMode.ForWrite, true);
                        pExLtr.Erase(false);
                    }
                }
                else // create it...
                {
                    LayerTableRecord pNewLTR = new LayerTableRecord();
                    pNewLTR.Name = sLayer;
                    pLayerTable.UpgradeOpen();
                    layerId = pLayerTable.Add(pNewLTR);
                    tr.AddNewlyCreatedDBObject(pNewLTR, true);
                }

                db.Clayer = layerId;
                db.Cecolor = Color.FromColorIndex(ColorMethod.ByLayer, 256);//Added
                db.Celtype = db.ByLayerLinetype; //Added
            }
        }



        public static void setCurrentLayer(ObjectId layerId)
        {
            if (layerId == ObjectId.Null) return;
            Database db = HostApplicationServices.WorkingDatabase;
            db.Clayer = layerId;
            db.Cecolor = Color.FromColorIndex(ColorMethod.ByLayer, 256);
            db.Celtype = db.ByLayerLinetype;
           
        }



        [CommandMethod("SetObjLayerCurrent")]
        public void SetObjLayerCurrent()
        {
            string sLayer = GetSubEntityLayer("Pick an object on the layer you want to make current:");
            if( sLayer.Contains("|"))
            {
                MessageBox.Show("You can not make the x-ref layer " + sLayer +" current");
                return;
            }
            setCurrentLayer(sLayer);
           Print (sLayer + " is now the current layer. ");
           
        }


        [CommandMethod("IsolateLayer")]
        public void IsolateLayer()
        {
           Print("Select object(s) on the layer(s) to be isolated:");
            string Msg = "Select objects", sLayer;
            StringCollection layerset = new StringCollection();
            do
            {
                sLayer = GetSubEntityLayer(Msg);
                if (sLayer != "")
                    layerset.Add(sLayer);       
            } while (sLayer != "");

            for (int i = 0; i < layerset.Count; i++)
            {
                if (!layerset[i].Contains("|"))
                {
                    setCurrentLayer(layerset[i]);
                    break;
                }
            }

            Database db = HostApplicationServices.WorkingDatabase;
            LayerTableRecord layer;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                foreach (ObjectId layerId in lt)
                {
                    layer = tr.GetObject
                        (layerId, OpenMode.ForWrite) as LayerTableRecord;
                    layer.IsOff = true;
                }

                for (int i = 0; i < layerset.Count; i++)
                {
                    sLayer = layerset[i];
                    layer = tr.GetObject

                            (lt[sLayer], OpenMode.ForWrite) as LayerTableRecord;
                    layer.IsOff = false;
                    if (i == 0) Msg = sLayer;

                    else Msg = Msg + " and " + sLayer;
                }
                tr.Commit();
                acadApp.DocumentManager.MdiActiveDocument.Editor.Regen();
               Print("The isolated layer names are " + Msg);
            }
        }



        [CommandMethod("Layerson")]
        public void Layerson()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            LayerTableRecord layer;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                foreach (ObjectId layerId in lt)
                {
                    layer = tr.GetObject
                        (layerId, OpenMode.ForWrite) as LayerTableRecord;
                    layer.IsOff = false;
                }
                tr.Commit();
            }
        }



        [CommandMethod("Layeroff")]
        public void LayerOff()
        {   
            Database db=HostApplicationServices.WorkingDatabase;
            string msg, sLayer;
            do
            {
                sLayer = GetSubEntityLayer("Pick an object on the layer you want to turn off:");
                if (sLayer == "") return;
                if(sLayer ==(string) acadApp.GetSystemVariable("CLayer"))
                {
                    msg="\nDo you really want to turn the current layer off?";
                    MessageBox.Show(msg,"Layer off",MessageBoxButtons.YesNo);
                }
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                    LayerTableRecord ltr = tr.GetObject
                        (lt[sLayer], OpenMode.ForWrite) as LayerTableRecord;
                    ltr.IsOff = true;
                   Print(sLayer + " is turned off. ");
                    tr.Commit();
                }
           } while (sLayer != "");
        }


        [CommandMethod("Layerfreeze")]
        public void Layerfreeze()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            string msg, sLayer, curLayer = (string)acadApp.GetSystemVariable("CLayer");
            do
            {
                sLayer = GetSubEntityLayer("Pick an object on the layer you want to freeze:");
                if (sLayer == "") return;
                if (sLayer ==curLayer)
                {
                    msg = "\nDo can not freeze the current layer?";
                    MessageBox.Show(msg, "Freeze");
                }
                else
                {
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                        LayerTableRecord ltr = tr.GetObject
                            (lt[sLayer], OpenMode.ForWrite) as LayerTableRecord;
                        ltr.IsFrozen = true;
                       Print(sLayer + " is frozen. ");
                        tr.Commit();
                    }
                }
            } while (sLayer != "");
        }




        [CommandMethod("Thaw")]
        public void ThawAll()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            LayerTableRecord layer;
            string curLayer = (string)acadApp.GetSystemVariable("CLayer");

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                foreach (ObjectId layerId in lt)
                {
                    layer = tr.GetObject
                        (layerId, OpenMode.ForWrite) as LayerTableRecord;
                    if(layer.Name!=curLayer)
                        layer.IsFrozen = false;
                }
                tr.Commit();
                acadApp.DocumentManager.MdiActiveDocument.Editor.Regen();
            }
        }



        static public void Print(string sMsg)
        {
            Document Doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = Doc.Editor;
            ed.WriteMessage("\n" + sMsg );
        }

fixo

  • Guest
Re: .NET LAYER Routines
« Reply #8 on: October 13, 2010, 04:52:21 am »
Save each layers in separate files

~'J'~

kaefer

  • Swamp Rat
  • Posts: 572
Re: .NET LAYER Routines
« Reply #9 on: October 13, 2010, 12:37:00 pm »
Save each layers in separate files

Hi Oleg, that's very nice!

My question: whence the necessity to open (and lock) all those documents if one is able to write directly to a new Database? I do see that the easy way has its problems, my test run wasn't entirely successful because the new drawings aren't in metric but imperial units.

F# alarm! Confer:
Code: [Select]
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

let selectOnLayer lrname =
    let res =
        new SelectionFilter[| new TypedValue(int DxfCode.LayerName, lrname) |]
        |> acApp.DocumentManager.MdiActiveDocument.Editor.SelectAll
    if res.Status <> PromptStatus.OK then null
    else new ObjectIdCollection(res.Value.GetObjectIds())

[<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 current document's path and name without extension
    let currRoot = acApp.GetSystemVariable "DWGPREFIX" :?> string
    let currName = acApp.GetSystemVariable "DWGNAME" :?> string
    let currName = System.IO.Path.GetFileNameWithoutExtension currName

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

    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

    for lrname in lrcoll do
        let objcoll = selectOnLayer lrname
        if objcoll <> null then

            let strFilename =
                System.IO.Path.Combine(
                    currRoot, currName + @"_" + lrname + @".dwg" ) //<-- build filename as you need here

            ed.WriteMessage("\n" + strFilename)

            // Create a new database to copy the objects to
            use newdb = new Database(true, true)
           
            use newtr = newdb.TransactionManager.StartTransaction()

            // Open the Block table record Model space for read
            let newbtr =
                newtr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId newdb, OpenMode.ForRead) :?> BlockTableRecord

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

            newdb.SaveAs(strFilename, DwgVersion.Current)
            newtr.Commit()               

    tr.Commit()
Have fun, Thorsten

fixo

  • Guest
Re: .NET LAYER Routines
« Reply #10 on: October 13, 2010, 02:24:57 pm »
Thanks, Thorsten!

I will check it on my machine
Not sure about that it is needs to LockDocument (old one)
as well as the new documents, I think you're right if
your code is working good without it
But it's my thoughts...
Probably, better yet to create a new topic with question about LockDocument,
because in ObjectARX docs is poor explanation about this thing?
Keep firing :)

Regards,

Oleg

Jeff H

  • Needs a day job
  • Posts: 5841
Re: .NET LAYER Routines
« Reply #11 on: October 14, 2010, 09:14:11 am »
because in ObjectARX docs is poor explanation about this thing?
Keep firing :)

Regards,

Oleg
Have looked in the arxdoc.chm?
I use to use the arxmgd.chm but arxdoc.chm is alot better.
If you have not looked open the arxdoc.chm and on the index tab type in "locking" and double that and read all entries that come up. It gives a pretty good explanation.

This is what the developers guide says
Quote
•Interacts with AutoCAD from a modeless dialog box
•Accesses a loaded document other than the current document
•Used as a COM server
•Registers a command with the Session command flag

feesa

  • Mosquito
  • Posts: 13
Re: .NET LAYER Routines
« Reply #12 on: February 27, 2017, 08:52:02 am »
Hi,

Can any one provide me a sample code to copy all objects from layer1 to layer 2, also i want to union all object in layer 2.

Thanks & Regards