Author Topic: How many ways to insert ents into my current drawing form an external dwg file.  (Read 4930 times)

0 Members and 1 Guest are viewing this topic.

waterharbin

  • Guest
Hi.
Now I have a task to insert some entities form external dwg file to my current drawing. I have searched this forum. I find one here.
http://www.theswamp.org/index.php?topic=21853.msg264766#msg264766
This guy just clone the ents in the specified layers. But I need a further step: I want to specify the insert point in my current drawing by clicking my mouse.Then I heard that I can insert blocks.
There are two points:
(1) Import the blocks to the current drawing, if the blocks have already been imported, then do nothing.
(2) Specify the insert point by clicking the mouse, and I want the block's insert point to coincide with the mouse clicking point.
 I am trying some codes. But I get stucked. Here is what I get from a Chinese forum.
Code: [Select]
public ObjectId InsertDwg(string fileName, ref string blockName)
        {
            Editor se = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;

            try
            {
                if (fileName == "" || !File.Exists(fileName))
                {
                    se.WriteMessage("File not found");
                    return ObjectId.Null;
                }
                if (!fileName.ToLower().EndsWith(".dwg"))
                {
                    se.WriteMessage("Not dwg file");
                    return ObjectId.Null;
                }                   
            }
            catch (System.Exception ex)
            {
                se.WriteMessage(ex.StackTrace);
                return ObjectId.Null;
            }
            Database newDB = new Database(false, false);
            bool newDBHasDispose = false;
            try
            {
                Database myDb = HostApplicationServices.WorkingDatabase;

                if (blockName == "")
                {
                    FileInfo fileInfo = new FileInfo(fileName);
                    blockName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 4);
                }
                //newDB.ReadDwgFile(fileName, System.IO.FileShare.Read, true, fileName);
                newDB.ReadDwgFile(fileName, System.IO.FileShare.Read, true, null);
                if (newDB.Insbase.GetAsVector().Length > 0.00001)
                {
                    if (newDB.Insbase.X >= newDB.Extmin.X && newDB.Insbase.X <= newDB.Extmax.X
                      && newDB.Insbase.Y >= newDB.Extmin.Y && newDB.Insbase.Y <= newDB.Extmax.Y)
                    {
                        //Insbase位于图形范围,不进行移动,有可能不符合预期
                        return myDb.Insert(blockName, newDB, true);
                    }
                    else
                    {
                        if (newDB.Extmin.X > newDB.Extmax.X)
                        {
                            //图形范围Extmin Extmax未初始化,不进行移动,有可能不符合预期
                            return myDb.Insert(blockName, newDB, true);
                        }
                        else
                        {
                            Matrix3d tMat = Matrix3d.Displacement(newDB.Insbase.GetAsVector().Negate());
                            newDB.Insbase = Point3d.Origin;
                            ObjectId blockId = myDb.Insert(blockName, newDB, true);
                            if (0 >= newDB.Extmin.X && 0 <= newDB.Extmax.X && 0 >= newDB.Extmin.Y && 0 <= newDB.Extmax.Y)
                            {
                                //坐标原点位于图形范围,不进行移动,有可能不符合预期
                                return blockId;
                            }
                            else
                            {
                                //Insbase不位于图形范围 坐标原点也不位于图形范围,将图形从Insbase移到原点,有可能不符合预期
                                using(Transaction ctrans = myDb.TransactionManager.StartTransaction())
                                {
                                    BlockTableRecord cbtr = (BlockTableRecord)ctrans.GetObject(blockId, OpenMode.ForWrite);
                                    foreach (ObjectId tId in cbtr)
                                    {
                                        Entity ent = (Entity)ctrans.GetObject(tId, OpenMode.ForWrite);
                                        ent.TransformBy(tMat);
                                    }
                                    ctrans.Commit();
                                }
                                return blockId;
                            }
                        }

                    }
                }
                else
                {
                    //Insbase位于原点,不用做任何处理
                    [color=red]return myDb.Insert(blockName, newDB, true);         //An exception is thrown out here, exception message:eSelfReference[/color]                }
            }
            catch (System.Exception ex)
            {
                se.WriteMessage(ex.StackTrace + "\n" + ex.Message + "\n" + ex.TargetSite);
                return ObjectId.Null;
            }
            finally
            {
                if (!newDBHasDispose)
                    newDB.Dispose();
            }
        }
