def qEvent_elevation(dPack): """ Method caters for recording of change in gradient. dPack = { "tremb": ccTremb, # For full DB access. "db": cLine, # Database entries for the line. "dEntry": { # This parameter will be passed back "km":fDist, # kmilage marker "id":iHighest+1, # Unique reference number "item":None, # We need to fill this with our data "type":None, # We need to fill this with our data "xVal":None}, # We need to fill this with our data } """ dEntry = dPack["dEntry"] # Unpack the prototype sMenu = ("Please select the elevation event from the list\n") sMenu += "Select track event:\n" sMenu += "- [Comments not allowed here. Technical reasons]\n" sMenu += "1 Record spot height\n" sMenu += ("2 Trapezoidal change (_/TT\_). (!)" + " Req. All 4 pts in km seq. (!)\n") print(sMenu) sInput = input().upper() # COMMENT if sInput == "0": # Comment print("Comments not allowed for 'elevation events'") return None # SPOT ELEVATION if sInput == "1": #"dEntry":{"km":fDist,"id":0,"item":None,"type":None,"xVal":None}, dEntry["item"] = "elev_ft" dEntry["type"] = "spot" # Type of transaction sTxt = "Please enter spot elevation, (in ft), as an integer" iSpot = misc.get_int(sTxt, bNeg=True) dEntry["xVal"] = iSpot return dEntry # TRAPEZIODAL ELEVATION _/TT\_ if sInput == "2": #"dEntry":{"km":fDist,"id":0,"item":None,"type":None,"xVal":None}, dEntry["item"] = "elev_ft" dEntry["type"] = "trapezoid" # Type of transaction sTxt = ("Please enter the local change of elevation, (in ft), " + "as an integer.\n(Example '0' or '-20')") iSpot = misc.get_int(sTxt, bNeg=True) dEntry["xVal"] = iSpot return dEntry else: print("\n\aInvalid selection. Exiting") return None
def qEvent_crossing(dPack): """ This function builds up a piece of station for us. dPack = { "tremb": ccTremb, # For full DB access. "db": cLine, # Database entries for the line. "dEntry": { # This parameter will be passed back "km":fDist, # kmilage marker "id":iHighest+1, # Unique reference number "item":None, # We need to fill this with our data "type":None, # We need to fill this with our data "xVal":None}, # We need to fill this with our data } """ dEntry = dPack["dEntry"] # Unpack the prototype sMenu = ("Please select the station event from the list") sMenu += "Select track event:\n" sMenu += "0 Comment (record something unusual)\n" sMenu += "1 River (bridge or tunnel)\n" print(sMenu) sInput = input().upper() # COMMENT if sInput == "0": # Comment dEntry["item"] = "crossing" dEntry["type"] = "comment" # Type of transaction sTxt = "Please enter a comment regarding station" print(sTxt) dEntry["xVal"] = input() return dEntry # REGISTERED HOST if sInput == "1": #"dEntry":{"km":fDist,"id":0,"item":None,"type":None,"xVal":None}, dEntry["item"] = "crossing" dEntry["type"] = "river" # Type of transaction sTxt = "Please enter the name of the river being crossed:" print(sTxt) sName = input() sTxt = "Please enter approximate width of the river in integer meters" iWidth = misc.get_int(sTxt) if iWidth == None: return None xVal = { "sName": sName, "iWidth": iWidth, } dEntry["xVal"] = xVal return dEntry else: print("\n\aInvalid selection. Exiting") return None
def remove_sub_comp(ccTremb): """ Method prompts the user for data and returns distance on the map for the approach to the structure. """ # Request the line identifier sTxt = ("You are about to remove a component from a line.\nPlease enter " + "the K-code ('K00-001' for example) of the line\n") print(sTxt) sK_code = input().upper() # Verify the line number sRte_det = qVerify_line(sK_code, ccTremb) if sRte_det == None: return None # Ask for the identifier mark sTxt = ("Please enter the item identifier (id: 39 for example) as an " + "integer") iId_req = misc.get_int(sTxt) if iId_req == None: return None # Pull up the data you are about to delete: xParam = {"my_id": sK_code, "dVal.id": iId_req} xRestr = {"_id": 0, "dVal": 1} cDatabase = db.lines(ccTremb) dQuery = cDatabase.find(xParam, xRestr) dElement = [] for query in dQuery: dElement.append(query) print("\n-----------------------------") sTxt = ("You are about to remove\n\n{0}\n\nfrom {1}\n\n" + "Do you want to procceed?") sTxt = sTxt.format(dElement[0], sRte_det) yn_remove = misc.get_binary(sTxt) if yn_remove == None: return None if yn_remove == "N": print("\n\aAborting removal") return None # Remove the item xParam = {"my_id": sK_code, "dVal.id": iId_req} xRestr = {} dQuery = cDatabase.delete_one(xParam, xRestr) print("Specified element deleted")
def add_housing(ccTremb): """ Adds details of the housing to the database """ # Obtain the highest "my_id" code that is registered in the database. xParam = {} xRestr = {"_id": 0, "my_id": 1} cHousing = db.housing(ccTremb) dId_query = cHousing.find(xParam, xRestr) iHighest, aEvery_id = misc.find_highest_id(dId_query) if (False): # Debugging sTxt = "\n\nHighest number is {0}(10) < < < < < < < <" print(sTxt.format(iHighest)) # We do have the highest identifier (expressed as a decimal number). Hence, # we can incerement the sequence and use it. iNext_id = iHighest + 1 if iNext_id > 36**5: print("\n\aMaximum count has been exceeded") return None # Convert to base36 sBase36 = misc.base_conv(iNext_id) sBase36_5 = sBase36.rjust(5, "0") # "0002W" -> "D00-02W" sNew_id = "H{0}-{1}".format(sBase36_5[:2], sBase36_5[2:]) print("\nNext id is {0}".format(sNew_id)) # START GETTING THE USER TO ENTER THE NEW DATA. # Open a blank dictionary, so that the elements are arranged in a certain # order. dNew_housing = { "my_id": sNew_id, "host_geo_code": None, "aName": { "lat": None, "cyr": None }, # Is the block of flats named? "type": None, # Green(space), Res(idential) "sub_type": None, # house, lin apt, sq apt, x apt, irreg apt, "iUnits_per_floor": 0, # How many apartments in the block "iNo_of_floors": 1, # How tall is the building "iNo_of_buildings": 1, # How many buildings in the 'package' "iTot_units": 0, # Total households in this location "sDesc": "", # Description ex: "9x2x1M; 9 = 7+1S+1SP" "demographic": "", # 'r' to 'p' "aParking": { "iFloors": 1, # How many levels is parking offered on. "iVeh": 0, # Vehicles in total "map_a": 0, # sq.mm on the map per floor of the parking area. }, "aMap": { "sRegion": None, "iYear": None, "fScale": None, "x": None, "y": None, "a": None }, "aFpt_bldg": { "qty": None, "uom": None }, "aArea_plot": { "qty": None, "uom": None }, } # Automatically obtain the geo-code of the last entry. Chances are that we'd # like to re-use it. xParam = {} xRestr = {"_id": 0, "host_geo_code": 1} dId_query = cHousing.find(xParam, xRestr).sort("_id", 1) dId_query.sort("_id", -1) # Pull out the geo-code sGeo_code = dId_query[0]["host_geo_code"] cDest = db.destinations(ccTremb) dGeo_names = misc.verify_geo_code(sGeo_code, cDest) if dGeo_names == None: return None # An error has occured. # Names of the settlement. sP_lat = dGeo_names["lat"] sP_cyr = dGeo_names["cyr"] sTxt = "Are you working on {0} ({1} / {2})?" sTxt = sTxt.format(sGeo_code, sP_lat, sP_cyr) yn_last_host = misc.get_binary(sTxt) if yn_last_host == None: return None if yn_last_host == "N": # HOST sTxt = ("\nWho is hosting this residential area OR greenspace?\n" + "Please enter host's geo-code.") print(sTxt) sGeo_code = input().upper() dGeo_element = misc.get_geo_element(sGeo_code, cDest) if dGeo_element == None: return aHost_name = dGeo_element["aName"] dNew_housing["host_geo_code"] = sGeo_code sTxt = "\nHosted by {0} / {1}".format(aHost_name["lat"], aHost_name["cyr"]) print(sTxt) # TYPE sMenu = "\n" sMenu += "What type area is it?\n" sMenu += "0: Greenspace (Park)\n" sMenu += "1: Residential\n" iType_option = misc.get_int(sMenu, 1) if iType_option == None: print("\a") return None if iType_option == 0: dNew_housing["type"] = "Green" elif iType_option == 1: dNew_housing["type"] = "Res" else: print("\n\aInvalid choice for area type type") return # SUB-TYPE: if dNew_housing["type"] == "Res": # Residential: sMenu = "\n" sMenu += "Type of housing is it?\n" sMenu += "0: House: Free-standing building for 1 or 2 households\n" sMenu += "1: Apartments, Linear: Straight block of appartments\n" sMenu += "2: Apartments, Square: Square-edged Doughnut-shaped bldg\n" sMenu += "3: Apartments, Cross: Cross-shaped building\n" sMenu += "4: Apartments, Irregular: Irregularly-shaped building\n" sMenu += "5: Other: Something rare, or that doesn't fit above descr.\n" iType_option = misc.get_int(sMenu, 5) if iType_option == None: print("\a") return None if iType_option == 0: dNew_housing["sub_type"] = "house" elif iType_option == 1: dNew_housing["sub_type"] = "lin apt" elif iType_option == 2: dNew_housing["sub_type"] = "sq apt" elif iType_option == 3: dNew_housing["sub_type"] = "x apt" elif iType_option == 4: dNew_housing["sub_type"] = "irrg apt" elif iType_option == 5: dNew_housing["sub_type"] = "other" else: print("\n\aInvalid choice for port type") return # Greenspace was selected else: dNew_housing["sub_type"] == "N/A" # MAP REFERENCE sMap = "plot" dData = misc.get_map_input(ccTremb, sMap) # Asks for user to input stuff. if dData in [None, True]: # No map selected print("\n\aInvalid entry from the map. Exiting") return None # Transfer data through. dNew_housing["aMap"] = dData["dMap"] dNew_housing["aArea_plot"] = dData["dArea"] # BUILDING SIZE if dNew_housing["type"] == "Res" and dNew_housing["sub_type"] != "house": sTxt = "\nEnter the footprint of the building in sq.mm from map." fBldg_ftp = misc.get_float(sTxt) if fBldg_ftp == None: return None # Calculate area fScale = dNew_housing["aMap"]["fScale"] dNew_housing["aFpt_bldg"] = misc.calc_area(fBldg_ftp, fScale) # OPTIONAL NAME aName = misc.building_name() if aName == None: return None if aName != False: # False: if a name was not chosen dNew_housing["aName"] = aName # DEMOGRAPHICS: sMenu = "\n" sMenu += "Which demographic is residing here?\n" sMenu += "0: Rich [2500sq.m plot and up]\n" sMenu += "1: High-income [1600sq.m plot]\n" sMenu += "2: Mid-income [ 900sq.m plot]\n" sMenu += "3: Low-income [ 600sq.m plot]\n" sMenu += "4: Poor [ 400sq.m plot]\n" iLevel_option = misc.get_int(sMenu, 4) if iLevel_option == None: print("\a") return None if iLevel_option == 0: dNew_housing["demographic"] = "r" elif iLevel_option == 1: dNew_housing["demographic"] = "h" elif iLevel_option == 2: dNew_housing["demographic"] = "m" elif iLevel_option == 3: dNew_housing["demographic"] = "l" elif iLevel_option == 4: dNew_housing["demographic"] = "p" else: print("\n\aInvalid choice for port type") return # DESCRIPTION: sTxt = ("\nGive a brief description of the area. For example:\n" + "'(9x2)x1M [7+1S+1SP]': Seven units in a row, 1 from the side, " + "1 panhandle from\nside with two households sharing this building") print(sTxt) dNew_housing["sDesc"] = input() # BUILDING COUNT sTxt = ("\nHow many buildings in the group?") iNo_of_buildings = misc.get_int(sTxt) if iNo_of_buildings == None: return None dNew_housing["iNo_of_buildings"] = iNo_of_buildings # FLOOR COUNT sTxt = ("\nHow many floors does each building have?") iFloor_cnt = misc.get_int(sTxt) if iFloor_cnt == None: return None dNew_housing["iNo_of_floors"] = iFloor_cnt # APPARTMENT COUNT sTxt = ("\nHow many appartments per floor in this building?") iUnits_per_floor = misc.get_int(sTxt) if iUnits_per_floor == None: return None dNew_housing["iUnits_per_floor"] = iUnits_per_floor # TOTAL UNITS fTot_units = iNo_of_buildings * iFloor_cnt * iUnits_per_floor iTot_units = int(round(fTot_units, 0)) dNew_housing["iTot_units"] = iTot_units # PARKING: sMenu = "\n" sMenu += "How do you want to calculate car parking available?\n" sMenu += "0: Individual houses, with x number of cars per plot\n" sMenu += "1: Square footprint, with x and y known in mm.\n" sMenu += "2: Footprint, with area in sq.mm is known\n" iParking_option = misc.get_int(sMenu, 2) if iParking_option == None: return None iVeh = None # I publish the results of the parking. # INDIVIDUAL HOUSES if iParking_option == 0: sTxt = ("There are {0} plots in this area. Enter number of vehicles " + "per plot\nthat can be parked off the street. (Usually 2)") sTxt = sTxt.format(iNo_of_buildings) iVeh = misc.get_int(sTxt) if iVeh == None: return None iVeh *= iNo_of_buildings dNew_housing["aParking"]["iVeh"] = iVeh # SQUARE FOOTPRINT KNOWN SIDES elif iParking_option == 1: sTxt = ("Enter the first side of the area for parking") fParking_x = misc.get_float(sTxt) if fParking_x == None: return None sTxt = ( "Enter the second side of the area for parking, perpendicular" + " to the first") fParking_y = misc.get_float(sTxt) if fParking_y == None: return None # Calculate the parking area fMap_area = fParking_x * fParking_y fMap_scale = dNew_housing["aMap"]["fScale"] aParking_area = misc.calc_area(fMap_area, fMap_scale) if aParking_area == None: return None # We know the real-world scale of the parking. # In the real world, a parking bay is 5.5m x 2.5m (13.75sq.m). However, # each vehicle needs access to that bay. The above calcuation gives # 7.27veh/100sq.m. However, each vehilce needs some space to get to the # bay. Hence, I'm using the figure of 6 veh / 100sq.m (600veh/ha) # Verify the units of measurement if aParking_area["uom"] != "sq.m": print( "\nUnexpected calculation result for residential parking:\n" + "Expected 'sq.m', but got {0}\a".format(aParking_area["uom"])) return None fSqm_P = aParking_area["qty"] sTxt = ("On how many levels are cars parked?") iFloors = misc.get_int(sTxt) if iFloors == None: return None if iFloors > 1 and fSqm_P < 90: sTxt = ("\n\aInsufficient space for a ramp " + "(1:10 @ h = 3.6m, w = 2.5m). Exiting") return None if iFloors > 1: fSqm_P -= 90 # Take room for the ramp fVeh = 6.0 * fSqm_P / 100 # 6 cars per 100 sq.m print("fVeh:{0}; fSqm_P:{1}".format(fVeh, fSqm_P)) iVeh = int(round(fVeh, 0)) # Round off to whole vehicles fVeh = iVeh * iFloors # We need to round off per floor. iVeh = int(round(fVeh, 0)) # Round off to whole vehicles fVeh = iVeh * iNo_of_buildings # Parking in each building iVeh = int(round(fVeh, 0)) # Round off to whole vehicles dNew_housing["aParking"]["iFloors"] = iFloors dNew_housing["aParking"]["iVeh"] = iVeh dNew_housing["aParking"]["map_a"] = fMap_area # BASEMENT PARKING: FOOTPRINT AREA KNOWN elif iParking_option == 2: sTxt = ("Enter the area of the parking footprint in sq.mm from map.") fMap_area = misc.get_float(sTxt) if fMap_area == None: return None # Calculate the parking area fMap_scale = dNew_housing["aMap"]["fScale"] aParking_area = misc.calc_area(fMap_area, fMap_scale) if aParking_area == None: return None # We know the real-world scale of the parking. # In the real world, a parking bay is 5.5m x 2.5m (13.75sq.m). However, # each vehicle needs access to that bay. The above calcuation gives # 7.27veh/100sq.m. However, each vehilce needs some space to get to the # bay. Hence, I'm using the figure of 6 veh / 100sq.m (600veh/ha) # Verify the units of measurement if aParking_area["uom"] != "sq.m": print( "\nUnexpected calculation result for residential parking:\n" + "Expected 'sq.m', but got {0}\a".format(aParking_area["uom"])) return None fSqm_P = aParking_area["qty"] print("Parking is: {0}{1}".format(aParking_area["qty"], aParking_area["uom"])) sTxt = ("On how many levels are cars parked?") iFloors = misc.get_int(sTxt) if iFloors == None: return None if iFloors > 1 and fSqm_P < 90: sTxt = ("\n\aInsufficient space for a ramp " + "(1:10 @ h = 3.6m, w = 2.5m). Exiting") return None if iFloors > 1: fSqm_P -= 90 # Take room for the ramp fVeh = 6.0 * fSqm_P / 100 iVeh = int(round(fVeh, 0)) # Round off to whole vehicles fVeh = iVeh * iFloors # We need to round off per floor. iVeh = int(round(fVeh, 0)) # Round off to whole vehicles fVeh = iVeh * iNo_of_buildings # Parking in each building iVeh = int(round(fVeh, 0)) # Round off to whole vehicles dNew_housing["aParking"]["iFloors"] = iFloors dNew_housing["aParking"]["iVeh"] = iVeh dNew_housing["aParking"]["map_a"] = fMap_area # Save the data in the array print("\nThese buildings park {0} vehicles".format(iVeh)) # -- -- -- -- -- -- -- -- -- -- # UPDATE THE GEO-OBJECT dSup_hhold = dGeo_element["aSupply_hholds"] # Get the existing data out dTot_sup = dSup_hhold["total"] aItemised = dSup_hhold["aItemised"] # Update total of this particular demographic sGroup = dNew_housing["demographic"] # 'r' to 'p' iTot_units = dNew_housing["iTot_units"] # Household count. dTot_sup[sGroup] += iTot_units # Add to the grand total # Generate the prototype dItem = {"sName": None, "r": 0, "h": 0, "m": 0, "l": 0, "p": 0} # Update the item dItem["sName"] = dNew_housing["my_id"] # > 36 blocks possible dItem[sGroup] += iTot_units # Build the item aItemised.append(dItem) # Save with suburb # UPDATE DATA BASE cHousing.insert_one(dNew_housing) # Housing pushed # UPDATE HOST xParam = {"geo_code": sGeo_code} xNew_data = {"$set": {"aSupply_hholds": dSup_hhold}} cDest.update_one(xParam, xNew_data) print("\n DATABASE ENTRIES UPDATED ({0})".format(sNew_id))
def add_station(ccTremb): """ Adds details of a station to the database """ # Obtain the highest "my_id" code that is registered in the database. # Get a list of all the registered base-36 codes xParam = {} xRestr = {"_id": 0, "my_id": 1} cStation = db.stations(ccTremb) dId_query = cStation.find(xParam, xRestr) iHighest, aEvery_id = misc.find_highest_id(dId_query) if (False): # Debugging sTxt = "\n\nHighest number is {0}(10) < < < < < < < <" print(sTxt.format(iHighest)) # We do have the highest identifier (expressed as a decimal number). Hence, # we can incerement the sequence and use it. iNext_id = iHighest + 1 if iNext_id > 36**5: print("\n\aMaximum count has been exceeded") return None # Convert to base36 sBase36 = misc.base_conv(iNext_id) sBase36_5 = sBase36.rjust(5, "0") # "0002W" -> "D00-02W" sNew_id = "S{0}-{1}".format(sBase36_5[:2], sBase36_5[2:]) # START GETTING THE USER TO ENTER THE NEW DATA. # Open a blank dictionary, so that the elements are arranged in a certain # order. dNew_port = { "my_id": sNew_id, "host_geo_code": None, "aName": { "lat": None, "cyr": None }, "type": None, "sub_type": None, "level": None, "aMap": { "sRegion": None, "iYear": None, "fScale": None, "x": None, "y": None, "a": None }, "aArea": { "qty": None, "uom": None }, "lServices": [], "lWarehouse": [], "iLoading_zones": 0, } # HOST cDest = db.destinations(ccTremb) # To verify the geocode sTxt = ("\nWho is hosting this station/port? Please enter thier geo-code.") print(sTxt) sGeo_code = input().upper() aHost_name = misc.verify_geo_code(sGeo_code, cDest) if aHost_name == None: return dNew_port["host_geo_code"] = sGeo_code sTxt = "\nHosted by {0} / {1}".format(aHost_name["lat"], aHost_name["cyr"]) print(sTxt) # TYPE sMenu = "\n" sMenu += "What type of a station or port is it?\n" sMenu += "0: Rail\n" sMenu += "1: Road\n" sMenu += "2: Water\n" sMenu += "3: Air\n" iType_option = misc.get_int(sMenu, 3) if iType_option == None: print("\a") return None if iType_option == 0: dNew_port["type"] = "Rail" elif iType_option == 1: dNew_port["type"] = "Road" elif iType_option == 2: dNew_port["type"] = "Water" elif iType_option == 3: dNew_port["type"] = "Air" else: print("\n\aInvalid choice for port type") return # SUB-TYPE sMenu = "\n" sMenu += "What is transported?\n" sMenu += "0: Passangers (PAX)\n" sMenu += "1: Freight (F)\n" sMenu += "2: Livestock (L/S)\n" iType_option = misc.get_int(sMenu, 2) if iType_option == None: print("\a") return None if iType_option == 0: dNew_port["sub_type"] = "Pax" elif iType_option == 1: dNew_port["sub_type"] = "Freight" elif iType_option == 2: dNew_port["sub_type"] = "Livestock" else: print("\n\aInvalid choice for port type") return # LEVEL sMenu = "\n" sMenu += "What level is the station or port on?\n" sMenu += "0: International ['0V9'->'0Q1']\n" sMenu += "1: National / Inter-Provincial ['V'->'L']\n" sMenu += "2: Provincial / Inter-District ['GY'->'VA']\n" sMenu += "3: District / Inter-County ['GYN'->'GY0']\n" sMenu += "4: County / Inter-Municipal ['GYN-2'->GYN-0] \n" sMenu += "5: Municipal / Intra-Municipal ['VAA-0A'->'VAA-0B'])\n" iLevel_option = misc.get_int(sMenu, 5) if iLevel_option == None: print("\a") return None if iLevel_option == 0: dNew_port["level"] = "Int'l" elif iLevel_option == 1: dNew_port["level"] = "Nat'l" elif iLevel_option == 2: dNew_port["level"] = "Prov." elif iLevel_option == 3: dNew_port["level"] = "Dist." elif iLevel_option == 4: dNew_port["level"] = "Cnty." elif iLevel_option == 5: dNew_port["level"] = "Muni." else: print("\n\aInvalid choice for port type") return # MAP REFERENCE # Obtain the reference to the CAD map. The maps available have their own # database entry cMaps = db.maps_db(ccTremb) xParam = {} xRestr = {"_id": 0} dMap_query = cMaps.find(xParam, xRestr) iNo_of_maps = 0 dMap_copy = [] for dMap in dMap_query: iNo_of_maps += 1 dMap_copy.append(dMap) # Setup a menu of the maps available # Setup an option of entering a region which is not mapped print("\nOn which map is this station/port?") sMenu = "0: No map\n" iCnt = 0 # Go through all the available maps. for one_map in dMap_copy: iCnt += 1 # xScale = "{:.1e}".format(one_map["fScale"]) # 1.0e6 for 1:1M xScale = "{0:,}".format(int(one_map["fScale"])) # Commas every 1000's sTxt = "{0}: {1}, {2} 1:{3}\n" sMenu += sTxt.format(iCnt, one_map["sRegion"], one_map["iYear"], xScale) sMenu += "x: Invalid choice will exit this sub menu" print(sMenu) # Get the response from the user, with reference to the menu being offered. sInput = input() if sInput.isnumeric() == False: # An inbuilt 'abort' system where the user can enter 'x' to exit. print("\nInput is not a numeric value. Returning to menu") return None # Get the details from the dictionary and write them into the destinations # entry. iInput = int(sInput) if (iInput == 0): dNew_port["aMap"]["sRegion"] = "No Map" dNew_port["aMap"]["iYear"] = None dNew_port["aMap"]["fScale"] = None elif (iInput > iCnt): print("\nChoice out of range. Returning to menu") return None else: iIdx = iInput - 1 dNew_port["aMap"]["sRegion"] = dMap_copy[iIdx]["sRegion"] dNew_port["aMap"]["iYear"] = dMap_copy[iIdx]["iYear"] dNew_port["aMap"]["fScale"] = dMap_copy[iIdx]["fScale"] # Map location: Co-ordinates on the speciied CAD map. if (dNew_port["aMap"]["fScale"] != None): # This only works if the map exists. sQuestion = "\nEnter the x-coordinate from the map:" fX = misc.get_float(sQuestion, None, True) if fX == None: return None dNew_port["aMap"]["x"] = fX sQuestion = "\nEnter the y-coordinate from the map:" fY = misc.get_float(sQuestion, None, True) if fY == None: return None dNew_port["aMap"]["y"] = fY sQuestion = "\nEnter the area in mm2 from the map:" fA = misc.get_float(sQuestion) if fA == None: return None dNew_port["aMap"]["a"] = fA # Calcluate the area. dArea = misc.calc_area(dNew_port["aMap"]["a"], dNew_port["aMap"]["fScale"]) if dArea == None: return None # Compensate for inconsistency dArea_2 = {"val": dArea["qty"], "uom": dArea["uom"]} dNew_port["aArea"] = dArea_2 # End of map location entry # NAME IT! bExit = False while bExit == False: sMenu = "\nDo you want a to use host's name/a random name?" sRand_name_yn = misc.get_binary(sMenu) if sRand_name_yn == None: return None sName_only_lat = "" sName_only_cyr = "" # Manual entry: if sRand_name_yn == "N": print("\nPlease enter the name of the station / port in" + "(Use international Keyboard)") sName_only_lat = input() # User entered name in Cyrillic print("\nНапиш име стацйи люб порту в Цырполюю. " + "(пшэлаьч клавятурэ рэьчне)") sName_only_cyr = input() # Randomly generated Name elif sRand_name_yn == "Y": # Operated by an external routine import modules.x_random_names as rnd_name # We are storing the random names from the various systems here. # Hence, we will build up one set of arrays for the user to #choose aLat = [] aCyr = [] # Host name aLat.append(aHost_name["lat"]) aCyr.append(aHost_name["cyr"]) # Male-static: iNo_of_combos = 3 aName = rnd_name.rnd_male_name(iNo_of_combos) aSurname = rnd_name.qRnd_static_surname(iNo_of_combos) for iIdx in range(iNo_of_combos): sName = aName[iIdx]["lat"] sSurname = aSurname[iIdx]["lat"] aLat.append("{0} {1}".format(sName, sSurname)) sName = aName[iIdx]["cyr"] sSurname = aSurname[iIdx]["cyr"] aCyr.append("{0} {1}".format(sName, sSurname)) # Male-dynamic: iNo_of_combos = 3 aName = rnd_name.rnd_male_name(iNo_of_combos) aSurname = rnd_name.qRnd_dynamic_surname(iNo_of_combos) for iIdx in range(iNo_of_combos): sName = aName[iIdx]["lat"] sSurname = aSurname[iIdx]["lat"] aLat.append("{0} {1}".format(sName, sSurname)) sName = aName[iIdx]["cyr"] sSurname = aSurname[iIdx]["cyr"] aCyr.append("{0} {1}".format(sName, sSurname)) # Female-static: iNo_of_combos = 3 aName = rnd_name.rnd_female_name(iNo_of_combos) aSurname = rnd_name.qRnd_static_surname(iNo_of_combos) for iIdx in range(iNo_of_combos): sName = aName[iIdx]["lat"] sSurname = aSurname[iIdx]["lat"] aLat.append("{0} {1}".format(sName, sSurname)) sName = aName[iIdx]["cyr"] sSurname = aSurname[iIdx]["cyr"] aCyr.append("{0} {1}".format(sName, sSurname)) # Female-dynamic: iNo_of_combos = 3 aName = rnd_name.rnd_female_name(iNo_of_combos) aSurname = rnd_name.qRnd_dynamic_surname(iNo_of_combos) for iIdx in range(iNo_of_combos): sName = aName[iIdx]["lat"] sSurname = aSurname[iIdx]["lat"] aLat.append("{0} {1}".format(sName, sSurname)) sName = aName[iIdx]["cyr"] sSurname = aSurname[iIdx]["cyr"] aCyr.append("{0} {1}".format(sName, sSurname)) # Display the names iNo_of_names = len(aLat) sChoices = "0: Choose again\n" # Don't like the options iCnt = 1 for idx in range(0, iNo_of_names): sTxt = "{0}: {1} / {2}\n" sChoices += sTxt.format(iCnt, aLat[idx], aCyr[idx]) iCnt += 1 iChoice = misc.get_int(sChoices, iNo_of_names) if iChoice == None: return None # Invalid choice if iChoice == 0: continue # Choose again. iChoice -= 1 # Export the final names sName_only_lat = aLat[iChoice] sName_only_cyr = aCyr[iChoice] # Prepare post-fix sLat_Intl = "" sCyr_Intl = "" if dNew_port["level"] == "Int'l": sLat_Intl = "International" # The joys of Slavic grammar! if dNew_port["type"] in ["Rail"]: sCyr_Intl = "Меьдзыщнародова" elif dNew_port["type"] in ["Water", "Road"]: sCyr_Intl = "Меьдзыщнародовы" elif dNew_port["type"] in ["Air"]: sCyr_Intl = "Меьдзыщнародовэ" # Type of transport sLat_B = "" sCyr_B = "" # Rail #################################################### if dNew_port["type"] == "Rail": if dNew_port["sub_type"] == "Pax": sLat_B = "Train Station" sCyr_B = "Стаця Колеёва" elif dNew_port["sub_type"] == "Freight": sLat_B = "Freight Station" sCyr_B = "Стаця Товарова" elif dNew_port["sub_type"] == "Livestock": sLat_B = "Livestock Station" sCyr_B = "Стаця Звъежаьт" # Road - - - - - - - - - - - - - - - - - - - - - - - - - - - elif dNew_port["type"] == "Road": if dNew_port["sub_type"] == "Pax": sLat_B = "Bus Station" sCyr_B = "Двожэс Алтобусовы" elif dNew_port["sub_type"] == "Freight": sLat_B = "Truck Depot" sCyr_B = "Двожэс Товаровы" elif dNew_port["sub_type"] == "Livestock": sLat_B = "Livestock Depo" sCyr_B = "Двожэс Звъежэьтьи" # Water ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ elif dNew_port["type"] == "Water": if dNew_port["sub_type"] == "Pax": sLat_B = "Passanger Harbour" sCyr_B = "Порт Особовы" elif dNew_port["sub_type"] == "Freight": sLat_B = "Freight Harbour" sCyr_B = "Порт Товаровы" elif dNew_port["sub_type"] == "Livestock": sLat_B = "Livestock Harbour" sCyr_B = "Порт Звъежэьтьи" # Air > > > - - - - - - - - - - - - - - - - - < < < elif dNew_port["type"] == "Air": if dNew_port["sub_type"] == "Pax": sLat_B = "Airport" sCyr_B = "Лётниско" elif dNew_port["sub_type"] == "Freight": sLat_B = "Freight Airport" sCyr_B = "Лётниско Товаровэ" elif dNew_port["sub_type"] == "Livestock": sLat_B = "Livestock Airport" sCyr_B = "Лётниско Звъежэьцэ" else: print("Invalid choice. Exiting") return None # Full Latin name if sLat_Intl == "": sTxt = "{0} {1}".format(sName_only_lat, sLat_B) else: sTxt = "{0} {1} {2}".format(sName_only_lat, sLat_Intl, sLat_B) dNew_port["aName"]["lat"] = sTxt # Cyrillc grammar if sCyr_Intl == "": sTxt = "{1} о им. {0}".format(sName_only_cyr, sCyr_B) else: sTxt = "{1} {2} о им. {0}" sTxt = sTxt.format(sName_only_cyr, sCyr_Intl, sCyr_B) dNew_port["aName"]["cyr"] = sTxt # Confirm the name choice sNew_lat = dNew_port["aName"]["lat"] sNew_cyr = dNew_port["aName"]["cyr"] sMenu = "Are the names:\n'{0}'\n'{1}' OK?" sMenu = sMenu.format(sNew_lat, sNew_cyr) sNames_ok_yn = misc.get_binary(sMenu) if sNames_ok_yn == "Y": bExit = True # End of 'its named' # SERVICES: WHICH AREA DOES THIS FACILITY SERVICE bDone = False # Multiple areas. while bDone == False: sTxt = ( "\nThis station/port serves the people of ___." + "\n(Enter the geo-code of the entity OR Press '.' to exit loop") print(sTxt) sGeo_code = input().upper() if sGeo_code in ["", None, "."]: bDone = True continue # Verify the geo-code aName = misc.verify_geo_code(sGeo_code, cDest) if aName == None: bDone = True continue # Geocode verified, add the geo code to the list dNew_port["lServices"].append(sGeo_code) sLat_name = aName["lat"] sCyr_name = aName["cyr"] print("({0} / {1})".format(sLat_name, sCyr_name)) # end of while loop # WAREHOUSE: lSta_Whs = dNew_port["lWarehouse"] # Station warehouse for sTown in dNew_port["lServices"]: # Passanger or freight? if dNew_port["sub_type"] == "Pax": aData = {} # Travel demand: Why not model on Newton's equation of gravitation: # F = G*m1*m2 / r^2. Where, 'm' would be the population. xParam = {"geo_code": sTown} xRestr = {"_id": 0, "aDemographics": 1} dRun_query = cDest.find(xParam, xRestr) for query in dRun_query: aData = query["aDemographics"] # Freight or livestock: else: # Pull the data from the warehouses. dClt_whs = [] # List, client warehouse xParam = {"geo_code": sTown} xRestr = {"_id": 0, "aWarehouse": 1} dRun_query = cDest.find(xParam, xRestr) for query in dRun_query: dClt_whs = query["aWarehouse"] # The could be no data in the warehouse if dClt_whs == {}: continue # Extract the data from the warehouse for sShelf in dClt_whs: # Pull the data apart: look what is on the 'shelf' dContent = dClt_whs[sShelf] sResource = dContent["resource"].lower() fAmount = dContent["annual_output"] xUnits = dContent["units"] if xUnits == "t/yr": xUnits = "t/wk" elif xUnits == "kg/yr": xUnits = "kg/wk" elif xUnits == "kt/yr": xUnits = "kt/wk" else: print("Units are not presented as weight per year") # We have "shelves" in the warehouse already bNot_found = True for dSta_whs_shelf in lSta_Whs: # Find the correct shelf to add the contents. if dSta_whs_shelf["resource"] != sResource: continue if dSta_whs_shelf["units"] != xUnits: print("\n\aUnits mismatch at the warehouse. EXITING") return None fWeekly_produce = round(fAmount / 52, 2) fWeekly_total = dSta_whs_shelf["weekly_output"] fSub_tot = round(fWeekly_total + fWeekly_produce, 2) dSta_whs_shelf["weekly_output"] = fSub_tot bNot_found = False # We need to add another shelf to the warehouse: if bNot_found == True: dEntry = {} dEntry["resource"] = sResource # NOTE: Logistics run on weekly cycles. dEntry["weekly_output"] = round(fAmount / 52, 2) dEntry["units"] = xUnits lSta_Whs.append(dEntry) # End of warehouse shelf created # end of going through each of the client's shelves # end of freight/livestock vs passangers # end of going through the towns on the include list. fTot_weight = 0.0 for dEntry in dNew_port["lWarehouse"]: sName = dEntry["resource"] fAmount = dEntry["weekly_output"] sUnits = dEntry["units"] if sUnits == "t/wk": fTot_weight += fAmount # Publish total weight elif sUnits == "kt/wk": fTot_weight += fAmount * 1000 elif sUnits == "kg/wk": fTot_weight += fAmount / 1000 sTxt = "{0}: {1}{2}".format(sName, fAmount, sUnits) print(sTxt) if len(dNew_port["lWarehouse"]) > 0: fTot_weight = round(fTot_weight, 3) # Round off . fTot_daily = fTot_weight / 5.0 # MON to FRI fTot_daily = round(fTot_daily, 3) sTxt = "-------------\n" sTxt += "TOTAL: {0}t/wk\n".format(fTot_weight) sTxt += "TOTAL: {0}t/day\n".format(fTot_daily) print(sTxt) # Number of loading bays sTxt = ("\nEnter the number of 'loading zones'. " + "Take into account the imports") iLoading_zones = misc.get_int(sTxt) if iLoading_zones == None: return dNew_port["iLoading_zones"] = iLoading_zones # ATTACH TO HOST if dNew_port["type"] == "Rail": if dNew_port["sub_type"] == "Pax": sInd_code = "QP1" # Passanger operations else: # Freight / livestock operations sInd_code = "QF1" # ROAD TRANSPORT elif dNew_port["type"] == "Road": if dNew_port["sub_type"] == "Pax": sInd_code = "QB1" # Bus operations else: sInd_code = "QT1" # Truck port. Currently at 20t / trip # Air TRANSPORT elif dNew_port["type"] == "Air": if dNew_port["sub_type"] == "Pax": sInd_code = "QA1" # Passanger air ops else: sInd_code = "QG1" # Freight air ops dBriefcase = { "ccTremb": ccTremb, # Link to all the databases "sGeo_code": dNew_port["host_geo_code"], # of the host "sInd_code": sInd_code, # Passanger or Freight? "sName_lat": dNew_port["aName"]["lat"], # Don't overkill it. "sYour_id": dNew_port["my_id"], # When constructed in city, link it! "aArea": dNew_port["aArea"], # Footprint "iNo_of_builds": 1, # Number of stations. "lServices": dNew_port["lServices"], # Who makes use of this? "fCapacity": None, # How much is used (schools, ect) } xFeedback = d_py.add_wkp_auto(dBriefcase) if xFeedback == None: return cStation.insert_one(dNew_port) print("\n>>>\nNew station added")
def add_community_services(ccTremb): """ Adds the the following items to the database. It takes data from the map. The actual number of employees will be determined later. These can be placed first; its service region can be edited later. Another method will update these and their hosts. The list of items accessed through here is: 5YP: Community Police station, 5YF: Community Fire station, 5YH: Community clinics, 5YG: Community governance, ED0: Pre-school, ED1: Primary School, ED2: Middle School, ED3: High School, OAH: Standard Old Age Home, 5SŠ: Community shop ("Small Šop"), 5LX: Community Libraries, 5TH: Community Theatres, 5PO: Community Post Offices. """ # Obtain the highest "my_id" code that is registered in the database. xParam = {} xRestr = {"_id": 0, "my_id": 1} cCommunity = db.community_services(ccTremb) dId_query = cCommunity.find(xParam, xRestr) iHighest, aEvery_id = misc.find_highest_id(dId_query) # We do have the highest identifier (expressed as a decimal number). Hence, # we can incerement the sequence and use it. iNext_id = iHighest + 1 if iNext_id > 36**5: print("\n\aMaximum count has been exceeded") return None # Convert to base36 sBase36 = misc.base_conv(iNext_id) sBase36_5 = sBase36.rjust(5, "0") # "0002W" -> "D00-02W" sNew_id = "A{0}-{1}".format(sBase36_5[:2], sBase36_5[2:]) print("\nNext id is {0}".format(sNew_id)) # START GETTING THE USER TO ENTER THE NEW DATA. # Open a blank dictionary, so that the elements are arranged in a certain # order. dNew_service = { "my_id": sNew_id, "host_geo_code": None, "aName": { "lat": None, "cyr": None }, # Is the block of flats named? "type_code": None, # "5YP" for example "type_name": "", # "Police" "iNo_of_units": 1, # Multiple units operating from one site. "sub_type": None, # RFU "aServes": [], # Geo-codes of commuinties it serves. "iClients": 0, # Quick summary of clients supplied "iCapacity": 0, # Summary of how much we can hold "sNotes": "", # Irregular building "aMap": { "sRegion": None, "iYear": None, "fScale": None, "x": None, "y": None, "a": None }, "aFtp_bldg": { "qty": None, "uom": None }, "aArea_plot": { "qty": None, "uom": None }, } # HOST cDest = db.destinations(ccTremb) # To verify the geocode sTxt = ("\nWho is hosting this community service?" + " Please enter thier geo-code.") print(sTxt) sGeo_code = input().upper() dHost_element = misc.get_geo_element(sGeo_code, cDest) if dHost_element == None: return dNew_service["host_geo_code"] = sGeo_code aHost_name = dHost_element["aName"] sTxt = "\nHosted by {0} / {1}".format(aHost_name["lat"], aHost_name["cyr"]) print(sTxt) # MAKE A LIST OF THE SERVICES cCity_services = db.city_services_const(ccTremb) xParam = {} xRestr = {"_id": 0} dCity_query = cCity_services.find(xParam, xRestr) # Copy out the query dCity_copy = [] for dItem in dCity_query: dCity_copy.append(dItem) # Setup the menu sMenu = ("\nWhich service are you adding? (Invalid entry will exit)\n") iCnt = 0 for dOne_service in dCity_copy: iCnt += 1 sCode = dOne_service["code"] sName = dOne_service["name"] sMenu += ("{0}: [{1}] {2}\n".format(iCnt, sCode, sName)) # Print the menu and get the response iChoice = misc.get_int(sMenu, 13) if iChoice == None: return None # Select the service dSvc = dCity_copy[iChoice - 1] # Count started at one! # Record the code dNew_service["type_code"] = dSvc["code"] # 5YP for example dNew_service["type_name"] = dSvc["name"] # Police for example # MAP REFERENCE sMap = dSvc["name"] dData = misc.get_map_input(ccTremb, sMap) # Asks for user to input stuff. if dData in [None, True]: # No map selected print("\n\aInvalid entry from the map. Exiting") return None # Transfer data through. dNew_service["aMap"] = dData["dMap"] dNew_service["aArea_plot"] = dData["dArea"] # BUILDING: sTxt = "Is the size of the actual building(s) known?" sYn_bldg = misc.get_binary(sTxt) if sYn_bldg == None: return None if sYn_bldg == "Y": sTxt = "\nEnter the footprint of the building in sq.mm from map." fBldg_ftp = misc.get_float(sTxt) if fBldg_ftp == None: return None # Calculate area fScale = dNew_service["aMap"]["fScale"] dNew_service["aFpt_bldg"] = misc.calc_area(fBldg_ftp, fScale) # NAME THE FACILITY aName = misc.building_name() if aName == None: return None if aName != False: # A name was chosen dNew_service["aName"] = aName # Building count sTxt = ("How many units operate from this facility?") iNo_of_units = misc.get_int(sTxt) if iNo_of_units == None: return None dNew_service["iNo_of_units"] = iNo_of_units # Calculate total customer capacity: fTot_cust = iNo_of_units * dSvc["capacity"] iTot_cust = int(round(fTot_cust, 0)) # Just to be sure. dNew_service["iCapacity"] = iTot_cust # SERVICES: WHICH AREA DOES THIS FACILITY SERVICE # While here, show live updates of the service demand. sDgfx_code = dSvc["serves"] # iTOT-PAX for example bDone = False # Multiple areas. while bDone == False: sTxt = ( "\nThis facility serves the people of ___." + "\n(Enter the geo-code of the entity OR Press '.' to exit loop") print(sTxt) sGeo_code = input().upper() if sGeo_code in ["", None, "."]: bDone = True continue # Verify the geo-code dCust_element = misc.get_geo_element(sGeo_code, cDest) if dCust_element == None: bDone = True continue # Geocode verified, add the geo code to the list dNew_service["aServes"].append(sGeo_code) sLat_name = dCust_element["aName"]["lat"] sCyr_name = dCust_element["aName"]["cyr"] # Sort out the capacity as we go along. sTxt = "{0} / {1}:\n".format(sLat_name, sCyr_name) sTxt += "{0} is ".format(sDgfx_code) aDgfx = dCust_element["aDemographics"] # Shorter access if aDgfx == {}: dNew_service["sNotes"] += " {0}*,".format(sGeo_code) sTxt += ("N/A") else: iClients = aDgfx[sDgfx_code] sTxt += ("{0}\n".format(iClients)) dNew_service["iClients"] += iClients iNs_clt = dNew_service["iClients"] iNs_cap = dNew_service["iCapacity"] fPercentage = iNs_clt / iNs_cap sPercentage = "{:.3f}".format(fPercentage) # Hopefully "0.344" sTxt_a = ("Total clients: {0} / {2} = ({1} of capacity)") sTxt += sTxt_a.format(iNs_clt, sPercentage, iNs_cap) print(sTxt) # end of while loop, servicing the facilities. print("Enter comments (if any)") dNew_service["sNotes"] += "| " dNew_service["sNotes"] += input() # UPDATE THE WORKPLACE SUPPLY. # Create the element first. It will either be overridden or a new entry will # be created fDenominator = dNew_service["iCapacity"] * iNo_of_units if fDenominator == 0.00: print("\n\aDivide by zero error caught during capacity calc. Exiting") return None fNumerator = dNew_service["iClients"] fCapacity = fNumerator / fDenominator sCapacity = "{:.3}".format(fCapacity) dThe_item = { "iCnt": iNo_of_units, # How many pre-schools in this facility "sCode": dSvc["code"], # 5YH for example "sName": dNew_service["my_id"], # A00-001 for example (unique) "lServices": dNew_service["aServes"], # Geo-codes within the scope "fCapacity": sCapacity, # Needs to be calculated } print(dThe_item) # for aDemand_workforce print(dNew_service) # Own database entry # WRITE TO DATABASE aSupply_workplace = dGeo_element["aSupply_workplace"] aSupply_workplace.append(dThe_item) xParam = {"geo_code": dNew_service["host_geo_code"]} xNew_data = { "$set": { "aSupply_workplace": aSupply_workplace, } } cDest.update_one(xParam, xNew_data) cCommunity.insert_one(dNew_service) print(">>> Databases updated ({0})".format(dNew_service["my_id"]))
def qEvent_signage(dPack): """ This function sets up a 'trafic sign'. dPack = { "tremb": ccTremb, # For full DB access. "db": cLine, # Database entries for the line. "dEntry": { # This parameter will be passed back "km":fDist, # kmilage marker "id":iHighest+1, # Unique reference number "item":None, # We need to fill this with our data "type":None, # We need to fill this with our data "xVal":None}, # We need to fill this with our data } """ dEntry = dPack["dEntry"] # Unpack the prototype sMenu = ("Please select the station event from the list") sMenu += "Select track event:\n" sMenu += "0 Comment (record something unusual)\n" sMenu += "1 Speed limit, dir: 'away' (increasing km-count)\n" sMenu += "2 Speed limit, dir: 'home' (decreasing km-count)\n" print(sMenu) sInput = input().upper() # COMMENT if sInput == "0": # Comment dEntry["item"] = "sign" dEntry["type"] = "comment" # Type of transaction sTxt = "Please enter a comment regarding station" print(sTxt) dEntry["xVal"] = input() return dEntry # SPEED AWAY if sInput == "1": #"dEntry":{"km":fDist,"id":0,"item":None,"type":None,"xVal":None}, dEntry["item"] = "sign" dEntry["type"] = "speed_away" # Type of transaction sTxt = "Please enter speed limit going away in km/h:" iKmh = misc.get_int(sTxt) if iKmh == None: return # Error handling xVal = { # For synchronisation with other signs "val": iKmh, "dis": None, "dur": None } dEntry["xVal"] = xVal return dEntry # SPEED HOME if sInput == "2": #"dEntry":{"km":fDist,"id":0,"item":None,"type":None,"xVal":None}, dEntry["item"] = "sign" dEntry["type"] = "speed_home" # Type of transaction sTxt = "Please enter speed limit coming home in km/h:" iKmh = misc.get_int(sTxt) if iKmh == None: return # Error handling xVal = { # For synchronisation with other signs "val": iKmh, "dis": None, "dur": None } dEntry["xVal"] = xVal return dEntry else: print("\n\aInvalid selection. Exiting") return None
def qEvent_track(dPack): """ This function builds up a piece of track for us. dPack = { "tremb": ccTremb, # For full DB access. "db": cLine, # Database entries for the line. "dEntry": { # This parameter will be passed back "km":fDist, # kmilage marker "id":iHighest+1, # Unique reference number "item":None, # We need to fill this with our data "type":None, # We need to fill this with our data "xVal":None}, # We need to fill this with our data } """ dEntry = dPack["dEntry"] # Unpack the prototype sMenu = ( "The observer is looking away from the point 'km:0.00'. Hence, " + "'start', 'end',\n'merge', 'diverge', 'left', 'right' are biased. " + "'track:n' is after the track\nevent. Tracks are numbered '1' to 'n' " + "left to right\n\n") sMenu += "Select track event:\n" sMenu += "0 Comment (record something unusual)\n" sMenu += "1 Start tracks (Terminus if at km:0.00)\n" sMenu += "2 [RFU] End tracks (dead-end / Storage)\n" sMenu += "3 Merge tracks (4 to 1 for example)\n" sMenu += "4 Diverge tracks (1 to 4 for example)\n" sMenu += "5 IXI-junction (Simultaneous bi-direct. 'lane change')\n" sMenu += "6 [RFU] Rail-to-rail level crossing\n" sMenu += "7 [RFU] Join two lines head-on (at a border)\n" print(sMenu) sInput = input().upper() # COMMENTS if sInput == "0": # Comment dEntry["item"] = "track" dEntry["type"] = "comment" # Type of transaction sTxt = "Please enter a comment regarding track" print(sTxt) dEntry["xVal"] = input() return dEntry # START OF TRACK if sInput == "1": # Start tracks #"dEntry":{"km":fDist,"tracks":0,"item":None,"type":None,"xVal":None}, # Terminus question: if dEntry["km"] < 0.001: # Beginning of the line from a terminus sTxt = "Please enter number of tracks that are starting:" iNew_tracks = misc.get_int(sTxt) if iNew_tracks == None: return None dEntry["item"] = "track" dEntry["type"] = "start_all" dEntry["xVal"] = iNew_tracks else: print("TODO") return None return dEntry if sInput == "2": # End tracks print("TODO") if sInput == "3": # Merge tracks sTxt = "Please confirm number of tracks BEFORE merger:" iBef = misc.get_int(sTxt) if iBef == None: return None sTxt = "Please enter number of tracks AFTER merger:" iAft = misc.get_int(sTxt) if iAft == None: return None dEntry["item"] = "track" dEntry["type"] = "merge" xVal = {"iBef": iBef, "iAft": iAft} dEntry["xVal"] = xVal return dEntry if sInput == "4": # Diverge tracks sTxt = "Please confirm number of tracks BEFORE divergence:" iBef = misc.get_int(sTxt) if iBef == None: return None sTxt = "Please enter number of tracks AFTER divergence:" iAft = misc.get_int(sTxt) if iAft == None: return None dEntry["item"] = "track" dEntry["type"] = "diverge" xVal = {"iBef": iBef, "iAft": iAft} dEntry["xVal"] = xVal return dEntry if sInput == "5": # IXI-junction: Allows for changes between tracks. # Simultaneous merge then diverge. Imagine that all the 'legs' of # the letters are tracks. They would form the prase "IXI" sTxt = "Please confirm number of tracks in 'IXI' junction:" iIxi = misc.get_int(sTxt) if iIxi == None: return None dEntry["item"] = "track" dEntry["type"] = "ixi" xVal = {"iBef": iIxi, "iAft": iIxi} dEntry["xVal"] = xVal return dEntry if sInput == "6": # Rail-to-rail level crossing print("TODO") else: print("\n\aInvalid selection. Exiting") return None
def add_sub_comp(ccTremb): """ This method adds to the railway line opened. Items line track switches, level crossings, diverges, merges, stations, ect can be added. """ # Get the line input. # To avoid annoying the user of having to enter the line segment, lets # assume that the user is working on the 'latest' line. So, lets provide # the preselected item. xParam = {} xRestr = {"_id": 0} cLine = db.lines(ccTremb) dId_query = cLine.find(xParam, xRestr).sort("_id", -1) dId_query.sort("_id", -1) # From latest to earliest # Pull the text for the user to know if he is working on the correct object sCode = dId_query[0]["my_id"] sTxt = ("The last worked on line was '{0}'. Would you like to work on" + " it more?").format(sCode) yn_prev_code = misc.get_binary(sTxt) if yn_prev_code == "N": print("Please enter the line code (K00-001) you would like to work on") sLast_code = input().upper() # Verify the existance of the code and return a string verifying identity sRte_det = qVerify_line(sCode, ccTremb) if sRte_det == None: return None # Error condition # Full confirmation message: sTxt = ("Are you are working on {0}".format(sRte_det)) yn_confirm = misc.get_binary(sTxt) if yn_confirm == 'N': return # Confirmation completed. Lets get the reference point # Run a query on all milestones. xParam = {"my_id": sCode, "tag": "val"} xRestr = {"_id": 0} dQuery = cLine.find(xParam, xRestr) dData = [] for query in dQuery: dData.append(query) # Save data for further processing # Pull out the distances already entered s1st_line = "Enter the relative distance from the last known point" sMenu = "{0}:\n".format(s1st_line) sMenu += "0 : -.--km (beginning of the line)\n" iNo_of_entries = len(dData) iIndex = 0 # pull out the reference numbers iHighest = 0 # Offer the distances in a menu for idx in range(iNo_of_entries): iIndex += 1 # This will show up in the menu. sLast_item = "" dItem = dData[idx]["dVal"] sLast_item += "{:.2f}km ".format(dItem["km"]) sLast_item += "({0}-".format(dItem["item"]) sLast_item += "{0}-".format(dItem["type"]) sLast_item += "{0})".format(dItem["xVal"]) iLoc_high = dItem["id"] if iLoc_high > iHighest: iHighest = iLoc_high sMenu += ("{0:<3}: {1}".format(iIndex, sLast_item))[:78] + "\n" # Keep the string less than 78 characters (avoid collumn breaks) # Get the user to choose. iDist_choice = misc.get_int(sMenu, iIndex) if iDist_choice == None: return # Default option, when there is no other options. fDist = 0.00 if iDist_choice != 0: sTxt = "Is the absolute distance known (from 0.00km)?" yn_abs_dist = misc.get_binary(sTxt) if yn_abs_dist == "Y": sTxt = "Please enter the absolute distance in km" fAbs_dist = misc.get_float(sTxt) # Allow negative dist. if fAbs_dist == None: return fDist = round(fAbs_dist, 2) # We want to enter a relative distance else: sTxt = "Is the relative distance read from the map?" yn_rel_map = misc.get_binary(sTxt) if yn_rel_map == "N": # Relative distance is known in km. sTxt = "Please enter the relative distance in km" fRel_dist = misc.get_float(sTxt, bNeg=True) if fRel_dist == None: return fRel_dist = round(fRel_dist, 2) # We are reading off the map. else: # Select a map to work on dMap = misc.get_the_map(ccTremb) if dMap == None: print("\n\aInvalid map selected. Exiting") return None fScale = dMap["fScale"] # Ask user to input the distance on the map. sTxt = "Please enter the relative distance in mm from the map" fRel_mm = misc.get_float(sTxt, bNeg=True) if fRel_mm == None: return fRel_dist = fRel_mm * (fScale / 1e6) # Convert map mm to km fRel_dist = round(fRel_dist, 2) print("km distance: {0}".format(fRel_dist)) # Relative distane known. Now calculate the absolute distance iEntry = iDist_choice - 1 # 1-count to 0-count fOld_dist = dData[iEntry]["dVal"]["km"] fDist = fOld_dist + fRel_dist fDist = round(fDist, 2) # Absolute distance is now known. # Non-initial condition is being closed here. sMenu = "\nPlease select 'event' category:\n" sMenu += "1. Build Track\n" sMenu += "2. Build Junction\n" sMenu += "3. Station\n" sMenu += "4. Non-rail crossing\n" sMenu += "5. [RFU] --- Structure\n" sMenu += "6. Elevation\n" sMenu += "7. [RFU] --- Signal\n" sMenu += "8. Sign (speed / warning / direction)" print(sMenu) sInput = input().upper() dPack = { "tremb": ccTremb, # For full DB access. "db": cLine, "dEntry": { "km": fDist, "id": iHighest + 1, # Unique reference number "item": None, "type": None, "xVal": None }, } if sInput == "1": dEntry = qEvent_track(dPack) elif sInput == "2": dEntry = qEvent_junction(dPack) elif sInput == "3": dEntry = qEvent_station(dPack) elif sInput == "4": dEntry = qEvent_crossing(dPack) elif sInput == "6": dEntry = qEvent_elevation(dPack) elif sInput == "8": dEntry = qEvent_signage(dPack) else: print("\n\aInvalid selection. Exiting") return if dEntry == None: return # We got an error somewhere. # Add the item to the database dAdd_line = { "my_id": sCode, # K00-001 "tag": "val", # Describes that this is the description "dVal": dEntry, # The data generated } sTxt = "Is this entry OK?: \n{0}\n".format(dAdd_line) yn_final = misc.get_binary(sTxt) if yn_final == "N": print("User confirmation declined. Exiting") return # Add to the data base. cLine.insert_one(dAdd_line) print(">>>\nNew item added")