Тема: z координата AcDbFace объектов

Добрый день!
У меня есть сеть из AcDbFace объектов. Мне нужно с помошью линии выбрать объекты AcDbFace и получить набор 3д точек пересечения, при этом линия выбора может не попадать на узлы.
Подскадите, как проще получить z координату?

(изменено: Николай, 21 мая 2012г. 11:35:00)

Re: z координата AcDbFace объектов

я так понимаю что линия идет в плане, а AcDbFace трехмерные? и нужно получить срез по траектории?
если да, то:
1. разбиваешь face на треугольники (т.к. из 4 точек только три лежат в одной плоскости).
2. дальше в плане ищешь координату XY пересечения (с каджым треугольником независимо), а Z добываешь путем интерполяции исходя из изввесных вершин фейса.
3. клеишь в кучу все точки (достаточно упорядочить по длине от первой до последней точки по XY)
4. убить одинаковые точки, т.к. очень возможна ситуация, когда точки будут дублироваться :):):)
5. всё

Re: z координата AcDbFace объектов

Николай пишет:

а Z добываешь путем интерполяции исходя из изввесных вершин фейса.

Z можно получить только самостоятельно посчитав используя 3д координат вершин Файса и координаты точки пересечения с ребром, или есть уже готовый методы?

Re: z координата AcDbFace объектов

если я правильно понял задачу, то есть линия (возможно и 3d, хотя вероятней всего 2d(если пользователь клацает по экрану)), есть набор 3d фейсов. так о каком реальном пересечении вообще идет речь, если:
1. врядли все фейсы лежат в одной плоскости
2. врядли физическое пересечение есть вообще. на самом деле результат пересечения в общем случае фейса и отрезка - это точка или отрезок внутри фейса, а нужно построить красивый срез поверхности.

PS: да, только ручками, причем целиком всё ручками для каждого отдельно взятого фейса, а потом клеить всё в одну полилинию или что там нужно на выхлопе. единственное упрощение может быть, если выбрать "по траектории" только фейсы, над которыми проходит отрезок, а не крутить алгоритм через все фейсы слоя или чертежа.

Re: z координата AcDbFace объектов

Николай пишет:

а Z добываешь путем интерполяции исходя из изввесных вершин фейса.

Если метод intersectWith() вызывать у объекта AcDbFace (он содержит значения z), то выходной массив уже содержит z отметки.

Re: z координата AcDbFace объектов

отрезок и фейс лежат в разных плоскостях, о каком  intersectWith() идет речь?

PS:моё понимание задачи верно?

Re: z координата AcDbFace объектов

Николай пишет:

1. врядли все фейсы лежат в одной плоскости

Фейсы не лежат в одной плоскости.

Николай пишет:

то есть линия (возможно и 3d, хотя вероятней всего 2d

Совершенно верно, 2д.

Николай пишет:

врядли физическое пересечение есть вообще. на самом деле результат пересечения в общем случае фейса и отрезка - это точка или отрезок внутри фейса, а нужно построить красивый срез поверхности.

В 3д пересечение нет, но intersectWith() можно вызвать в плоскости AcGePlane::kXYPlane, тогда перечесение есть.

Re: z координата AcDbFace объектов

:) ну так откуда тогда возьмутся отметки Z, если пересечение идет в плоскости? только X,Y. а потом эту точку поднимать на фейс интерполяцией.
да, еще, врядли пользователь попадет точно в границу фейсов дважды (первой и последней точкой), так что все-равно как минимум две точки (ну вдруг захочется не отрезком а полилинией срез делать) будут лежать внутри фейсов или вообще где-то в стороне. так что от интерполяции никуда не убежать

Re: z координата AcDbFace объектов

Николай пишет:

ну так откуда тогда возьмутся отметки Z, если пересечение идет в плоскости?

Фрагмент документации:
The intersectWith() function is an overloaded function with two forms. The second form takes an additional argument, which is a projection plane for determining the apparent intersection of two entities.
Т.е. intersectWith проецирует объекты на заданую плоскость и в ней определяет пересечение. При указании AcGePlane::kXYPlane пересечение проверяется в плоскости ХУ, при этом в выходной массив тиочек пересечения записываются координаты точек в пространстве.
Если метод intersectWith вызвать для Файса, а не полилинии то мы получим точки с отметкой 3д. Это уже проверенно.
Но тогда встает другой вопрос, думаю очень простоя, но по скольку я плохо знаю ObjektARX прошу помоши...
Пользоватль проводит 2д полилинию. Для того что бы воспользоваться intersectWith надо получить массив Файсев, которые пересекаются (в плоскости ХУ) с полилинией (выбрать объекты с помошью линии).
После этого последовательно для всех файсов вызвать метод intersectWith и получить точки пересечения с полилинией (точки будут содержать z координату, именно из за нее метод вызывается для фейса, а не полилинии). Теперь надо отсеить повторяющиеся точки (можно на лету, что бы лишний раз не гонять массив точек).
После всего этого с массивом можно уже делать дальнейшую обработку.

