Author Topic: Erase blocks and replacing them  (Read 2030 times)

0 Members and 1 Guest are viewing this topic.

latour_g

  • Newt
  • Posts: 184
Erase blocks and replacing them
« on: February 17, 2016, 01:19:06 PM »
Hi,

I have a drawing with a lot of differents blocks.  I want to replace them to be all the same blocks.  What I'm doing is I delete them and I insert a new block at the same place as they were.  If all the blocks I am replacing has differents names, it's working well but if not, some blocks aren't going to be replace.
I know that my code need to be fix but I don't know how.   The try/catch is a workaround for the time I'm trying to fix my code.

Code - C#: [Select]
  1.         private void bbtnChangeBLK_Click(object sender, EventArgs e)
  2.         {
  3.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  4.             Database db = doc.Database;
  5.             Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  6.  
  7.             using (DocumentLock lockDoc = doc.LockDocument())
  8.             {
  9.                 //Trouver tous les blocs et inscrire à côté le nom et la visibilité
  10.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  11.                 {
  12.                     TypedValue[] filList = new TypedValue[1] { new TypedValue((int)DxfCode.Start, "INSERT") };
  13.                     SelectionFilter filter = new SelectionFilter(filList);
  14.                     PromptSelectionOptions opts = new PromptSelectionOptions();
  15.                     opts.MessageForAdding = "Select block references: ";
  16.                     PromptSelectionResult res = ed.GetSelection(opts, filter);
  17.  
  18.                     // Do nothing if selection is unsuccessful
  19.                     if (res.Status != PromptStatus.OK) { return; }
  20.  
  21.                     SelectionSet selSet = res.Value;
  22.  
  23.                     ObjectId[] idArray = selSet.GetObjectIds();
  24.  
  25.                     foreach (ObjectId blkId in idArray)
  26.                     {
  27.                         BlockReference blkRef = (BlockReference)tr.GetObject(blkId, OpenMode.ForWrite);
  28.                         string cNomBlk = "";
  29.                         try
  30.                         {
  31.                             cNomBlk = blkRef.Name.ToUpper();
  32.                         }
  33.                         catch
  34.                         {
  35.                             continue;
  36.                         }
  37.                         Point3d ptLoc = blkRef.Position;
  38.                         string cLayer = blkRef.Layer;
  39.                         double nRotation = blkRef.Rotation;
  40.                         Scale3d sc3d = blkRef.ScaleFactors;
  41.  
  42.                         BlockTableRecord  btr = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
  43.                         blkRef.Erase();
  44.                         btr.Erase();
  45.  
  46.                         if(cNomBlk.StartsWith("ARP172"))
  47.                         {
  48.                             UTIL.insertBlock(ptLoc, "ARBUSTE", sc3d.X, nRotation, cLayer, false);
  49.                         }
  50.                     }
  51.                     tr.Commit();
  52.                 }
  53.             }
  54.         }
  55.  
  56.  
« Last Edit: February 18, 2016, 11:56:44 AM by latour_g »

Tharwat

  • Swamp Rat
  • Posts: 710
  • Hypersensitive
Re: Erase blocks and replacing them
« Reply #1 on: February 17, 2016, 02:48:22 PM »
Hi,
A few points to consider;

* There is no need to make a selection set plus an Array of ObjectID's , so just replace it in the foreach function with res.value.GetObjctIds()
* Your try block is useless I think since it does not cover the needed tasks for the main goal of the codes, so must be modified.
* You did not exclude the Attributed Blocks since that you did not account for them and that is not a simple thing and must need lots of codes to obtain all occurrences.
* Dynamic Blocks Names are also very important to take care of since their source names can not be retrieved from the simple property .Name

That's what come up to my mind when I read your codes , so good luck with your coding .

latour_g

  • Newt
  • Posts: 184
Re: Erase blocks and replacing them
« Reply #2 on: February 17, 2016, 02:58:08 PM »
Hi,

