Тема: Как организовать итерацию по базе?
Как организовать итерацию по базе с целью выборки определенных примитивов, например всех полилиний?
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → ObjectARX → Как организовать итерацию по базе?
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Как организовать итерацию по базе с целью выборки определенных примитивов, например всех полилиний?
> Draft_men
Есть несколько способов. Если стоит такая конкретная задача, то проще всего:
ads_name ss; resbuf *rb = acutBuildList(RTDXF0,"*POLYLINE",RTNONE); int rc = acedSSGet("_X",NULL,NULL,rb,ss); acutRelRb(rb); if (rc == RTNORM) { // В наборе ss только полилинии // При помощи acedSSLength() получаешь их количество // При помощи acedSSName() получаешь имя примитива полилинии }
Александр, а Вы не могли бы показать код, который пробегает по всей базе, выводит мена всех примитивов? Или хотя бы где его возможно увидеть.
И еще один вопрос: как я могу поменять параметры конкретно необходимого мне примитива, например линии или окружности? Опять же где возможно увидеть код.
Спасибо.
> Lanter
Запросто. Только чтобы я не занимался пустой тратой времени уточни:
1) что ты понимаешь под именем примитива?
2) что тебе известно о (цитирую) конкретно необходимого мне примитива, например линии или окружности - это должно быть или имя примитива (ads_name или AcDbObjectId) или метка примитива (группа 5 в DXF или AcDbHandle).
Ну а код как обычно нужно искать в ObjectARX SDK (или в Help'е, или в примерах).
Под именем примитива я понимаю AcDbObjectId.
На данный момент мне известно о примитиве следующее:
acedEntSel("\nУкажите объект: ", ent1, pt1); acdbGetObjectId(entId1, ent1); acdbOpenAcDbEntity(pEnt1, entId1, AcDb::kForWrite);
В данном случае я выбрал примитив мышкой.
Теперь я хочу изменить его параметры из командной строки;
(под параметрами понимаю линейные размеры, координаты, цвет и пр.)
Вопрос далее:
А если я например хочу найти в базе определнный примитив, то я буду искать его по его метке?
Соответственно в случае успеха я хочу также поменять его параметры.
Я рисую линию:
AcGePoint3d startPt(32,112.5,0); AcGePoint3d endPt(161.2,140.8,0); AcDbLine* pLine = new AcDbLine(startPt,endPt); pMS->appendAcDbEntity(pLine) pLine->close();
Теперь я закрою чертеж. После открытия чертежа я хочу найти в его базе эту линию и поменять ее лину и координаты.
И еще вопрос, каким образом я могу обрабатывать параметры примитива? Присвоить переменной значение функции наподбие GetParam() и обрабатывать то что есть в переменной?
Если да то какой тип переменной и какой функцией?
1) Вот пример команды, которая меняет цвет выбранного примитива при помощи командной строки:
static void ChangeColor(void) { ads_point p; ads_name ent; int nColor; if (acedEntSel("\nВыберите примитив для изменения цвета: ",ent,p) == RTNORM) { AcDbObjectId id; acdbGetObjectId(id,ent); AcDbObjectPointer<AcDbEntity> pEnt(id,AcDb::kForWrite); if (pEnt.openStatus() == Acad::eOk) { nColor = pEnt->colorIndex(); char buf[256]; sprintf(buf,"\nУкажите номер цвета (0...256) <%d>: ",nColor); acedInitGet(RSG_NONEG,NULL); if (acedGetInt(buf,&nColor) == RTNORM) { nColor = nColor % 257; // На всякий случай приводим к диапазону 0...256 pEnt->setColorIndex(nColor); } } } }
Так как понятие "цвета" есть у всех примитивов, то нет необходимости уточнять какой именно это примитив!
2) Вот команда, которая удлиняет выбранный отрезок в два раза (относительно середины отрезка):
static void Lengthen2(void) { ads_point p; ads_name ent; if (acedEntSel("\nВыберите отрезок для удлинения в два раза: ",ent,p) == RTNORM) { AcDbObjectId id; acdbGetObjectId(id,ent); AcDbObjectPointer<AcDbEntity> pEnt(id,AcDb::kForWrite); if (pEnt.openStatus() == Acad::eOk) { AcDbLine *pLine = AcDbLine::cast(pEnt.object()); // Приводим к отрезку if (!pLine) { acutPrintf("\nЭто не отрезок!"); return; } AcGeVector3d dir = pLine->startPoint() - pLine->endPoint(); pLine->setStartPoint(pLine->startPoint() + dir*0.5); pLine->setEndPoint (pLine->endPoint() - dir*0.5); } } }
В данном случае приходится выполнить приведение к отрезку (AcDbLine)
3) Для того, чтобы после закрытия и повторного открытия чертежа найти нужный примитив, ты должен знать его метку (группа DXF 5, AcDbHandle - значение AcDbObjectId не сохраняется между сеансами AutoCAD). Так что при добавлении примитива в базу ты должен его получить и где-то сохранить.
Для получения AcDbObjectId примитива (или объекта) по строке метки можно воспользоваться функцией:
//--------------------------------------------------------- // Функция по строке метки (handle) возвращает AcDbObjectId // объекта в текущем чертежее //--------------------------------------------------------- static AcDbObjectId GetObjectIdByHandleString(char *str) { AcDbHandle h(str); AcDbObjectId id = AcDbObjectId::kNull; acdbCurDwg()->getAcDbObjectId(id,false,h); return id; }
Вот пример ее использования:
static void GetObjectByHandle(void) { Acad::ErrorStatus es; char buf[1024]; if (acedGetString(FALSE,"\nУкажите метку примитива: ",buf) == RTNORM) { AcDbObjectId id = GetObjectIdByHandleString(buf); if (!id.isValid()) { acutPrintf("\nОбъекта с такой меткой в чертеже нет!"); return; } AcDbObjectPointer<AcDbObject> pObj(id,AcDb::kForRead); if ((es = pObj.openStatus()) != Acad::eOk) { acutPrintf("\nНе смогли открыть объект: %s",acadErrorStatusText(es)); return; } // По AcDbObjectId получаем строку - представление AcDbHandle pObj->objectId().handle().getIntoAsciiBuffer(buf); acutPrintf("\nName: %s id=%0X handle=%s",pObj->isA()->name(),pObj->objectId().asOldId(),buf); } }
И еще вопрос, каким образом я могу обрабатывать параметры примитива? Присвоить переменной значение функции наподбие GetParam() и обрабатывать то что есть в переменной?
Как это будет по-русски? :) Что такое параметры примитива? Есть понятие параметра кривой (AcDbCurve), но похоже речь не об этом. Увы, но я ничего не понял...
P.S.: Дальнейшие вопросы оформляйте отдельными темами - на этом форуме принято в каждой теме задавать только один вопрос.
Александр, спасибо за исчерпывающий ответ.
Извните за "нерусский". :)
Могу ля прбежаться по базе и выбрать все блоки не используя acedSSGet? Скажем, используя AcDbBlockTableIterator?
А как узнать, на что ссылается "record" в "block table" - на блок или скажем на *ModelSpace?
const char *pName; AcDbBlockTableIterator *pBTItr; if (pBlockTable->newIterator(pBTItr) == Acad::eOk) { while (!pBTItr->done()) { AcDbBlockTableRecord *pRecord; if (pBTItr->getRecord(pRecord, AcDb::kForRead) == Acad::eOk) { pRecord->getName(pName); acutPrintf("\nText is: %s",pName); pRecord->close(); } pBTItr->step(); } }
> Draft_men
*ModelSpace - это тоже блок, но имеющий особенный смысл.
А так можно проверить, что это обычный блок:
bool isUsualBlock = (!pRecord->isFromExternalReference() && !pRecord->isFromOverlayReference() && !pRecord->isLayout());
> Александр Ривилис
Однако все равно выдаёт мне блоки с непонятными именами *X11,*X12,*X13 и т.д.
P.S.: А еще если не нужны анонимные блоки, то:
!pRecord->isAnonymous();
Углубившись, понял, что заблудился ("чем дальше в лес - тем толще партизаны"). Мне показалось, или нет, что:
1)для того чтобы выбрать все блоки в "Model space", отделная функция!
2)для того чтобы выбрать все блоки в "Paper space", отделная функция!
Вопрс, а нелзя ли выбрать все болки одним махом?
> Draft_men
Не путай описание блоков (AcDbBlockTableRecord) со вставками блоков (AcDbBlockReference). Когда поймешь что именно тебе нужно получить (все имена блоков и их содержимое или все вставки всех блоков), только тогда "партизаны" покажутся худенькими и приветливыми. :)
Вопрос, а нелзя ли выбрать все болки одним махом?
Так что же ты собираешься выбирать?
Вставки блока, однозначно! Только они могут быть как в "model space" так и в "paper space".
Ок, с этим разобрался! )) Но, есть одно "но", но "всёж", что это за *X11,*X12,*X13- описания блоков??? (я так понимаю это штриховки)
Это не описания, а наименования "анонимных" блоков (все начинаются со звездочки). Они получаются при создании штриховок, размеров, таблиц и т.д., и кроме того ты сам можешь создавать анонимные блоки. Все они не видны в списке команды _INSERT.
Хорошо!!!
Значит, скачу я по базе, все очень волшебно, "аттрибуты" вокруг, "блоки" всякие, и все чудесно но...
Вот кусок кода, который выбирает: аттрибуты, определения аттрибутов и пару видов текста->
for (; !pBlockIterator->done(); pBlockIterator->step()) { pBlockIterator->getEntity(pEntity, AcDb::kForWrite); const char *pCname = pEntity->isA()->name(); //acutPrintf("class %s.\n",pCname); if ( pEntity->isA() == AcDbBlockReference::desc () ) { aBlkR = AcDbBlockReference::cast(pEntity); AcDbObjectIterator *objIterator; objIterator = aBlkR->attributeIterator(); for (objIterator->start(); !objIterator->done(); objIterator->step()) { AcDbAttribute *pAtt; aBlkR->openAttribute(pAtt,objIterator->objectId(),AcDb::kForWrite); AcDbObjectId styleId = NULL; char *pName = GetTextStyleName(pAtt->textStyle()); pAtt->setTextString(convertText(pAtt->textString())); pAtt->close(); } pEntity->close(); } else if ( pEntity->isA() == AcDbAttributeDefinition::desc () ) { aTtdef = AcDbAttributeDefinition::cast(pEntity); AcDbObjectId styleId = NULL; char *pName = GetTextStyleName(aTtdef->textStyle()); aTtdef->setTextString(convertText(aTtdef->textString())); aTtdef->close(); pEntity->close(); } else if ( pEntity->isA() == AcDbText::desc () ) { teXt = AcDbText::cast(pEntity); if (teXt != NULL) { AcDbObjectId styleId = NULL; char *pName = GetTextStyleName(teXt->textStyle()); //acutPrintf("\nStyle name: %s",pName); teXt->setTextString(convertText(teXt->textString())); } pEntity->close(); } else if ( pEntity->isA() == AcDbMText::desc () ) { MteXt = AcDbMText::cast(pEntity); if (MteXt != NULL) { AcDbObjectId styleId = NULL; char *pName = GetTextStyleName(MteXt->textStyle()); //acutPrintf("\nStyle name: %s",pName); MteXt->setContents(convertText(MteXt->contents())); } pEntity->close(); } else pEntity->close(); }
А мне еще надо выбрать все что связано с текстом в "деменшонах", а этож еще куча "ифов", можно ли как-то оптимизировать енто дело?
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → ObjectARX → Как организовать итерацию по базе?
Форум работает на PunBB, при поддержке Informer Technologies, Inc