У меня вопрос только в том, как проще получить массив Файсов пересекающейся с полилиние в плоскости ХУ.

Re: z координата AcDbFace объектов

acedSSGet(_T("_F"),...

Re: z координата AcDbFace объектов

Николай пишет:

acedSSGet(_T("_F"),...

Не получается, никаких изменений не происходит, подскажите где ошибка:

static void PetrPavlovv0_0_triang(void)
{
// пропускаю код создания Файсов

//Создаю массив точек для полилинии
AcGePoint3dArray points;
    points.append(AcGePoint3d(0.0, 25.0, 0.0));
    points.append(AcGePoint3d(80.0, 35.0, 0));
    points.append(AcGePoint3d(90.0, 22.0, 0.0));
    points.append(AcGePoint3d(120.0, 40.0, 0.0));
    points.append(AcGePoint3d(130.0, 15.0, 0.0));
    points.append(AcGePoint3d(195.0, 65.0, 0.0));
AcDbObjectId polylineId = createPolyLine(points); // строю полилинию

ads_name ent;  // переменная для имен выбранных объектов
struct resbuf *pointlist = ptsToResbuf(points); //форматирую точки для acedSSGet

acedSSGet(_T("_F"),pointlist, NULL, NULL, ent); // выбор примитивов


}


resbuf * Cv0_0App::ptsToResbuf( AcGePoint3dArray ptArray )
{
    resbuf* ptList = NULL;
    resbuf* lastRb = NULL;
    resbuf* rb = NULL;
    int len = ptArray.length();
    for (int i = 0; i < len; i++)
    {
        if ( (rb = acutNewRb(RT3DPOINT)) == NULL )
        {
            acutRelRb(ptList);
            return NULL;
        }
        rb->resval.rpoint[X] = ptArray.at(i).x;
        rb->resval.rpoint[Y] = ptArray.at(i).y;
        rb->resval.rpoint[Z] = ptArray.at(i).z;
        if (ptList == NULL)
        {
            ptList = rb;
            lastRb = rb;
        } 
        else
        {
            lastRb->rbnext = rb;
            lastRb = rb;
        }
    }
    lastRb->rbnext = NULL;
    return ptList;
}

Re: z координата AcDbFace объектов

если компиляция прошла успешно, то все остальное правильно. маленькие дополнения:
перед acedSSGet вставить для зумирования код (acedssget срабатывает корректно только для видимой области чертежа)

AcGePoint2d minPolylineBox, maxPolylineBox; // это минимальная и максимальная точка рамки, ограничивающей полилинию
acedCommand(RTSTR,_T("_ZOOM"),RTSTR,_T("_W"),RTPOINT,asDblArray(minPolylineBox),RTPOINT,asDblArray(maxPolylineBox),RTNONE);

после acedSSGet

acutRelRb(pointlist); // обязательно почистить буфер
long len = 0L;
acedSSLength(ent, &len);
acutPrintf(_T("\n%d объектов пересекает полилинию. ",len - 1); // -1, т.к. сама полилиния тоже попадает в пересечения

Re: z координата AcDbFace объектов

Непонятная ситуация.   

Если вызвать функцию выбора polyLineSel в команде (triang), в которой создаются файсы, то выбор не происходит, acedSSGet возвращает RTERROR или RTCAN, точнее не проверял. Если вызвать функцию выбора polyLineSel в другой команде, то все работает.

Так же если вызвать команду triang повторно, то создается еще три фейса, поверх предыдущих и выбирается три объекта, хотя фейсов уже 6. Если опять вызвать triang  то строиться еще три новых фейса (всего 9) и выбирается 6 старых объектов.

Это не проблема, все программа сама фейсы строить не будет, но интересно, почему так?
Код:

    // - PetrPavlovv0_0._triang command (do not rename)
    static void PetrPavlovv0_0_triang(void)
    {
        AcGePoint3d firstPt(10.0, 10.0, 0.0), secondPt(100.0, 40.0, 40.0), lastPt(120.0, 20.0, 60.0);
        AcGePoint3d firstPt2(130.0, 50.0, 2.0);
        AcGePoint3d firstPt3(180.0, 20.0, 9.0);

        create3DFace(secondPt, firstPt2, lastPt);
        create3DFace(firstPt2, lastPt, firstPt3);
        create3DFace(firstPt, secondPt, lastPt);

        AcGePoint3dArray points;
            points.append(AcGePoint3d(0.0, 25.0, 0.0));
            points.append(AcGePoint3d(80.0, 35.0, 0));
            points.append(AcGePoint3d(90.0, 22.0, 0.0));
            points.append(AcGePoint3d(120.0, 40.0, 0.0));
            points.append(AcGePoint3d(130.0, 15.0, 0.0));
            points.append(AcGePoint3d(195.0, 65.0, 0.0));

        ads_name ent;
        polyLineSel(points, &ent);
        acedSSFree(ent);
    }

AcDbObjectId Cv0_0App::create3DFace( const AcGePoint3d& firstPt, const AcGePoint3d& secondPt, const AcGePoint3d& lastPt)
{
    AcDbFace* pFace = new AcDbFace(firstPt, secondPt, lastPt);
    AcDbBlockTable *pBlockTable;
    acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable, AcDb::kForRead);
    AcDbBlockTableRecord *pBlockTableRecord;
    pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);
    pBlockTable->close();
    AcDbObjectId FaceId;
    pBlockTableRecord->appendAcDbEntity(FaceId, pFace);
    pBlockTableRecord->close();
    pFace->close();
    return FaceId;
}

void Cv0_0App::polyLineSel( AcGePoint3dArray ptArray, ads_name* name )
{
        struct resbuf *pointlist = ptsToResbuf(ptArray);

        struct resbuf filter, tmp;
        filter.restype = AcDb::kDxfStart;
        filter.resval.rstring = _T("3DFACE");
        tmp.restype = AcDb::kDxfLayerName;
        tmp.resval.rstring = _T("0");
        tmp.rbnext = NULL;
        filter.rbnext = &tmp;

        AcGePoint2d minPolylineBox, maxPolylineBox;
        acedCommand(RTSTR, _T("ZOOM"), RTSTR, _T("_W"), RTPOINT, asDblArray(minPolylineBox), RTPOINT, asDblArray(maxPolylineBox), RTNONE);

        switch (acedSSGet(_T("_F"),pointlist,NULL,&filter, *name))
        {
        case RTERROR :
        case RTCAN     :
            {
                acutPrintf(_T("\nУпс! Выбор отменен."));
                return;
            }
            break;
        }
        
        long len = 0L;
        int res = acedSSLength(*name, &len);
        if (res != RTNORM || len == 0) 
            {
                acutPrintf(_T("Ух! Объекты не выбраны.\n"));
                return;
            }
        acutPrintf(_T("\nВыбранно %d объектов"), len);
        if (pointlist != NULL) acutRelRb(pointlist);
}

(изменено: Николай, 6 июня 2012г. 13:54:28)

Re: z координата AcDbFace объектов

AcGePoint2d minPolylineBox, maxPolylineBox; // это минимальная и максимальная точка рамки, ограничивающей полилинию

а заполнять циферками это кто будет?

сейчас гляну что там не так и отпишусь.
-------------
всё работает, но
1. ZOOM нада поменять на _ZOOM (у меня именно с подчеркиванием. зачем у себя убрал. твой вариант будет работать ТОЛЬКО в английском автокаде, а мой в любой локализации)
2. перед зумированием нужно вставить

AcGePoint3d minPolylineBox, maxPolylineBox; 
minPolylineBox = maxPolylineBox = ptArray.first();
for (int i = 0; i < ptArray.length(); i++)
{
  if (ptArray.at(i).x < minPolylineBox.x) minPolylineBox.x = ptArray.at(i).x;
  if (ptArray.at(i).y < minPolylineBox.y) minPolylineBox.y = ptArray.at(i).y;
  if (ptArray.at(i).x > maxPolylineBox.x) maxPolylineBox.x = ptArray.at(i).x;
  if (ptArray.at(i).y > maxPolylineBox.y) maxPolylineBox.y = ptArray.at(i).y;
}

3. чуть не забыл

if (pointlist != NULL) acutRelRb(pointlist);

это лучше делать сразу после acedssget, а то у тебя есть аж 2 дырки в коде, которые приведут к утечке памяти
4. polyLineSel( AcGePoint3dArray ptArray, ads_name* name ). а зачем так через Ж... можно ж просто ads_name &name


PS: для понимания не достаточно поудалять мои комментарии из кода. их нужно еще осмыслить и сделать то, что в них написано.