Thanks for your comments.  The try/catch block was to prevent this error (happening when a block from the same name has already been delete) :

latour_g

  • Newt
  • Posts: 184
Re: Erase blocks and replacing them
« Reply #3 on: February 17, 2016, 03:14:03 PM »
I think I need to erase the BlockTableRecord when I'm sure there is no more BlockReference refering to it.
But I didn't figure out how yet.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Erase blocks and replacing them
« Reply #4 on: February 17, 2016, 05:20:14 PM »
If it is a simple block I think changing BlockReference.BlockTableRecord will work.
You have express tool command BLOCKREPLACE but it does not work with annotative blocks.


Here is what I have been using for while and has worked for times I needed it.

Code - C#: [Select]
  1.         [CommandMethod("ReplaceBlock")]
  2.         public void ReplaceBlock()
  3.         {
  4.             PromptStringOptions pso = new PromptStringOptions("\nEnter Block Name to Replace");
  5.             pso.AllowSpaces = true;
  6.             PromptResult pr = Ed.GetString(pso);
  7.             if (pr.Status != PromptStatus.OK) return;
  8.  
  9.             string blockName = pr.StringResult.ToLower();
  10.  
  11.             PromptStringOptions psoNew = new PromptStringOptions("\nEnter Block Name to replace with");
  12.             psoNew.AllowSpaces = true;
  13.             PromptResult prNew = Ed.GetString(psoNew);
  14.             if (prNew.Status != PromptStatus.OK) return;
  15.  
  16.             string blockNameNew = prNew.StringResult.ToLower();
  17.  
  18.             using (Transaction trx = Db.TransactionManager.StartTransaction())
  19.             {
  20.                 BlockTable bt = Db.BlockTable();
  21.                 if (!bt.Has(blockName))
  22.                 {
  23.                     Ed.WriteLine("\n {0} is not in drawing", blockName);
  24.                     return;
  25.                 }
  26.  
  27.                 if (!bt.Has(blockNameNew))
  28.                 {
  29.                     Ed.WriteLine("\n {0} is not in drawing", blockNameNew);
  30.                     return;
  31.                 }
  32.  
  33.                 AllowedClassFilter acf = new AllowedClassFilter(typeof(BlockReference));
  34.                 PromptSelectionResult psr = Ed.GetSelection(acf);
  35.                 if (psr.Status != PromptStatus.OK) return;
  36.                 BlockTableRecord currentSpace = Db.CurrentSpace(OpenMode.ForWrite);
  37.  
  38.                 BlockTableRecord btr = bt[blockNameNew].GetDBObject<BlockTableRecord>();
  39.                 var attDefs = btr.GetAttributeDefinitions().Where(att => !att.Constant).ToList();
  40.  
  41.                 ObjectContextManager ocm = Db.ObjectContextManager;
  42.                 ObjectContextCollection occ = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
  43.  
  44.                 foreach (ObjectId id in psr.Value.GetObjectIds())
  45.                 {
  46.                     BlockReference bref = id.GetEntity<BlockReference>();
  47.                     if (bref.GetEffectiveName().ToLower() == blockName)
  48.                     {
  49.                         using (BlockReference newBref = new BlockReference(bref.Position, btr.ObjectId))
  50.                         {
  51.                             newBref.Rotation = bref.Rotation;
  52.                             newBref.LayerId = bref.LayerId;
  53.                             if (btr.Annotative == AnnotativeStates.True)
  54.                             {
  55.                                 ObjectContexts.AddContext(newBref, occ.CurrentContext);
  56.                             }
  57.                             else
  58.                             {
  59.                                 newBref.ScaleFactors = bref.ScaleFactors;
  60.                             }
  61.                             currentSpace.AppendEntity(newBref);
  62.                             trx.AddNewlyCreatedDBObject(newBref, true);
  63.                             foreach (var attDef in attDefs)
  64.                             {
  65.                                 using (AttributeReference attRef = new AttributeReference())
  66.                                 {
  67.                                     attRef.SetAttributeFromBlock(attDef, newBref.BlockTransform);
  68.                                     attRef.XData = attDef.XData;
  69.                                     newBref.AttributeCollection.AppendAttribute(attRef);
  70.                                     trx.AddNewlyCreatedDBObject(attRef, true);
  71.                                 }
  72.                             }
  73.                         }
  74.                         bref.UpgradeOpen();
  75.                         bref.Erase();
  76.                     }
  77.                 }
  78.  
  79.                 trx.Commit();
  80.             }
  81.         }
  82.  

