Author Topic: Civil 3d. Corridor targets from XRefs  (Read 1861 times)

0 Members and 1 Guest are viewing this topic.

Skre

  • Mosquito
  • Posts: 2
Civil 3d. Corridor targets from XRefs
« on: January 12, 2023, 08:07:15 AM »
Hello community!

I want to automate one of my key worktask with .net:

I have a corridor builded in Civil 3D. For targets i use polylines in XRefs.
Those Xrefs comes from another users. Polylines in XRefs are fine structured (layers, colors and other stuff are allways the same). Ony their position could be changed.
Obvisiously, after user replace old file with new one all corridor targets vanish. Don't know exactly why, but i blame new guids of polylines in new file.

So, i want to create a code wtich will replace targets in a corridor automaticaly without opening file with corridors.
And yes, if i open file with corridors - it regens and all targets with XRefs are cleared, so i dont have any data to operate with.

Longstory short:
1. Start code from a new file
2. By opendialogs - acquire databases of File with Corridors, and files with XRefs i want to update
3. Find Corridors in "File with Corridors".
4. Acquire targets ids
5. Manipulate.

I faced a wall on 4th step.
Targets from XRefs got (0) id if i dont open a file. And because of it - i can't get further to compare if this XRef is one i need or not.

I assume, that i need to "activate" corridors somehow, but all workarounds i could find in internet - gived no results.

These (0) id from debug - on attached screenshot.

Code:
Code: [Select]
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
            DocumentCollection dc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
           

            Autodesk.AutoCAD.Windows.OpenFileDialog ofdOrig = new Autodesk.AutoCAD.Windows.OpenFileDialog("Corridor File", "", "", "DWG", Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.NoUrls);
            ofdOrig.ShowDialog();
            string OrigFilePath = ofdOrig.Filename;

            Database OrigDb = new Database(true,false);
            OrigDb.ReadDwgFile(OrigFilePath, FileOpenMode.OpenForReadAndAllShare, true,"");
           
            Autodesk.AutoCAD.Windows.OpenFileDialog ofdXrefs = new Autodesk.AutoCAD.Windows.OpenFileDialog("XRef Files", "", "", "DWG", Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.AllowMultiple);           
            ofdXrefs.ShowDialog();
            string[] XrefFilePaths = ofdXrefs.GetFilenames();       

            if ((ofdOrig.Filename.Length> 1)&&((XrefFilePaths.Length>0)))
                using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
                {                   
                    HostApplicationServices.WorkingDatabase = OrigDb; //without this one it will not even get SubassemblyTargetInfoCollection.
                    BlockTable OrigBT = (BlockTable)OrigDb.BlockTableId.GetObject(OpenMode.ForWrite);
                    ObjectIdCollection CorIds = new ObjectIdCollection();
                    ObjectIdCollection XrefsIds = new ObjectIdCollection();
                    foreach(ObjectId OrigBtrId in OrigBT)
                    {
                        BlockTableRecord OrigBtr = (BlockTableRecord)OrigBtrId.GetObject(OpenMode.ForRead);
                        foreach(ObjectId TMPId in OrigBtr)
                        {
                            if (TMPId.ObjectClass.DxfName == "AECC_CORRIDOR")
                                CorIds.Add(TMPId);                           
                        }
                       
                    }
                    foreach (ObjectId CorId in CorIds)
                    {
                        Corridor Cor = (Corridor)CorId.GetObject(OpenMode.ForWrite);                       
                        foreach (Baseline Bl in Cor.Baselines)
                        {
                            foreach (BaselineRegion Blr in Bl.BaselineRegions)
                            {
                                SubassemblyTargetInfoCollection stic = Blr.GetTargets();
                                foreach (SubassemblyTargetInfo sti in stic)
                                {
                                    foreach (ObjectId TId in sti.TargetIds)//here is my breakpoint where i took screenshot
                                    {
                                        if (TId.ObjectClass.DxfName == "LWPOLYLINE")
                                        {
                                            //So, it newer comes here, because (0) ObjectId has null ObjectClass.DxfName
                                            Autodesk.AutoCAD.DatabaseServices.Polyline Poly = (Autodesk.AutoCAD.DatabaseServices.Polyline)TId.GetObject(OpenMode.ForRead);
                                        }
                                    }
                                }
                            }
                        }
                    }
                   
                }

        }
« Last Edit: January 12, 2023, 08:12:49 AM by Skre »

Skre

  • Mosquito
  • Posts: 2