And this is the function I call the InsertDwg(string fileName, ref string blockName).
Code: [Select]
[CommandMethod("IB")]
        public void InsertBlock()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            try
            {
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                    //ImportBlock_DB("test.dwg", "sample");
                    string blockName = "sample"; InsertDwg("test.dwg", ref blockName);

                    trans.Commit();
                }
            }
            catch (System.Exception ex)
            {               
                ed.WriteMessage(ex.StackTrace + "\n" + ex.Message + "\n" + ex.TargetSite);
                return;
            }
                     
        }

My codes can be compiled successfully. But when I run the command, an runtime error occurred: a "eSelfReference" exception. I use AutoCAD2008.
Someone help!!

« Last Edit: April 02, 2013, 10:22:32 AM by 闻仲 »

WILL HATCH

  • Bull Frog
  • Posts: 450
A few things that stand out:

- you don't pass a complete file path to the subroutine so when it does the Database.ReadDwgFile() it won't be reading the file you are really after

- you only commit the transaction if the "if (newDB.Insbase.GetAsVector().Length > 0.00001)" statement results in true

- you don't check that blockName doesn't already exist in the destination drawing, not sure if it would throw an error for you

I personally don't use Database.Insert() very often, I prefer the Database.WblockCloneObjects() method

waterharbin

  • Guest
Hi,Will. For your comments:
--I past the absolute path:
Code: [Select]
string blockName = "sample"; InsertDwg("c:\\TestTwo.dwg", ref blockName);.
The result is the same.
--If the condition "if (newDB.Insbase.GetAsVector().Length > 0.00001)" if false, no need to commit. At least, I think so.
--I made the drawing myself, I can make sure the blockName do exist in my drawing. I put some common entities into a drawing as an archive, and I just want to insert these entities in my current drawing when i click the mouse.
The most important is that I am not good at coding, that is why I come here and ask for help. Haha, :-)

WILL HATCH

  • Bull Frog
  • Posts: 450
If you don't already have the ObjectARX SDK get it

Quote
Acad::ErrorStatus insert(
    AcDbObjectId& blockId,
    const ACHAR* pBlockName,
    AcDbDatabase* pDb,
    bool preserveSourceDatabase = true
);
Parameters
AcDbObjectId& blockId
Input object ID for the new block table record created by this function
const ACHAR* pBlockName
Input name to be used by the new block table record created by this function
AcDbDatabase* pDb
Input pointer to database to insert entities from
bool preserveSourceDatabase = true
Input to determine whether the source database pDb will be left intact
Description
This function mimics the AutoCAD INSERT command. First a new block table record is created in the database executing this function. This new block table record is given the name pointed to by pBlockName and the blockId argument is filled in with its object ID. Then, all the Model Space entities in the database pointed to by pDb are copied into the new block table record.

The preserveSourceDatabase argument determines whether the source database pDb is left intact or not. The default value of the argument is true. In that case, objects from the source database are copied to the destination database and the source database is not changed. If the caller passes false for this argument, objects from the source database could be physically moved into the destination database. The latter runs faster, but it leaves the source database dependent on the destination database. The caller should make sure that the source database is deleted either immediately or at least before the destination database is deleted.

When preserveSourceDatabase is false, the deep clone context is AcDb::kInsert during the cloning that occurs during AcDbDatabase::insert(). When preserveSourceDatabase is true, the deep clone context is AcDb::kInsertCopy during the cloning that occurs during AcDbDatabase::insert().

