Author Topic: Problem with hatch inside a block  (Read 5041 times)

0 Members and 1 Guest are viewing this topic.

gregi

  • Mosquito
  • Posts: 4
Problem with hatch inside a block
« on: December 21, 2014, 12:25:42 PM »
Hi all!

I am a new guy in TheSwamp and .Net (it is my choice to migrate from the old one, preety good, damn Lisp :) ).

Now, I am at the moment of trying to apply some simple apps in C#. I have a very big problem in a simple (such I thought) task:
- create in Autocad database block definition which consists:
  • Closed polyline in shape like an arrow.
  • Solid hatch in the arrowhead region.

Creating block definition with a closed polyline is rather simple, but when I am trying to add solid hatch -> the Visual Studio Debugger throws me an exception at line 54 (when I want to oHatch.AppendLoop ) of the presented code: Additional information: eInvalidInput

I am sure that error is a result of my lack of Autocad .NET knowledge so I please you - is there anyone who can show me my bug?

Additional informations: Autocad 2015, VS 2013, .NET Framework 4.5.

Code - C#: [Select]
  1.         [CommandMethod("CreateArrowBlock")]
  2.         static public void CreateArrowBlock()
  3.         {
  4.             // Get the current database and start a transaction
  5.             Database acCurDb;
  6.             acCurDb = Application.DocumentManager.MdiActiveDocument.Database;
  7.  
  8.             using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
  9.             {
  10.                 // Open the Block table for read
  11.                 BlockTable acBlkTbl;
  12.                 acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
  13.  
  14.  
  15.                 if (!acBlkTbl.Has("Arrow"))
  16.                 {
  17.                     using (BlockTableRecord acBlkTblRec = new BlockTableRecord())
  18.                     {
  19.                         acBlkTblRec.Name = "Arrow";
  20.  
  21.                         // Set the insertion point for the block
  22.                         acBlkTblRec.Origin = new Point3d(0, 0, 0);
  23.  
  24.                         // Add a circle to the block
  25.                         using (Polyline plBox = new Polyline())
  26.                         {
  27.                             plBox.Normal = Vector3d.ZAxis;
  28.  
  29.                             Point2d pt0 = new Point2d(0.0, 0.0);
  30.                             Point2d pt1 = PolarPoints(pt0, 0, 7.5, "d");
  31.                             Point2d pt2 = PolarPoints(pt1, 150.0, 1.0, "d");
  32.                             Point2d pt3 = new Point2d(10.0, 0.0);
  33.                             Point2d pt4 = new Point2d(pt2.X, -pt2.Y);
  34.                             plBox.AddVertexAt(0, pt0, 0.0, 0.0, 0.0);
  35.                             plBox.AddVertexAt(1, pt1, 0.0, 0.0, 0.0);
  36.                             plBox.AddVertexAt(2, pt2, 0.0, 0.0, 0.0);
  37.                             plBox.AddVertexAt(3, pt3, 0.0, 0.0, 0.0);
  38.                             plBox.AddVertexAt(4, pt4, 0.0, 0.0, 0.0);
  39.                             plBox.AddVertexAt(5, pt1, 0.0, 0.0, 0.0);
  40.                             plBox.Closed = true;
  41.  
  42.                             ObjectId pLineId;
  43.                             pLineId = acBlkTblRec.AppendEntity(plBox);
  44.  
  45.                             ObjectIdCollection ObjIds = new ObjectIdCollection();
  46.                             ObjIds.Add(pLineId);
  47.  
  48.                             using (Hatch oHatch = new Hatch())
  49.                             {
  50.                                 Vector3d normal = new Vector3d(0.0, 0.0, 1.0);
  51.                                 oHatch.Normal = normal;
  52.                                 oHatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
  53.  
  54.                                 oHatch.AppendLoop((int)HatchLoopTypes.Default, ObjIds);
  55.                                 oHatch.EvaluateHatch(true);
  56.  
  57.                                 acBlkTblRec.AppendEntity(oHatch);
  58.                             }
  59.  
  60.                             acBlkTbl.UpgradeOpen();
  61.                             acBlkTbl.Add(acBlkTblRec);
  62.                             acTrans.AddNewlyCreatedDBObject(acBlkTblRec, true);
  63.                         }
  64.                     }
  65.                 }
  66.  
  67.                 // Save the new object to the database
  68.                 acTrans.Commit();
  69.             }
  70.         }
  71.  

robaCAD

  • Guest
Re: Problem with hatch inside a block
« Reply #1 on: February 03, 2015, 07:43:18 AM »
Hello, I have exactly the same problem. ^-^
I want to write a hatch in a block.
 
How do I create the hatch to you then insert into the block added.

Have since found a solution?

Since the hatch is already in the database there,
I can not insert the block?



n.yuan

  • Bull Frog
  • Posts: 348
Re: Problem with hatch inside a block
« Reply #2 on: February 03, 2015, 11:21:02 AM »
The Hatch.AppedLoop(HatchLoopTypes, ObjectIdCollection) method requires that the loop entities have valid ObjectId. That means that the entities that can be used as hatch's loops must belong to a BlockTableRecord and Database-residing.