Re: Civil 3d. Corridor targets from XRefs
« Reply #1 on: March 07, 2023, 03:31:08 AM »
I managed to achieve my goals by changing logic of this function.
To make it work i need:
1. DXF file from remote designer.
2. DWG file where i copied insides of DXF. It should be polylines that user will use as coridor targets.
3. DWG file where user will build corridors. DWG file with polylines connected as XREF.

Code bellow works in next secuence:
1. Open drawing with corridors. Coridor's targets set to DWG file with polylines.
2. Run a command -> select DXF file
3. Collect all XREFS from current DWG to find one needed to update.
4. Iterate through BaseLines, their Regions and targets to find ones than are polylines and references
5. If found target are polyline and it's ref file name are same as picked on 2nd step DXF -> updating this polyline in xref using data from DXF.

Main goal of this is to making possible to recieve changes from remote designer without having to update all targets by hands. Because if you replace polys in DWG from DXF - corridor's targets will disapear.

P.S. I understand that this is really narrow case, but i want to contribute this code to community, because it contains many parts that could be separately interested for new users of civil api. And may be it will help someone as other topics from this forum helped me :)
P.P.S. I am also a beginner so this solution is really far from optimal.

Code - C#: [Select]
  1. public void CT_ROADS_UpdateTargets_Refs()
  2. {
  3.    Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
  4.    CivilDocument civilDoc = CivilApplication.ActiveDocument;
  5.    Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  6.    Database acCurDb = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
  7.    DocumentCollection dc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
  8.  
  9.    //picking dxf
  10.    Autodesk.AutoCAD.Windows.OpenFileDialog ofdUpdate = new Autodesk.AutoCAD.Windows.OpenFileDialog("Select DXF with new data", "", "", "DXF", Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.AllowMultiple);
  11.    ofdUpdate.ShowDialog();
  12.    string[] UpdateFilePaths = ofdUpdate.GetFilenames();
  13.    if (( UpdateFilePaths != null ))
  14.       for (int i = 0; i < UpdateFilePaths.Length; i++)
  15.       {
  16.          UpdateFilePaths[i] = UpdateFilePaths[i].ToUpper();
  17.       }
  18.  
  19.    ObjectIdCollection DonePolysIds = new ObjectIdCollection();
  20.  
  21.    if (( UpdateFilePaths != null ))
  22.       using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
  23.       {
  24.          BlockTable acBlkTbl;
  25.          acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForWrite) as BlockTable;
  26.  
  27.          BlockTableRecord acBlkTblRec;
  28.          acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
  29.  
  30.          //Getting xrefs from current file
  31.          string[] XRefNames = new string[100];
  32.          ObjectId[] XRefIds = new ObjectId[100];
  33.          BlockTable OrigBT = (BlockTable)acCurDb.BlockTableId.GetObject(OpenMode.ForWrite);
  34.          int i = 0;
  35.          foreach (ObjectId OrigBtrId in OrigBT)
  36.          {
  37.             BlockTableRecord OrigBtr = (BlockTableRecord)OrigBtrId.GetObject(OpenMode.ForRead);
  38.             foreach (ObjectId TMPId in OrigBtr)
  39.             {
  40.                if (TMPId.ObjectClass.DxfName == "INSERT")
  41.                {
  42.                   BlockReference ERTMP = (BlockReference)TMPId.GetObject(OpenMode.ForRead);
  43.                   BlockTableRecord ERBtrTMP = (BlockTableRecord)ERTMP.BlockTableRecord.GetObject(OpenMode.ForRead);
  44.                   if (ERBtrTMP.IsFromExternalReference)
  45.                   {
  46.                      XRefIds[i] = TMPId;
  47.                      XRefNames[i] = ERTMP.Name;
  48.                      i++;
  49.                   }
  50.                }
  51.             }
  52.          }
  53.  
  54.          CorridorCollection CorCol = civilDoc.CorridorCollection;
  55.          foreach (ObjectId CorId in CorCol)
  56.          {
  57.             Corridor Cor = (Corridor)CorId.GetObject(OpenMode.ForWrite);
  58.             foreach (Baseline Bl in Cor.Baselines)
  59.             {
  60.                Alignment alg = (Alignment)Bl.AlignmentId.GetObject(OpenMode.ForRead);
  61.                foreach (BaselineRegion Blr in Bl.BaselineRegions)
  62.                {
  63.                   //these points will be needed to determine
  64.                   //the side of polyline relative to baseline
  65.                   Point2d AlAP = P3dToP2d(alg.GetPointAtDist(Blr.StartStation));
  66.                   Point2d AlBP = P3dToP2d(alg.GetPointAtDist(Blr.StartStation + 1));
  67.  
  68.                   SubassemblyTargetInfoCollection stic = Blr.GetTargets();
  69.                   foreach (SubassemblyTargetInfo sti in stic)
  70.                   {
  71.                      foreach (ObjectId TId in sti.TargetIds)
  72.                      {
  73.                         if (( TId.ObjectClass.DxfName == "LWPOLYLINE" ) && ( TId.Database.Filename.Contains(".dwg") ) && ( DonePolysIds.Contains(TId) == false ))
  74.                         {
  75.                            string XRefFileName = ( Regex.Match(TId.Database.Filename, "(?<=\\\\(?!.*\\\\))(.*)", RegexOptions.None) ).Value;
  76.                            XRefFileName = XRefFileName.Remove(XRefFileName.IndexOf(".dwg"));
  77.                            string XRefPath = ( TId.Database.Filename.Remove(TId.Database.Filename.IndexOf(".dwg")) + ".dxf" ).ToUpper();
  78.  
  79.                            //if found poly are from ref file (TId.Database.Filename!="")
  80.                            //and its file name are in list of picked DXFs - updating starts
  81.                            if (UpdateFilePaths.Contains(XRefPath))
  82.                            {
  83.                               if (IsFileLockedOrReadOnly(new FileInfo(XRefPath)))
  84.                               {
  85.                                  ed.WriteMessage("\nUnable to read XREF: " + XRefPath);
  86.                                  return;
  87.                               }
  88.                               else
  89.                               {
  90.                                  //getting DB of XREF
  91.                                  BlockReference XRefBlk = (BlockReference)XRefIds[Array.IndexOf(XRefNames, XRefFileName)].GetObject(OpenMode.ForWrite);
  92.                                  BlockTableRecord XRefBlkTR = (BlockTableRecord)XRefBlk.BlockTableRecord.GetObject(OpenMode.ForWrite);
  93.                                  Database XRefDb = XRefBlkTR.GetXrefDatabase(false);
  94.                                  using (var xf = XrefFileLock.LockFile(XRefDb.XrefBlockId))
  95.                                  {
  96.                                     XRefDb.RestoreOriginalXrefSymbols();
  97.                                     BlockTable XRefBT = (BlockTable)XRefDb.BlockTableId.GetObject(OpenMode.ForWrite);
  98.                                     BlockTableRecord XRefMS = (BlockTableRecord)XRefBT[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite);
  99.                                     ObjectId XRefPolyId = new ObjectId();
  100.  
  101.                                     //Finding poly to update
  102.                                     foreach (ObjectId UpdateBtrId in XRefMS)
  103.                                     {
  104.                                        if (UpdateBtrId.ToString() == TId.ToString())
  105.                                           XRefPolyId = UpdateBtrId;
  106.                                     }
  107.                                     Autodesk.AutoCAD.DatabaseServices.Polyline XRefPoly = (Autodesk.AutoCAD.DatabaseServices.Polyline)XRefPolyId.GetObject(OpenMode.ForWrite);
  108.  
  109.                                     //determine polyline side
  110.                                     Point2d XRefPolyP = P3dToP2d(XRefPoly.GetClosestPointTo(alg.GetPointAtDist(Blr.StartStation), true));
  111.                                     double XRefPolySide = LeftOrRight(AlAP, AlBP, XRefPolyP);
  112.  
  113.                                     //Getting poly info from DXF
  114.                                     //as DXF is a text file - read it as text file
  115.                                     string ln;
  116.                                     bool huyl = false;
  117.                                     bool plin = false;
  118.                                     int UpdPlinesCounter = 0;
  119.                                     string PrevStr = "";
  120.                                     string PolyLayer = "";
  121.                                     int verC = 0;
  122.                                     double PolyX = 0;
  123.                                     int cntr = 0;
  124.                                     Autodesk.AutoCAD.DatabaseServices.Polyline Poly = new Autodesk.AutoCAD.DatabaseServices.Polyline();
  125.                                     using (StreamReader DXFRem = new StreamReader(XRefPath))
  126.                                     {
  127.                                        while (( ln = DXFRem.ReadLine() ) != null)
  128.                                        {
  129.                                           cntr++;
  130.  
  131.                                           //here is a logic to find a needed poly from all polys inside DXF
  132.                                           //It first creates a "Poly" from DXF data.
  133.                                           //Then it compares side and layer of found poly and xref poly
  134.                                           //if found poly on same side and layer - updating.
  135.                                           if (ln == "AcDbEntity")
  136.                                           {
  137.                                              huyl = true;
  138.                                              plin = false;
  139.                                              i++;
  140.                                              PrevStr = "";
  141.                                              verC = 0;
  142.                                              if (Poly.NumberOfVertices > 2)
  143.                                              {
  144.                                                 Point2d UpdatePolyP = P3dToP2d(Poly.GetClosestPointTo(alg.GetPointAtDist(Blr.StartStation), true));
  145.                                                 double UpdatePolySide = LeftOrRight(AlAP, AlBP, UpdatePolyP);
  146.                                                 if (PolyLayer == XRefPoly.Layer && XRefPolySide == UpdatePolySide)
  147.                                                 {
  148.                                                    Point3dCollection PolyPnts = new Point3dCollection();
  149.                                                    Poly.GetStretchPoints(PolyPnts);
  150.                                                    for (int DelP = XRefPoly.NumberOfVertices - 1; DelP > 0; DelP--)
  151.                                                    {
  152.                                                       XRefPoly.RemoveVertexAt(DelP);
  153.                                                    }
  154.                                                    for (int InsP = 1; InsP < PolyPnts.Count; InsP++)
  155.                                                    {
  156.                                                       XRefPoly.AddVertexAt(InsP, P3dToP2d(PolyPnts[InsP]), 0, 0, 0);
  157.                                                    }
  158.                                                    XRefPoly.RemoveVertexAt(0);
  159.                                                    XRefPoly.ColorIndex = 10;
  160.                                                    break;
  161.                                                 }
  162.                                              }
  163.                                              PolyLayer = "";
  164.                                              Poly = new Autodesk.AutoCAD.DatabaseServices.Polyline();
  165.                                           }
  166.                                           if (ln == "AcDbPolyline")
  167.                                           {
  168.                                              plin = true;
  169.                                           }
  170.                                           if (huyl)
  171.                                           {
  172.                                              switch (PrevStr)
  173.                                              {
  174.                                                 case "  8":
  175.                                                    PolyLayer = ln;
  176.                                                    break;
  177.  
  178.                                                 case " 10":
  179.                                                    if (plin) PolyX = Convert.ToDouble(ln);
  180.                                                    break;
  181.  
  182.                                                 case " 20":
  183.                                                    if (plin)
  184.                                                    {
  185.                                                       Poly.AddVertexAt(verC, new Point2d(PolyX, Convert.ToDouble(ln)), 0, 0, 0);
  186.                                                       verC++;
  187.                                                    }
  188.                                                    break;
  189.                                              }
  190.                                              PrevStr = ln;
  191.                                           }
  192.                                        }
  193.                                     }
  194.                                     DonePolysIds.Add(TId);
  195.                                     XRefDb.RestoreForwardingXrefSymbols();
  196.                                  }
  197.                               }
  198.                            }
  199.                         }
  200.                      }
  201.                   }
  202.                }
  203.             }
  204.             break;
  205.          }
  206.          acTrans.Commit();
  207.       }
  208. }
  209.  
  210. public static bool IsFileLockedOrReadOnly(FileInfo fi)
  211. {
  212.    FileStream fs = null;
  213.  
  214.    try
  215.    {
  216.       fs =
  217.         fi.Open(
  218.           FileMode.Open, FileAccess.ReadWrite, FileShare.None
  219.         );
  220.    }
  221.    catch (System.Exception ex)
  222.    {
  223.       if (ex is IOException || ex is UnauthorizedAccessException)
  224.       {
  225.          return true;
  226.       }
  227.       throw;
  228.    }
  229.    finally
  230.    {
  231.       if (fs != null)
  232.          fs.Close();
  233.    }
  234.  
  235.    // File is accessible
  236.    return false;
  237. }
  238. public static int LeftOrRight(Point2d A, Point2d B, Point2d P)
  239. {
  240.    if (( B.X - A.X ) * ( P.Y - A.Y ) - ( B.Y - A.Y ) * ( P.X - A.X ) > 0)
  241.       return 1;
  242.    else
  243.       return -1;
  244. }
  245.  
  246.  


codetags added:kdub
« Last Edit: March 08, 2023, 12:49:29 AM by kdub »