Returns Acad::eOk if operation is successful.

Returns Acad::eSelfReference (and does not complete the insert process) if the database pointed to by pDb contains a block table record with the name pBlockName, even if that block table record is not referenced by entities in the pDb Model Space. 


Does your source database also have a block named 'sample'?

waterharbin

  • Guest
Hi,Will
I don't use the SDK, I set the configuration manually.

Thanks for your helping.
Anyhow, I still found some code snippets come from other forums.
Here is one that can import blocks from external file.
Code: [Select]
public static ObjectId m_ImportBlock(string fileName, string blockName, bool bReplace)
        {
            ObjectId destId = m_GetBlockId(blockName);
            if (destId.IsNull)
            {
                using (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument())//记住一定要先锁定文档
                {
                    using (Database sourceDb = new Database(false, false))
                    {
                        sourceDb.ReadDwgFile(fileName.Trim(), FileShare.Read, true, null);
                        //destId = mCommands.m_db.Insert(blockName, sourceDb, false);//错误?!?!块自参照???!!!
                        destId = m_ImportBlock(sourceDb, blockName, bReplace);
                        sourceDb.CloseInput(true);
                    }
                }
            }
            return destId;
        }

public static ObjectId m_ImportBlock(Database sourceDb, string blockName, bool bReplace)
        {
            ObjectId destId = ObjectId.Null;
            using (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument())
            {
                using (Transaction sourceTr = sourceDb.TransactionManager.StartTransaction())
                {
                    BlockTable sourceBt = sourceTr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead) as BlockTable;
                    if (sourceBt.Has(blockName))
                    {
                        ObjectId sourceId = sourceBt[blockName];
                        IdMapping idMap = new IdMapping();
                        sourceDb.WblockCloneObjects(
                            new ObjectIdCollection(new ObjectId[] { sourceId }),
                            HostApplicationServices.WorkingDatabase.BlockTableId,
                            idMap,
                            bReplace == true ? DuplicateRecordCloning.Replace : DuplicateRecordCloning.MangleName,
                            false);
                        destId = idMap[sourceId].Value;
                    }
                    sourceTr.Commit();
                }
            }
            return destId;
        }

public static ObjectId m_GetBlockId(string BlockName)
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;

            ObjectId blockId = ObjectId.Null;
            using (Transaction m_tr = db.TransactionManager.StartTransaction())
            {
                BlockTable m_bt = (BlockTable)m_tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (m_bt.Has(BlockName)) blockId = m_bt[BlockName];
                //else
                //{
                //    MessageBox.Show(string.Format("指定块名\"{0}\"不存在!", BlockName));
                //}
                m_tr.Commit();
            }
            return blockId;
        }

Now, I am trying to specify the insert point to coincide with the blocks' insertpoint.
« Last Edit: April 03, 2013, 04:17:11 AM by 闻仲 »

WILL HATCH

  • Bull Frog
  • Posts: 450
I don't use the SDK, I set the configuration manually.
I think you may be misunderstanding, the ARX SDK includes all the documentation on the methods you are trying to use and often help solve problems
Quote
Now, I am trying to specify the insert point to coincide with the blocks' insertpoint.
I'm not quite sure what you mean here, but if you want to move the objects around inside the block definition then you'll have to do something like
Code - C#: [Select]
  1. Matrix3d transform = whatever you are wanting to do with these objects;
  2. foreach (ObjectId id in trans.GetObject(DestBlockTable[blockname],Openmode.ForWrite);
  3. {
  4.    Entity ent = trans.GetObject(id, OpenMode.ForWrite) as Entity;
  5.    if (ent!=null)
  6.    {
  7.       ent.TransformBy(transform);
  8.    }
  9. }

Otherwise if you are trying to specify the insertion point of a new blockreference then you'll need to add a bit of code creating the new reference.  There's plenty of that on here