So, the problem in your code is that even the polyline has been appended to the new BlockTableRecord, but before the new BlockTableRecord is added to BlockTable, the new BlockTableRecord is not database-residing, thus, its ObjectId is null, in turn the entities in the BlockTableRecord (the polyline) also has a null ObjectId. That is why the call to Hatch.AppendLoop() raises eInvalidInput exception.

Because Hatch's creation depends on database-residing entities as its loop, you cannot create it as your code shows before the new BlockTableRecord is added into BlockTable. So, you need to create the BlockTableRecord without hatch first, and then open the BlockTableRecord to modify it to add Hatch.

In this case, I'd rather do this similarly to what we do manually in AutoCAD: create (or select) existing entities in drawing (say, in ModelSpace), and use them to create a new BlockTableRecord, and then erase the existing entities (as an optional step). Here is the code that successfully creates a block definition with a hatched square:

Code: [Select]
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(CreateHatchedBlock.MyCadCommands))]

namespace CreateHatchedBlock
{
    public class MyCadCommands
    {
        [CommandMethod("HatchedBlock")]
        public static void CreateHatchedBlock()
        {
            Document dwg = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;

            //Create entities and get a available block name
            ObjectId plId = ObjectId.Null;
            ObjectId htId = ObjectId.Null;
            string blkName = null;

            using (var tran = dwg.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tran.GetObject(
                    dwg.Database.BlockTableId, OpenMode.ForRead);
                blkName = GetNewBlockName(bt);

                BlockTableRecord model = (BlockTableRecord)tran.GetObject(
                    SymbolUtilityServices.GetBlockModelSpaceId(dwg.Database),
                    OpenMode.ForWrite);

                Polyline pl = CreateClosedPolyline();

                plId = model.AppendEntity(pl);
                tran.AddNewlyCreatedDBObject(pl, true);

                Hatch hatch = CreateHatch(
                    new ObjectIdCollection(
                        new ObjectId[] { plId }));

                htId = model.AppendEntity(hatch);
                tran.AddNewlyCreatedDBObject(hatch, true);

                tran.Commit();
            }

            //Create BlockTableRecord based on the 2 entities
            ObjectId[] ids = new ObjectId[] { plId, htId };
            CreateBlockDefinitionBasedOnExistingEntities(
                dwg.Database, blkName, ids, true); 
        }

        private static Polyline CreateClosedPolyline()
        {
            Polyline pl = new Polyline(4);
            pl.AddVertexAt(0, new Point2d(0.0, 0.0), 0.0, 0.0, 0.0);
            pl.AddVertexAt(1, new Point2d(4.0, 0.0), 0.0, 0.0, 0.0);
            pl.AddVertexAt(2, new Point2d(4.0, 4.0), 0.0, 0.0, 0.0);
            pl.AddVertexAt(3, new Point2d(0.0, 4.0), 0.0, 0.0, 0.0);

            pl.Closed = true;

            return pl;
        }

        private static Hatch CreateHatch(ObjectIdCollection loopIds)
        {
            Hatch ha = new Hatch();
            ha.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
            ha.Normal = Vector3d.ZAxis;

            ha.AppendLoop(HatchLoopTypes.Default, loopIds);
            ha.EvaluateHatch(true);

            return ha;
        }

        private static string GetNewBlockName(BlockTable bt)
        {
            int i = 0;
            string name = "TestBlock" + i;

            while(bt.Has(name))
            {
                i++;
                name = "TestBlock" + i;
            }

            return name;
        }

        private static void CreateBlockDefinitionBasedOnExistingEntities(
            Database db, string blkName,
            ObjectId[] ids, bool eraseEntities = false)
        {
            using (var tran = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tran.GetObject(
                    db.BlockTableId, OpenMode.ForWrite);

                BlockTableRecord br = new BlockTableRecord();
                br.Name = blkName;
                br.Origin = new Point3d(0.0, 0.0, 0.0);

                foreach (var id in ids)
                {
                    Entity ent = (Entity)tran.GetObject(id, OpenMode.ForRead);
                    br.AppendEntity(ent.Clone() as Entity);
                    if (eraseEntities)
                    {
                        ent.UpgradeOpen();
                        ent.Erase(true);
                    }
                }

                bt.Add(br);
                tran.AddNewlyCreatedDBObject(br, true);

                tran.Commit();
            }
        }
    }
}

robaCAD

  • Guest
Re: Problem with hatch inside a block
« Reply #3 on: February 05, 2015, 12:13:32 PM »
Hi, thanks for the help!
I immediately switched push it VB.NET (BricsCAD/Teigha) and it runs. :-) :-) :-) :-)
Then it should work in AutoCAD.


Additional informations: BricsCAD 2013   ;-), VS 2013, .NET Framework 4.5.

gregi

  • Mosquito
  • Posts: 4
Re: Problem with hatch inside a block
« Reply #4 on: February 07, 2015, 10:36:02 AM »
Thank you very much n.yuan - your solution works!