Tharwat

  • Swamp Rat
  • Posts: 710
  • Hypersensitive
Re: Erase blocks and replacing them
« Reply #5 on: February 18, 2016, 07:14:48 AM »
Hi,

Here is my attempt in this regard, select First block then select a bunch of blocks to be replaced with the first one selected.
Try it and let me know.

I am not that experienced guy with C# yet, but I fell that I am driving my self and doing well at it for a while now and will never give up.  :whistling:

Code - C#: [Select]
  1.  public static void ReplacingBlocksWithAnother()
  2.         {
  3.             // Tharwat 18.02.2016
  4.             // Replace Blocks with another:
  5.             // Pick first block then select a bunch of blocks
  6.             // to be replaced with the first selected one.
  7.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  8.             Database db = doc.Database;
  9.             Editor ed = doc.Editor;
  10.             using (Transaction trA = db.TransactionManager.StartTransaction())
  11.             {
  12.                 try
  13.                 {
  14.                     PromptEntityOptions EntOpt = new PromptEntityOptions("\nPick on Single Block to replace with: ");
  15.                     EntOpt.SetRejectMessage("\nMust select Single Block !");
  16.                     EntOpt.AddAllowedClass(typeof(BlockReference), false);
  17.                     EntOpt.AllowNone = false;
  18.                     PromptEntityResult ent = ed.GetEntity(EntOpt);
  19.                     if (ent.Status != PromptStatus.OK) return;
  20.                     BlockReference NewBlkRef = (BlockReference)trA.GetObject(ent.ObjectId, OpenMode.ForRead);
  21.                     if (NewBlkRef.AttributeCollection.Count != 0)
  22.                     {
  23.                         ed.WriteMessage("\nBlock object must NOT be attributed !");
  24.                         return;
  25.                     }
  26.                     string name = GetEffectiveName(NewBlkRef);
  27.                     ed.WriteMessage("\nSelect Blocks to be replaced with < " + name + " >");
  28.                     TypedValue[] filList = { new TypedValue(0, "INSERT") , new TypedValue (-4, "<NOT")
  29.                                                , new TypedValue (66 , 1), new TypedValue (-4, "NOT>")};
  30.                     PromptSelectionOptions opts = new PromptSelectionOptions();
  31.                     opts.MessageForAdding = "Select block references: ";
  32.                     PromptSelectionResult res = ed.GetSelection(opts, new SelectionFilter(filList));
  33.                     if (res.Status == PromptStatus.OK)
  34.                     {
  35.                         BlockTable Btbl = (BlockTable)trA.GetObject(db.BlockTableId, OpenMode.ForRead);
  36.                         BlockTableRecord BlkRec = (BlockTableRecord)Btbl[NewBlkRef.Name].GetObject(OpenMode.ForWrite);
  37.                         BlockTableRecord sp = (BlockTableRecord)trA.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  38.                         foreach (ObjectId blkId in res.Value.GetObjectIds())
  39.                         {
  40.                             BlockReference OldRef = (BlockReference)trA.GetObject(blkId, OpenMode.ForWrite);
  41.                             BlockReference MBlock = new BlockReference(OldRef.Position, BlkRec.ObjectId);
  42.                             MBlock.ScaleFactors = OldRef.ScaleFactors;
  43.                             MBlock.LayerId = OldRef.LayerId;
  44.                             MBlock.Rotation = OldRef.Rotation;
  45.                             sp.AppendEntity(MBlock);
  46.                             trA.AddNewlyCreatedDBObject(MBlock, true);
  47.                             OldRef.Erase();
  48.                         }
  49.                     }
  50.                 }
  51.                 catch (System.Exception exP)
  52.                 {
  53.                     ed.WriteMessage(exP.Message);
  54.                 }
  55.                 trA.Commit();
  56.             }
  57.         }
  58.  
