Выполнение расчетов по графу дорог |
Скрипты на 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. Для сокращения времени выполнения расчетов выполняется обработка в нескольких потоках с разбиением списков объектов по потокам.
|