def _genNodesRoadBased(numNodes=None, boundingRegion=None, distToRoad=None, dataProvider=None, dataProviderArgs=None): """ Generate randomized node using Uniform distribution within a bounding area and close to roads Note ---- This function is an approximation, the error is getting larger when the location is closer to poles Parameters ---------- numNodes: int, Required Number of nodes to be generated boudingArea: list, Required A defined polygon, nodes are generated within this area distToRoad: float, Required The maximun distance to road for generated nodes. dataProvider: string, Conditional, default as None Specifies the data source to be used for generating nodes on a road network. See :ref:`Data Providers` for options and requirements. dataProviderArgs: dictionary, Conditional, default as None For some data providers, additional parameters are required (e.g., API keys or database names). See :ref:`Data Providers` for the additional arguments required for each supported data provider. Returns ------- list of lists A list of coordinates, within a given distance to its nearest street """ # Initialize locs = [] holes = [] goodLocs = [] # Generate nodes, if it is not close enough, discard and regenerate while (len(locs) < numNodes): newLocs = _genNodesUniformBounded(numNodes - len(locs), boundingRegion) goodLocs = [] for i in range(len(newLocs)): goodFlag = True for j in range(len(holes)): if (geoDistance2D(newLocs[i], holes[j][0]) < holes[j][1]): goodFlag = False break if (goodFlag): goodLocs.append(newLocs[i]) if (len(goodLocs) > 0): snapLocs = privGetSnapLocBatch(goodLocs, dataProvider, dataProviderArgs) for i in range(len(snapLocs)): dist = geoDistance2D(goodLocs[i], snapLocs[i]) if (dist > distToRoad): holes.append([goodLocs[i], dist - distToRoad]) else: locs.append(goodLocs[i]) return locs
def getSnapLocBatch(locs=None, dataProvider=None, dataProviderArgs=None): """ Snap multiple locations, each given by [lat, lon] coordinates, to their nearest locations on a road network. Parameters ---------- locs: list of lists, Required A list of GPS coordinates of node locations, in the form of [[lat, lon], [lat, lon], ...] dataProvider: string, Conditional, default as None Specifies the data source to be used for finding routes or generate nodes on a road network. See :ref:`Data Providers` for options and requirements of options. dataProviderArgs: dictionary, Conditional, default as None For some data provider, veroviz need some extra parameters such as API keys or database name. See :ref:`Data Providers` for the keys required for different data provider. Returns ------- list of lists A list of snapped locations in the format of [[lat, lon], [lat, lon], ...]. Note: Any altitude values provided as inputs in the `loc` parameter will be lost in the return. Example ------- Import veroviz and check if the version is up-to-date: >>> import veroviz as vrv >>> vrv.checkVersion() Also, import os so we can use environment variables for data provider API keys: >>> import os Snap a given list of location to their nearest streets: >>> locs = [ ... [42.00, -78.00], ... [42.10, -78.00], ... [42.20, -78.00]] >>> snapLocs = vrv.getSnapLocBatch( ... locs = locs, ... dataProvider = 'MapQuest', ... dataProviderArgs = {'APIkey': os.environ['MAPQUESTKEY']}) >>> snapLocs [[41.999401, -78.003876], [42.100021, -77.995549], [42.1993, -78.001011]] """ # validation [valFlag, errorMsg, warningMsg] = valGetSnapLocBatch(locs, dataProvider, dataProviderArgs) if (not valFlag): print(errorMsg) return elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""): print(warningMsg) snapLocs = privGetSnapLocBatch(locs, dataProvider, dataProviderArgs) return snapLocs
def _genNodesRoadBased(numNodes=None, boundingRegion=None, distToRoad=None, dataProvider=None, APIkey=None, databaseName=None): """ Generate randomized node using Uniform distribution within a bounding area and close to roads Note ---- This function is an approximation, the error is getting larger when the location is closer to poles Parameters ---------- numNodes: int, Required Number of nodes to be generated boudingArea: list, Required A defined polygon, nodes are generated within this area distToRoad: float, Required The maximun distance to road for generated nodes. dataProvider: string, Conditional, See :ref:`Dataprovider` Specifies the data source to be used for generating nodes on a road network. APIkey: string, Conditional, See :ref:`Dataprovider` Some data providers require an API key (which you'll need to register for). databaseName: string, Conditional, See :ref:`Dataprovider` If you are hosting a data provider on your local machine (e.g., pgRouting), you'll need to specify the name of the local database. Returns ------- list of lists A list of coordinates, within a given distance to its nearest street """ # Initialize locs = [] # Generate nodes, if it is not close enough, discard and regenerate while (len(locs) < numNodes): newLocs = _genNodesUniformBounded(numNodes - len(locs), boundingRegion) snapLocs = privGetSnapLocBatch(newLocs, dataProvider, APIkey, databaseName) for i in range(len(snapLocs)): if (geoDistance2D(newLocs[i], snapLocs[i]) <= distToRoad): locs.append(newLocs[i]) return locs
def privCreateNodesFromLocs(locs=None, initNodes=None, nodeType=None, nodeName=None, startNode=1, incrementName=False, incrementStart=1, snapToRoad=False, dataProvider=None, dataProviderArgs=None, leafletIconPrefix=VRV_DEFAULT_LEAFLETICONPREFIX, leafletIconType=VRV_DEFAULT_LEAFLETICONTYPE, leafletColor=VRV_DEFAULT_LEAFLETICONCOLOR, leafletIconText=None, cesiumIconType=VRV_DEFAULT_CESIUMICONTYPE, cesiumColor=VRV_DEFAULT_CESIUMICONCOLOR, cesiumIconText=None): """ Given a set of nodes lats and lons, return a node dataframe Parameters ---------- locs: list of lists, Required, default as None A list of locations, in the form of [[lat, lon, alt], [lat, lon, alt], ...] or [[lat, lon], [lat, lon], ...] initNodes: :ref:`Nodes`, Optional, default as None A dataframe containing an existing set of nodes. If `initNodes` is provided, this function will extend to that dataframe. nodeType: string, Optional, default as None A user-defined text field that can be used to classify nodes. This field is to categorize a batch of nodes (e.g., "restaurants"). If provided, all nodes generated by the `generateNodes()` function call will be given this value. The nodeType is not used by VeRoViz explicitly. nodeName: string, Optional, default as None The name of all nodes that are to be generated by this function call. This field is a more detailed description (e.g., "pizza" or "steakhouse"). The nodeName is not used by VeRoViz explicitly. startNode: int, Optional, default as 1 The starting node number will be the maximum of startNode and any id values contained in the initNodes dataframe (if provided). incrementName: boolean, Optional, default as False Toggle to choose if we add increment after nodeName, e.g. 'customer1', 'customer2',... incrementStart: int, Optional, default as 1 The starting number of the increment. leafletIconPrefix: string, Optional, default as "glyphicon" The collection of Leaflet icons. Options are "glyphicon" or "fa". See :ref:`Leaflet style` leafletIconType: string, Optional, default as "info-sign" The specific icon to be used for all generated nodes. The list of available options depends on the choice of the leafletIconType. See :ref:`Leaflet style` leafletColor: string, Optional, default as "blue" The icon color of the generated nodes when displayed in Leaflet. One of a collection of pre-specified colors. See :ref:`Leaflet style` leafletIconText: string, Optional, default as None Text that will be displayed within the node on a Leaflet map. See :ref:`Leaflet style` cesiumIconType: string, Optional, default as "pin" 'pin' is the only option right now. See :ref:`Cesium style` cesiumColor: string, Optional, default as "Cesium.Color.BLUE" The color of the generated nodes when displayed in Cesium. One of a collection of pre-specified colors. See :ref:`Cesium style` cesiumIconText: string, Optional, default as None Text that will be displayed within the node on a Cesium map. See :ref:`Cesium style` Return ------ :ref:`Nodes` A Nodes dataframe with given list of coordinates """ # Number of nodes numNodes = len(locs) # Define ids and nodeNames if (type(initNodes) is pd.core.frame.DataFrame): if (len(initNodes) > 0): maxID = max(initNodes['id']) startNode = max([maxID + 1, startNode]) ids = [n for n in range(startNode, startNode + numNodes)] if (incrementName): nodeNames = [(nodeName + "%s" % (n)) for n in range(incrementStart, incrementStart + numNodes)] else: nodeNames = [nodeName] * numNodes # Snap to road # FIXME! - Issue #28 - Multiple nodes might be snapped to the same location if (snapToRoad): locs = privGetSnapLocBatch(locs=locs, dataProvider=dataProvider, dataProviderArgs=dataProviderArgs) # node dataframe nodes = initDataframe('Nodes') # generate nodes dicLocs = locs2Dict(locs) for i in range(len(locs)): nodes = nodes.append( { 'id': ids[i], 'lat': dicLocs[i]['lat'], 'lon': dicLocs[i]['lon'], 'altMeters': dicLocs[i]['alt'], 'nodeName': nodeNames[i], 'nodeType': nodeType, 'leafletIconPrefix': leafletIconPrefix, 'leafletIconType': leafletIconType, 'leafletColor': leafletColor, 'leafletIconText': leafletIconText if (leafletIconText != None) else ids[i], 'cesiumIconType': cesiumIconType, 'cesiumColor': cesiumColor, 'cesiumIconText': cesiumIconText if (cesiumIconText != None) else ids[i] }, ignore_index=True) # if the user provided an initNode dataframe, add the new points after it if (type(initNodes) is pd.core.frame.DataFrame): nodes = pd.concat([initNodes, nodes], ignore_index=True) return nodes
def snapNodesToRoad(nodes=None, dataProvider=None, dataProviderArgs=None): """ Updates the locations of nodes within a dataframe, such that each node becomes located on a road network. Parameters ---------- nodes: :ref:`Nodes`, Required, default as None A :ref:`Nodes` dataframe containing an existing set of nodes. dataProvider: string, Conditional, default as None Specifies the data source to be used for generating nodes on a road network. See :ref:`Data Providers` for options and requirements. dataProviderArgs: dictionary, Conditional, default as None For some data providers, additional parameters are required (e.g., API keys or database names). See :ref:`Data Providers` for the additional arguments required for each supported data provider. Returns ------- :ref:`Nodes` dataframe A copy of the input `nodes` dataframe, with updated lat/lon values. Example ------- Import veroviz and check if the version is up-to-date: >>> import veroviz as vrv >>> vrv.checkVersion() Also, import os so we can use environment variables for data provider API keys: >>> import os Create a :ref:`Nodes` dataframe by :meth:`~veroviz.generateNodes.createNodesFromLocs` with two nodes that are off the road network: >>> exampleNodes = vrv.createNodesFromLocs( ... locs = [[42.80, -78.00], ... [42.81, -78.004]], ... leafletColor = 'red') These nodes are not aligned with the road network. The following examples demonstrate how to move the nodes to lat/lon locations that correspond to roads. >>> # Use OSRM as data provider >>> snappedNodes = vrv.snapNodesToRoad( ... nodes = exampleNodes, ... dataProvider = 'OSRM-online') Display the original (red) and OSRM-snapped (green) nodes to see the effects of snapping. >>> myMap = vrv.createLeaflet(nodes=exampleNodes, mapBackground='Stamen Toner') >>> myMap = vrv.createLeaflet(nodes=snappedNodesOSRM, mapObject=myMap) >>> myMap We can also use ORS, MapQuest, or pgRouting as the data source. In these cases, an API key or database name should be provided. >>> # Use MapQuest as data provider, and change node colors to purple: >>> snappedNodesMQ = vrv.snapNodesToRoad( ... nodes = exampleNodes, ... dataProvider = 'MapQuest', ... dataProviderArgs = { 'APIkey' : os.environ['MAPQUESTKEY']}) >>> snappedNodesMQ['leafletColor'] = 'purple' >>> # Add the MapQuest-snapped (purple) nodes to our map: >>> myMap = vrv.createLeaflet(nodes=snappedNodesMQ, mapObject=myMap) >>> myMap >>> # Use ORS as data provider, and change node colors to blue: >>> snappedNodesORS = vrv.snapNodesToRoad( ... nodes = exampleNodes, ... dataProvider = 'ORS-online', ... dataProviderArgs = {'APIkey': os.environ['ORSKEY']}) >>> snappedNodesORS['leafletColor'] = 'blue' >>> # Add the ORS-snapped (blue) nodes to our map: >>> myMap = vrv.createLeaflet(nodes=snappedNodesORS, mapObject=myMap) >>> myMap >>> # Use pgRouting as data provider, and change node colors to black: >>> snappedNodesPGR = vrv.snapNodesToRoad( ... nodes = exampleNodes, ... dataProvider = 'pgRouting', ... dataProviderArgs = {'databaseName': 'YOUR_DATABASENAME'}) >>> snappedNodesPGR['leafletColor'] = 'black' >>> # Add the pgRouting-snapped (black) nodes to our map: >>> myMap = vrv.createLeaflet(nodes=snappedNodesPGR, mapObject=myMap) >>> myMap """ # validation [valFlag, errorMsg, warningMsg] = valSnapNodesToRoad(nodes, dataProvider, dataProviderArgs) if (not valFlag): print(errorMsg) return elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""): print(warningMsg) # List of lat/lon before snapping locs = list(zip(nodes['lat'].tolist(), nodes['lon'].tolist())) snapNodes = nodes.copy() # Find list of snapped coordins snapLocs = privGetSnapLocBatch(locs, dataProvider, dataProviderArgs) # Make a copy of nodes and replace lat/lon columns withn snapped lat/lon snapNodes['lat'] = list(zip(*snapLocs))[0] snapNodes['lon'] = list(zip(*snapLocs))[1] return snapNodes