На главную... Продукты | Технологии | Классификаторы | Проекты | Скачать | Цены| Форум | Статьи | Обучение | Контакты

Поиск составной линии пересечения площадных объектов

Поиск  Пользователи  Правила  Войти
Форум » Linux » Средства разработки ГИС-приложений для Linux
Страницы: 1
RSS
Поиск составной линии пересечения площадных объектов
 
Здравствуйте.
Используем ГИС Конструктор 13.0.0.5 под AstraLinux 1.6.
Необходимо определить береговую черту в заданном радиусе. Для этого строю площадной объект hCircle (красный круг), и ищу для него линии пересечения с объектами "Океаны и моря". Линии пересечения копируются в hLand.

Код
while(mapWhatObjectBySelect(h_gd, hObj, &frame, select, flag, PP_PLANE ))
    {
        flag = WO_NEXT;

        if(hObj)
        {
            excode = mapObjectExcode(hObj);

            if(excode == 31110000 )    //океаны и моря
            {
                //пересечение
                HCROSS hCross = mapCreateObjectsCross( hCircle, hObj, LOCAL_LINE, 0);

                if (hCross) //0 если нет пересечения или если ошибка
                {
                    HOBJ hIntersect = mapCreateSiteObject(h_gd, taskCoord);
                    mapRegisterObject(hIntersect, 221054733,LOCAL_LINE);

                    while( mapGetNextCross( hCross, hIntersect) ) //0 если ошибки
                    {
                        int cnt = mapPointCount( hIntersect, 0 );
                        if( cnt )
                        {
                            int subject(0);
                            if( mapPointCount( hLand, 0 ) ) subject = mapCreateSubject( hLand );    //если метрика объекта занята - создаем подобъект

                            for( int i = 1; i <= cnt; i++ )
                                mapAppendPointPlane( hLand, mapXPlane( hIntersect, i ), mapYPlane( hIntersect, i ), subject );
                        }
                    }
                    mapFreeObject( hIntersect );
                }
                mapFreeObjectsCross( hCross );
            }
        }
    }

Предполагается, что в случае, когда hCircle пересекает один объект в нескольких местах, за счет while(...) мы обрабатываем их все. Но на практике обрабатывается только первое пересечение, а для следующего mapGetNextCross() возвращает 0.

Как получить все линии пересечения?
 
http://public.gisinfo.ru/Forum/crossobject.png

Допустим есть 2 объекта - окружность и ломаная:
Код
.SIT   4.0 UTF8
P010   test
P003   service.rsc
P004   3857
.DAT   2 
.OBJ   5562   LIN
.KEY   4
9
-4246.949890   22037.655399   
-8176.963221   24213.953104   
-5979.536412   27615.738837   
-3275.011109   30425.909660   
-7648.735623   32348.658117   
-9740.516912   28735.581345   
-12360.525799   28756.710449   
-12106.976552   36384.316968   
-16353.926442   25249.279197   
.OBJ   5559   LIN
.KEY   5
19
-10691.326589   35691.233515   
-8753.174765   35349.485055   
-7048.792656   34365.459586   
-5783.753897   32857.845100   
-5110.640832   31008.482155   
-5110.640832   29040.431215   
-5783.753897   27191.068270   
-7048.792656   25683.453784   
-8753.174765   24699.428315   
-10691.326589   24357.679855   
-12629.478412   24699.428315   
-14333.860522   25683.453784   
-15598.899281   27191.068270   
-16272.012345   29040.431215   
-16272.012345   31008.482155   
-15598.899281   32857.845100   
-14333.860522   34365.459586   
-12629.478412   35349.485055   
-10691.326589   35691.233515   
.END
Это файл TXF.

И такой тест:

Код
  TEMPHOBJ info1 = mapCreateObject(hmap, 1, IDDOUBLE2, 0);
  PANASSERT(info1, TESTNAME);
  TEMPHOBJ info2 = mapCreateObject(hmap, 1, IDDOUBLE2, 0);
  PANASSERT(info2, TESTNAME);

  double result = 0;
  double length = 0;

  PANASSERT(mapReadObjectByKey(hmap, hmap, info1, 1, 5), TESTNAME);
  PANASSERT(mapReadObjectByKey(hmap, hmap, info2, 1, 4), TESTNAME);

  TEMPHCROSS hcross = mapCreateObjectsCross(info1, info2, LOCAL_LINE, 0.01);
  while (mapGetNextCross(hcross, hobj) != 0)
  {
    result++;
    double temp = mapLengthInMap(hobj);
    length += temp;
  }

  PANASSERT(result == 3, TESTNAME);
  PANASSERT(Compare(length, 28190.20509, 0.001) == 0, TESTNAME);

Окружность вырезает у ломаной 3 части, которые находятся внутри окружности. Возвращает 3 объекта.
Если разомкнуть окружность, то нарезка будет выдавать все части нарезанного объекта. В данном примере - 7 частей (3 внутри и 4 снаружи).

Для поиска точек пересечения есть, например, функция - mapCreateObjectCrossPointsEx
 
Oleg Belenkov,если честно, понятней не стало. У меня, насколько я могу судить, написано тоже самое.
Окружность пересекает ломанную в нескольких местах, это видно глазами. Но при этом
Код
while (mapGetNextCross(hcross, hobj) != 0)
после первого прохода возвращает 0.

Переформулирую вопрос: что не так в коде, который привел я?
 
В ответе на Ваш вопрос размещен рабочий тест с исходными данными.
Может в Вашем примере на вход функции передаются 2 одинаковых объекта или другая ошибка в логике.
 
Хорошо, проверим, есть ли ошибка в логике

Для проверки модифицируем функцию таким образом, чтобы из кода рисовался тестовый полигон, который будет пересекать круг.

Легенда:
- Красный - секущий круг
- Красный пунктир - линии пересечения
- Полигон с синими границами - тестовый полигон

Код
void getTestLineCrossCircle(MapView *mapview_)
{
    //имитация береговой черты
    HOBJ hPolygon = mapCreateSiteObject(mapview_->h_gd, mapview_->taskCoord);
    mapRegisterObject(hPolygon,131044100,LOCAL_SQUARE);
    mapAppendPointPlane(hPolygon,5110074, 6375971);
    mapAppendPointPlane(hPolygon,5159727, 6387064);
    mapAppendPointPlane(hPolygon,5129354, 6404760);
    mapAppendPointPlane(hPolygon,5147050, 6452300);
    mapAppendPointPlane(hPolygon,5103207, 6464185);
    mapAppendPointPlane(hPolygon,5119318, 6516480);
    mapAppendPointPlane(hPolygon,5072041, 6487691);
    mapAppendPointPlane(hPolygon,5110074, 6375971);
    mapCommit(hPolygon);
    mapFreeObject(hPolygon);

    //секущий круг
    HOBJ hCircle;
    hCircle = mapCreateSiteObject(mapview_->h_gd, mapview_->taskCoord);
    mapRegisterObject(hCircle,201053200,LOCAL_SQUARE);
    DOUBLEPOINT altCenter;
    altCenter.X = 5045102;  altCenter.Y = 6399477;
    mapBuildEllpse( hCircle, &altCenter/*&dpos*/, 100000/*radius*/, 100000/*radius*/, 0, 100);
    mapAppendPointPlane(hCircle, mapXPlane( hCircle, 1 ), mapYPlane( hCircle, 1 ));

    //объект для сохранения линий пересечения
    HOBJ hLand = mapCreateSiteObject(mapview_->h_gd, mapview_->taskCoord);
    mapRegisterObject(hLand, 221054733,LOCAL_LINE);

    int excode(0);
    int flag = WO_FIRST;
    HOBJ hObj = mapCreateSiteObject(mapview_->h_gd, mapview_->taskCoord);

    HSELECT select = mapCreateSiteSelectContext( mapview_->h_gd, mapview_->taskCoord ); //селект содержит все нарисованные элементы слоя
    mapSelectLocal( select, -1, 0);             //блок всех локализаций
    mapSelectLocal( select, LOCAL_SQUARE, 1);     //выбираем площадные объекты

    while(mapSeekSelectObject(mapview_->h_gd, hObj, select, flag))
    {
        flag = WO_NEXT;

        if(hObj)
        {
            excode = mapObjectExcode(hObj);

            if(excode == /*131044100*/31110000)    //131044100 - корона, 31110000 - океаны и моря
            {
                //пересечение
                HCROSS hCross = mapCreateObjectsCross( hCircle, hObj, LOCAL_LINE, 0);

                if (hCross) //0 если нет пересечения или если ошибка
                {
                    HOBJ hIntersect = mapCreateSiteObject(mapview_->h_gd, mapview_->taskCoord);
                    mapRegisterObject(hIntersect, 221054733,LOCAL_LINE);


                    while( mapGetNextCross( hCross, hIntersect) ) //0 если ошибки
                    {
                        int cnt = mapPointCount( hIntersect, 0 );
                        if( cnt )
                        {
                            int subject(0);
                            if( mapPointCount( hLand, 0 ) ) subject = mapCreateSubject( hLand );    //если метрика объекта занята - создаем подобъект

                            for( int i = 1; i <= cnt; i++ )
                                mapAppendPointPlane( hLand, mapXPlane( hIntersect, i ), mapYPlane( hIntersect, i ), subject );
                        }
                    }
                    mapFreeObject( hIntersect );
                }
                mapFreeObjectsCross( hCross );
            }
        }
    }

    mapDeleteSelectContext( select );
    mapCommit( hLand );
    mapFreeObject( hLand );

//    mapDeleteObject(hCircle);
    mapCommit( hCircle );
    mapFreeObject(hCircle);
    mapFreeObject( hObj );

    mapview_->dmap->UpdatePictureBorder();
}
В результате выполнения этого кода получим 3 линии пересечения, как и должно быть.