« Last Edit: February 18, 2016, 11:47:43 AM by Tharwat »

latour_g

  • Newt
  • Posts: 184
Re: Erase blocks and replacing them
« Reply #6 on: February 18, 2016, 11:44:41 AM »
Thanks for both of your codes. 

Tharwat,  I tried it and it's working fine, I just had to add "using (doc.LockDocument())" and the line 38 need to be ForWrite instead of ForRead.

Finally I rmade some adjustments to my code and it's working fine.

Code - C#: [Select]
  1.         private void btnChangeBLK_Click(object sender, EventArgs e)
  2.         {
  3.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  4.             Database db = doc.Database;
  5.             Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  6.  
  7.             Utils.SetFocusToDwgView();
  8.            
  9.             using (DocumentLock lockDoc = doc.LockDocument())
  10.             {
  11.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  12.                 {
  13.                     TypedValue[] filList = new TypedValue[1] { new TypedValue((int)DxfCode.Start, "INSERT") };
  14.                     SelectionFilter filter = new SelectionFilter(filList);
  15.                     PromptSelectionOptions opts = new PromptSelectionOptions();
  16.                     opts.MessageForAdding = "Select block references: ";
  17.                     PromptSelectionResult res = ed.GetSelection(opts, filter);
  18.  
  19.                     if (res.Status != PromptStatus.OK) { return; }
  20.                    
  21.                     foreach (ObjectId blkId in res.Value.GetObjectIds())
  22.                     {
  23.                         BlockReference blkRef = (BlockReference)tr.GetObject(blkId, OpenMode.ForWrite);
  24.  
  25.                         string cNomBlk = cNomBlk = blkRef.Name.ToUpper();
  26.                         Point3d ptLoc = blkRef.Position;
  27.                         string cLayer = blkRef.Layer;
  28.                         double nRotation = blkRef.Rotation;
  29.                         Scale3d sc3d = blkRef.ScaleFactors;
  30.  
  31.                         blkRef.Erase();
  32.  
  33.                         if(cNomBlk.StartsWith("ARP172"))
  34.                         {
  35.                             UTIL.insertBlock(ptLoc, "FEUILLU", sc3d.X, nRotation, cLayer, false);
  36.                         }
  37.  
  38.                         else if (cNomBlk.StartsWith("ARP171"))
  39.                         {
  40.                             UTIL.insertBlock(ptLoc, "CONIFÈRE", sc3d.X, nRotation, cLayer, false);
  41.                         }
  42.                     }
  43.  
  44.                     tr.Commit();
  45.                 }
  46.             }
  47.         }
  48.  

How do you insert your code has C# code in your post ?
« Last Edit: February 18, 2016, 11:56:24 AM by latour_g »

Tharwat

  • Swamp Rat
  • Posts: 710
  • Hypersensitive
Re: Erase blocks and replacing them
« Reply #7 on: February 18, 2016, 11:53:44 AM »
Excellent , good for you to have it working as you expected.

I just updated the codes to prevent the user from selecting attributed block since the program does not account for them, although I see you are not interested in that issue , so I revised it if any one loved to try or use.

To post codes in C# just from the top right side hand ComboBox [ code ] there is an option of C# and some other programming languages.

Good luck.

latour_g

  • Newt
  • Posts: 184
Re: Erase blocks and replacing them
« Reply #8 on: February 18, 2016, 11:58:43 AM »
Thank you !

Tharwat

  • Swamp Rat
  • Posts: 710
  • Hypersensitive
Re: Erase blocks and replacing them
« Reply #9 on: February 18, 2016, 12:00:51 PM »