How to remove objects from a drawing
I have several objects on a DWG drawing that I want to delete when I load the drawing. It is a single block that is in one specific layer and used all over the drawing.
So what I want is some way to check if an object on screen is this specific one and remove it. I couldn't find any examples for this. I only found one example that loops through all objects on screen and I was able to detect the ones I want to remove, but how to remove them? I tried several things but nothing worked.
This is the program code I tried:
So what I want is some way to check if an object on screen is this specific one and remove it. I couldn't find any examples for this. I only found one example that loops through all objects on screen and I was able to detect the ones I want to remove, but how to remove them? I tried several things but nothing worked.
This is the program code I tried:
void deleteObjects()
{
AcDbBlockReference* pBlockRef;
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
// Get the current space object
AcDbBlockTableRecord* pBlockTableRecord;
Acad::ErrorStatus es = acdbOpenObject(pBlockTableRecord, pDb->currentSpaceId(), AcDb::kForRead);
// Create a new block iterator that will be used to step through each object in the current space
AcDbBlockTableRecordIterator* pItr;
pBlockTableRecord->newIterator(pItr);
// Create a variable AcDbEntity type which is a generic object to represent a Line, Circle, Arc, among other objects
AcDbEntity* pEnt;
// Step through each object in the current space
for (pItr->start(); !pItr->done(); pItr->step())
{
// Get the entity and open it for read
pItr->getEntity(pEnt, AcDb::kForRead); // I tried to put kForWrite here instead but that crashed the program instead
TCHAR* layerName = pEnt->layer();
// Check if entity is on the layer we want
if (_tcscmp(layerName, LAYERSTR_OFFSET) == 0)
{
// This works so that when I am here it is for one of the objects I want to remove
pEnt->erase(); // This doesn't work so it wasn't that easy
/*
// I tried the following code to see if that helped but no result
pBlockRef = AcDbBlockReference::cast(pEnt);
bool bBlockFound = (pBlockRef != NULL);
if (bBlockFound)
{
pBlockRef->erase();
}*/
}
pEnt->close();
}
// Close the current space object
pBlockTableRecord->close();
// Remove the block iterator object from memory
delete pItr;
}
{
AcDbBlockReference* pBlockRef;
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
// Get the current space object
AcDbBlockTableRecord* pBlockTableRecord;
Acad::ErrorStatus es = acdbOpenObject(pBlockTableRecord, pDb->currentSpaceId(), AcDb::kForRead);
// Create a new block iterator that will be used to step through each object in the current space
AcDbBlockTableRecordIterator* pItr;
pBlockTableRecord->newIterator(pItr);
// Create a variable AcDbEntity type which is a generic object to represent a Line, Circle, Arc, among other objects
AcDbEntity* pEnt;
// Step through each object in the current space
for (pItr->start(); !pItr->done(); pItr->step())
{
// Get the entity and open it for read
pItr->getEntity(pEnt, AcDb::kForRead); // I tried to put kForWrite here instead but that crashed the program instead
TCHAR* layerName = pEnt->layer();
// Check if entity is on the layer we want
if (_tcscmp(layerName, LAYERSTR_OFFSET) == 0)
{
// This works so that when I am here it is for one of the objects I want to remove
pEnt->erase(); // This doesn't work so it wasn't that easy
/*
// I tried the following code to see if that helped but no result
pBlockRef = AcDbBlockReference::cast(pEnt);
bool bBlockFound = (pBlockRef != NULL);
if (bBlockFound)
{
pBlockRef->erase();
}*/
}
pEnt->close();
}
// Close the current space object
pBlockTableRecord->close();
// Remove the block iterator object from memory
delete pItr;
}
0
Comments
-
If you're open to LISP, then this is an easy thing to do.
(ssget "X" '((0 . "INSERT")(2 . "BLOCK_NAME")(8 . "BLOCK_LAYER")))
Will create a selection set of all the blocks called "BLOCK_NAME" on the the drawing that are on the layer "BLOCK_LAYER".
You can use this to build a function to delete the blocks(defun DeleteBlocks ( / sset odoc ent num) (setq sset (ssget "X" '((0 . "INSERT")(2 . "BLOCK_NAME")(8 . "BLOCK_LAYER")))) (cond (sset (princ (strcat "\nFound " (itoa (sslength sset)) " Blocks to delete")) (setq odoc (vla-get-activedocument (vlax-get-acad-object))) ; retrieve active document (vla-endundomark odoc) (vla-startundomark odoc) ; set undo mark (setq num 0) (foreach ent (vle-selectionset->list sset) (if (entdel ent) (setq num (1+ num))) ) (vla-endundomark odoc) (princ (strcat "\nDeleted " (itoa num) " Blocks\n")) ) (T (Princ "\nBlock not found.\n")) ) num )
You add a call to this function in your on_doc_load.lsp to run automatically each time a drawing file is opened.
Regards,
Jason Bourhill
BricsCAD V22 Ultimate
CAD Concepts
0 -
The purge command would permit you to select a specific block. Below would be the sequence of commands to use, with what I type in bold capitals. This example would purge all blocks named "door".
PURGE
Purge: BAtch/All/Blocks/Dimstyles/LAyers/LTypes/MAterials/MLinestyles/Plotstyles/STyles/Tablestyles/Visualstyles/Regapps: BLOCK
Enter name(s) to purge <*>: DOOR <-TYPE THE NAME OF THE BLOCK</i>
Verify each name to be purged? [Yes/No] : N
:
So, you could create a macro that you could manually run. Or if you wanted it to run automatically, then either save as a script, that you run from the startup lisp. Or even just use the command feature of LISP to send those commands.
-Joe0 -
I have never done anything with LISP, but this code needs to be inside the C++ application so it must be in C++ code. I just want to remove all objects of a specific block from the drawing and it must be some way to do it?0
-
While sending keystrokes is not generally the best way to do things, just sending the keystrokes as though you were typing at a keyboard is one way to do it. Though I don't know if there is a way to get the program to run when a drawing opens, other than putting a command to load the C program inside the startup lisp file.
-Joe0 -
I found some examples using the acedSSGet function and that worked better. The following code almost works. It works first time I tries it, but if I open a new drawing it gives error "corrupt drawing, error in database" and with the debugger I can see that it is the acedSSGet command that crash, but why?ads_name pName;
struct resbuf eb;
TCHAR sbuf[100];
eb.restype = 8; // Layer name filter
_tcscpy(sbuf, LAYERSTR_OFFSET);
eb.resval.rstring = sbuf;
eb.rbnext = NULL;
acedSSGet(_T("X"), NULL, NULL, &eb, pName); // Retrieve all entities on layer
long number = 0;
if ((acedSSLength(pName, &number) != RTNORM) || (number == 0))
{
acedSSFree(pName);
}
ads_name ent;
AcDbObjectId id = AcDbObjectId::kNull;
// Open to delete
for (long i = 0; i < number; i++)
{
acedSSName(pName, i, ent) != RTNORM;
acdbGetObjectId(id, ent);
AcDbEntity* pEnt = NULL;
acdbOpenAcDbEntity(pEnt, id, AcDb::kForWrite);
pEnt->erase();
pEnt->close();
}
acedSSFree(pName);0 -
I removed everything so only this code is active and is triggered after a dwg file is loadedads_name pName = { 0,0 };
acedSSGet(NULL, NULL, NULL, NULL, pName);
acedSSFree(pName);
It still gives error. First time I load a drawing it works, but when I close the drawing and open it again (or another) it gives error that file is corrupt and database error.0 -
I got the first version working. I just had to change the entity from read to write with "pEnt->upgradeOpen();" command and after that I could do erase on it, but why the second example isn't working is another thing.0