Выполнение расчетов по графу дорог

Печать Предыдущая страница Стартовая страница Следующая страница

Скрипты на python могут выполнять расчеты по графу дорог при подготовке отчетов, обработке событий от различных программно-аппаратных средств, решении информационных задач.

Объявления функций для вычислений по графу дорог содержатся в graphapi.py.

Для выполнения расчетов по графу необходимо средствами ГИС построить карту графа дорог с контролем качества (проверкой связности всех элементов).

Например, необходимо в рамках решения логистических или социальных задач выполнить расчет кратчайших расстояний от группы объектов, записанных на одной карте, до группы объектов с другой карты и подготовить отчет в формате CSV. Пример реализации задачи содержится в базовом скрипте mindist.py.

Для построения кратчайших маршрутов сначала выбираются  2 карты (А и B) с двумя группами объектов и семантики, содержащие идентификаторы объектов, записываемые в отчет (например: кадастровый номер, адрес, GUID и так далее).

Выбор карт и семантик выполняется в диалоге, созданном средствами компонента tkinter.

 

def CalcMinDistances(hmap:maptype.HMAP, hobj:maptype.HOBJ) -> float:

...

   # Сформировать список видов семантик (атрибутов) по первым 100 объектам карты

   def CollectSemNames(hMap: maptype.HMAP, hSite: maptype.HSITE):

       semNames = []

       hObj = sitapi.mapCreateSiteObject(hMap,hSite)

       c = sitapi.mapGetSiteObjectCount(hMap,hSite)

       if c > 100: c = 100

       for i in range(0,c):

           if seekapi.mapReadObjectByNumber(hMap,hSite,hObj,1,i+1) == hObj:

               s = mapapi.mapSemanticAmount(hObj)

               for j in range(0,s):

                   _name = mapsyst.WTEXT(128)

                   mapapi.mapSemanticFullName(hObj, j+1, _name,_name.size())

                   namestr = _name.string()

                   if namestr not in semNames:

                       semNames.append(namestr)

       mapapi.mapFreeObject(hObj)

       return semNames

 

Поскольку объекты могут содержать как атрибуты, которые описаны в классификаторе, так и произвольные свойства вида Имя поля : Значение, то для выбора нужных семантик выполняется построение списка семантик объектов карт в функции CollectSemNames.

 

   # Найти карту - граф дорог

   def CollectMaps(hMap: maptype.HMAP):

       mapNames = []

       hSites   = []

       sitcount = sitapi.mapGetSiteCount(hMap)

       graph = 0

       for i in range(0,sitcount+1):

           hsite = sitapi.mapGetSiteIdent(hMap, i)

           if sitapi.mapIsSiteGraph(hMap, hsite) != 0:

               graph=hsite

               shortname = mapsyst.WTEXT(128)

               sitapi.mapGetSiteSheetNameUn(hMap,hsite,1,shortname,shortname.size())

               mapNames.append(shortname.string())

               hSites.append(hsite)

       return mapNames,hSites,graph

 

Поиск карты графа дорог выполняется в функции CollectMaps с помощью функции MAPAPI sitapi.mapIsSiteGraph, которая проверяет классификатор и наличие на карте объектов типа Дуга графа.

 

  def SetVars():

       ...

       graphPathfinder = GraphPathfinder(hmap,sitA,semFrom,sitB,semTo,sitGraph)

       processed = graphPathfinder.CalcMinDistances(outputFileName.name,16)

 

   ...

   mapapi.mapShowMessage(mapsyst.WTEXT("Обработано маршрутов:" + str(processed)), mapsyst.WTEXT('Подсчет длин маршрутов'))

   return processed

 

После выбора исходных данных выполняется создание объекта класса GraphPathfinder и вызов функции вычисления маршрутов и их длин CalcMinDistances.

 

class GraphPathfinder:

   ...

   def CollectData(self, hsite:maptype.HSITE, _semname:str):

       centers    = []

       seminfo    = []

       c = sitapi.mapGetSiteObjectCount(self.baseMap,hsite)

       hObj = sitapi.mapCreateSiteObject(self.baseMap,hsite)

       for i in range(0,c):

           isDeleted = seekapi.mapReadObjectByNumber(self.baseMap,hsite,hObj,1,i+1)

           if isDeleted != 1:

               x = ctypes.c_double(0)

               y = ctypes.c_double(0)

               if mapapi.mapGetObjectCenterEx(self.baseMap,hObj,ctypes.byref(x),ctypes.byref(y),1):

                   centers.append(maptype.DOUBLEPOINT(x,y))

               seminfo.append(self.SemanticValueByName(hObj,_semname))

       mapapi.mapFreeObject(hObj)

       return centers, seminfo

 

Сначала в функции CollectData формируется список центров объектов (если это полигоны или дуги) и семантик-идентификаторов объектов.

 

   def CalcThread(self, index, c_from, c_to):

        ...

        opennetparm = graphapi.OPENNETPARM()

      netGraph = graphapi.onOpenNetEx(self.baseMap, self.sitGraph, ctypes.byref(opennetparm))

        pathparam = graphapi.PATHPARM()

        for i in range(c_from,c_to):

            pathparam.Point1 = self.centersA[self.connections[i][0]]

            pathparam.Point2 = self.centersB[self.connections[i][1]]

            path = graphapi.onCreatePath(netGraph, ctypes.byref(pathparam))

            if path:

                length = graphapi.onGetPathLength(path)

            ...

        graphapi.onCloseNet(netGraph)

 

Для расчетов по графу в функции CalcThread открывается карта графа дорог (как граф) с помощью функции MAPAPI graphapi.onOpenNetEx. С помощью метода graphapi.onCreatePath по координатам двух точек строится маршрут и запрашивается его длина. При этом от ранее полученных точек центров объектов ищется кратчайшее растояние до ближайшей дуги графа и далее строится маршрут по дугам графа.

По окончании расчета граф закрывается методом graphapi.onCloseNet.

Полученные расстояния вместе с идентификаторами исходного и выходного пунктов записываются построчно в файл формата CSV.

Для сокращения времени выполнения расчетов выполняется обработка в нескольких потоках с разбиением списков объектов по потокам.