title: Creating a Solid Block from a Group of Lines in AutoCAD (C#)
body: <p>I'm trying to draw a solid 3D shape in AutoCAD programmatically. I can get the shape to draw as a wireframe. Here is what my code currently draws</p>
  
  <p><a href="https://i.stack.imgur.com/kAhTj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/kAhTj.png" alt="enter image description here"></a></p>
  
  <p>The object is a bunch of AutoCAD lines grouped together into a Group object. What I want is a method that takes a Group as an argument and turns that group into a solid blockreference. Here is my attempt at it.</p>
  
  <pre><code>public static void DefineBlockFromGroup(Group groupToCreateBlockFrom, string blockName, Point3d origin, bool replaceChosenEntities = false)
  {
      List&lt;ObjectId&gt; idsOfEntitiesInGroup = groupToCreateBlockFrom.GetAllEntityIds().ToList(); //Getting the entities that will be used to create the block
      CreateBlockDefinition(idsOfEntitiesInGroup, blockName, origin, replaceChosenEntities);
  }
  
  public static void CreateBlockDefinition(List&lt;ObjectId&gt; entities, string blockName, Point3d origin, bool replaceChosenEntities = false)
  {
      BlockTableRecord record = new BlockTableRecord(); //Will become record of new block type
      ObjectId blockId = ObjectId.Null; //Will become id of new block type
      using (Transaction tr = _database.TransactionManager.StartTransaction())
      using (DocumentLock docLock = _activeDocument.LockDocument())
      {
          BlockTable bt = (BlockTable)tr.GetObject(_database.BlockTableId, OpenMode.ForRead); //Getting block table to put new record in
          bt.UpgradeOpen();
          record = new BlockTableRecord(); //New record will contain all entities which will make up the block
          record.Name = blockName; //Setting name of the block
          record.Origin = origin; //Setting origin point of the block
          bt.Add(record);
          tr.AddNewlyCreatedDBObject(record, true);
          blockId = bt[record.Name];
  
          tr.Commit();
      }
  
      //copy the select entities to block by using deepclone.
      ObjectIdCollection collection = new ObjectIdCollection(entities.ToArray());
      IdMapping mapping = new IdMapping();
      _database.DeepCloneObjects(collection, blockId, mapping, false);
  
      if (replaceChosenEntities)
      {
          using (Transaction tr = _database.TransactionManager.StartTransaction())
          using (DocumentLock docLock = _activeDocument.LockDocument())
          {
              Entity baseEntity = tr.GetObject(entities[0], OpenMode.ForWrite) as Entity;
              foreach (ObjectId id in entities)
              {
                  EraseSingleObjectFromDrawingWithId(id);
              }
              DrawBlockFacingAPoint(record.Name, record.Origin, record.Origin, baseEntity.Layer, null);
              tr.Commit();
          }
      }
  }
  
  public static void EraseSingleObjectFromDrawingWithId(ObjectId idOfObjectToErase)
  {
      // Start a transaction
      using (Transaction tr = _database.TransactionManager.StartTransaction())
      {
          DBObject objToErase = tr.GetObject(idOfObjectToErase, OpenMode.ForWrite);
          // Check to make sure a valid SelectedObject object was returned
          if (objToErase != null)
          {
              objToErase.Erase();
          }
          tr.Commit();
      }
  }
  public static BlockReference DrawBlockFacingAPoint(string name, Point3d position, Point3d direction, string layerToInsertOn, List&lt;string&gt; attributeValues = null, Distance xScale = null, Distance yScale = null, Distance zScale = null)
  {
      LastPositionPoint = position;
      LastDirectionPoint = direction;
      //Creating default distances if null is passed for the scales
      if (xScale == null)
      {
          xScale = new Distance(DistanceType.Inch, 1);
      }
      if (yScale == null)
      {
          yScale = new Distance(DistanceType.Inch, 1);
      }
      if (zScale == null)
      {
          zScale = new Distance(DistanceType.Inch, 1);
      }
  
      ObjectId blkRecId = _generateBlockRecordId(name); //Generating ID for the block
      BlockReference blkRef = null; //Reference of the block that will be inserted
  
      using (Transaction tr = _database.TransactionManager.StartTransaction()) //Starting the transaction to insert the block into the drawing
      using (DocumentLock docLock = _activeDocument.LockDocument())
      {
          blkRef = new BlockReference(position, blkRecId); //Creating the block reference
          blkRef.SetDatabaseDefaults();
          blkRef.ScaleFactors = new Scale3d(xScale.Inches, yScale.Inches, zScale.Inches); //Changing the scales to what the programmer specifies
          blkRef.Layer = layerToInsertOn; //Assigning layer to draw the block on
          Point start = Point.MakePointWithInches(position.X, position.Y, position.Z); //Generating first AutoCAD point
          Point end = Point.MakePointWithInches(direction.X, direction.Y, direction.Z); //Generating second AutoCAD point
          GeometryClassLibrary.Line line = new GeometryClassLibrary.Line(start, end); //Creating a line to mirror a block over if necessary
          Angle a = new Angle(AngleType.Radian, 0); //Angle to rotate  the block by
  
          //Assigning angle based on direction point
          if (position.Y != direction.Y)
          {
              a = line.AngleBetween(GeometryClassLibrary.Line.XAxis);
          }
          if (direction.Y &lt; position.Y)
          {
              blkRef.Rotation = a.Negate().GetValue(AngleType.Radian); //Allowing for rotations beyond 180 degrees
          }
          else
          {
              blkRef.Rotation = a.GetValue(AngleType.Radian);
          }
  
          BlockTableRecord blkTblRec = tr.GetObject(_database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
          blkTblRec.AppendEntity(blkRef); //Adding block referece to the block table of the drawing
          tr.AddNewlyCreatedDBObject(blkRef, true); //Adding block to the drawing
  
          //Assigning attributes of the block
          BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead);
          int attCounter = 0; //Counter to iterate through attributes
          foreach (ObjectId objId in btr) //Checking each item in the BlockReference's records
          {
              DBObject obj = objId.GetObject(OpenMode.ForRead);
              if (obj is AttributeDefinition) //If the object is an attribute, update it.
              {
                  AttributeDefinition ad = obj as AttributeDefinition;
                  AttributeReference ar = new AttributeReference();
                  ar.SetAttributeFromBlock(ad, blkRef.BlockTransform);
                  ar.Position = ad.Position.TransformBy(blkRef.BlockTransform);
                  try
                  {
                      ar.TextString = attributeValues.ElementAt(attCounter);
                  }
                  catch (ArgumentNullException)
                  {
                      ar.TextString = "";
                  }
                  catch (ArgumentOutOfRangeException)
                  {
                      ar.TextString = "";
                  }
                  attCounter++;
                  blkRef.AttributeCollection.AppendAttribute(ar);
                  tr.AddNewlyCreatedDBObject(ar, true);
              }
          }
          tr.Commit();
          return blkRef;
      }
  }
  
  
  private static ObjectId _generateBlockRecordId(string passedBlockName)
  {
      Transaction tr = _database.TransactionManager.StartTransaction();
      DocumentLock docLock = _activeDocument.LockDocument();
      using (tr)
      using (docLock)
      {
          BlockTable blkTbl = tr.GetObject(_database.BlockTableId, OpenMode.ForRead) as BlockTable;
          ObjectId blkRecId = ObjectId.Null;
          if (blkTbl.Has(passedBlockName)) //Checking if the block exists
          {
              blkRecId = blkTbl[passedBlockName]; //If it does, getting the current id
          }
          else //If it doesn't exist create one
          {
              Database blkDb = new Database(false, true);
              blkDb.ReadDwgFile(passedBlockName + ".dwg", System.IO.FileShare.Read, true, ""); //Reading block source file
              _database.Insert(passedBlockName, blkDb, true);
              blkRecId = blkTbl[passedBlockName];
          }
          return blkRecId;
      }
  }
  </code></pre>
  
  <p>Sorry there's so many methods involved. I think the problem lies in actually drawing the block but I included all the involved methods just in case. Anyways, the methods succeed in creating a block definition and drawing an instance of that block in place of the group of lines. Problem is the block is still a wireframe. If anyone knows how to change this approach to draw solid blocks I will be wicked grateful!</p>