Далее, раскомментируем второй excode в строке:
Код
if(excode == /*131044100*/31110000)    //131044100 - корона, 31110000 - океаны и моря
В этом случае в качестве объекта, который режут, выступает полигон "Океаны и моря". В результате получаем только одну линию пересечения, хотя очевидно, что должна быть как минимум вторая в правом нижнем углу. Очевидно потому, что этот объект "Океаны и моря" выглядит вот так, если выделить его (QDMapView::SetObjSelected()).

Возможно, причина  - сложность полигона "Океаны и моря", он имеет полости, как видно на картинке.
Как бы то ни было, мне нужно получить все линии пересечения.
 
Цитата
Илья Аникин написал:
В этом случае в качестве объекта, который режут, выступает полигон "Океаны и моря". В  результате получаем  только одну линию пересечения, хотя очевидно, что должна быть как минимум вторая в правом нижнем углу. Очевидно потому, что этот объект "Океаны и моря"  выглядит вот так , если выделить его (QDMapView::SetObjSelected()).Возможно, причина  - сложность полигона "Океаны и моря", он имеет полости,  как видно на картинке .Как бы то ни было, мне нужно получить все линии пересечения.
Просьба прислать пример карты с двумя объектами для проверки.
Можно выслать на КБ Панорама <panorama@gisinfo.ru>

Спасибо!
 
По полученным данным можно сказать следующее.

Поскольку операция нарезки выполняется с полигоном (океаны и моря), то результатом является тоже полигон,
в котором содержатся сразу все части.

После операции нарезки для полученного объекта можно вызвать методы:
Код
// Установить признак мультиполигона, если есть внешние контура
mapSetMultiPolygonEx(hobj, 1, 1);

// Запросить число внешних контуров
int count = mapGetMultiSubjectCount(hobj);

// Выбрать внешние контура с подобъектами
for(int i = 1; i <= count; i++)
{
  mapReadCopyMultiSubject(hdest, hobj, i);
}
 

Здравствуйте!

Можно воспользоваться одним из следующих способов:
- преобразовать полученный объект в мультиполигон (доступно в ГИС Конструктор версии 14);
- перерегистровать тип объектов в линейный до выполнения нарезки.

Изменено: Константин Ганюшин - 10.09.2021 12:41:58
Страницы: 1
Читают тему (гостей: 1)



© КБ Панорама, 1991-2024

Регистрируясь или авторизуясь на форуме, Вы соглашаетесь с Политикой конфиденциальности