Executing calculations by the road graph

Print Previous page Top page Next page

Python scripts can execute calculations by the road graph when preparing reports, processing events from various software and hardware, and solving information problems.

Function declarations for calculations by the road graph are contained in graphapi.py.

To execute calculations by the graph, it is necessary by using the GIS tools to build a road graph map with quality control (checking the connectivity of all elements).

For example, as part of solving logistic or social problems, it is necessary to calculate the shortest distances from a group of objects written on one map up to a group of objects from another map and prepare a report in CSV format. An example of the implementation of the task is contained in the base script mindist.py.

To build the shortest routes, first 2 maps (A and B) are selected with two groups of objects and semantics, containing object identifiers written into the report (for example: cadastral number, address, GUID, and so on).

The selection of maps and semantics is done in a dialog created by the tkinter component.

 

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

...

   # Form a list of semantics (attributes) by the first 100 map objects

   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

 

Since objects can contain both attributes, which are described in the classifier, and arbitrary properties of the form Field name : Value, then to select the necessary semantics, the list of semantics of map objects is built in the CollectSemNames function.

 

   # Find map - road graph

   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

 

The search for a road graph map is performed in the CollectMaps function using the MAPAPI sitapi.mapIsSiteGraph function, which checks the classifier and the presence on the map of objects of the Graph arc type.

 

  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

 

After selecting the initial data, an object of the GraphPathfinder class is created and the function for calculating routes and their lengths CalcMinDistances is called.

 

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

 

First, in the CollectData function, a list of object centers (if these are polygons or arcs) and semantics- object identifiers is formed.

 

   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)

 

For calculations by graph in the CalcThread function, a map of the road graph is opened (as a graph) by using the MAPAPI graphapi.onOpenNetEx function. Using the graphapi.onCreatePath method, a route is built using the coordinates of two points and its length is requested. At the same time, from the previously obtained points of the centers of objects, the shortest distance to the nearest arc of the graph is sought, and then a route is built along the arcs of the graph.

At the end of the calculation, the graph is closed by the graphapi.onCloseNet method.

The obtained distances, together with the identifiers of the source and output points, are written line by line into a CSV file.

To reduce the time of calculations, processing is performed in several threads with the division of lists of objects by threads.