diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index 2c701e218..949db163c 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -1,48 +1,66 @@ --- Bicycle profile -api_version = 4 +-- Foot profile +local http = require("socket.http") -- LuaSocket for HTTP requests +local json = require("cjson") + +api_version = 2 Set = require('lib/set') Sequence = require('lib/sequence') Handlers = require("lib/way_handlers") -TrafficSignal = require("lib/traffic_signal") find_access_tag = require("lib/access").find_access_tag -limit = require("lib/maxspeed").limit -Measure = require("lib/measure") +stations_data = nil + + +function fetch_pollution_data() + local url = "http://128.199.51.173:8000/routes/api/pollution/PM10" + local response, status = http.request(url) + + if status == 200 and response then + print("Raw response:", response) + local success, data = pcall(json.decode, response) -- Manejar errores de JSON + if success and data and data.stations then + print("Pollution data fetched successfully.") + print("Number of stations:", #data.stations) + return data + else + print("Failed to decode JSON or missing 'stations' key.") + end + else + print("HTTP request failed. Status:", status) + end + + -- Fallback a datos vacíos si hay un error + return { stations = {} } +end + + function setup() - local default_speed = 15 - local walking_speed = 4 + local walking_speed = 5 + stations_data = fetch_pollution_data() + -- Check if data was successfully retrieved + if not stations_data or not stations_data.stations then + print("Warning: Pollution data could not be loaded. Defaulting to no pollution.") + stations_data = { stations = {} } -- Fallback to empty station data + else + print("Pollution data loaded successfully.") + end return { properties = { - u_turn_penalty = 20, - traffic_light_penalty = 2, - --weight_name = 'cyclability', weight_name = 'duration', - process_call_tagless_node = false, - max_speed_for_map_matching = 110/3.6, -- kmph -> m/s - use_turn_restrictions = false, + max_speed_for_map_matching = 40/3.6, -- kmph -> m/s + call_tagless_node_function = false, + traffic_light_penalty = 2, + u_turn_penalty = 2, continue_straight_at_waypoint = false, - mode_change_penalty = 30, + use_turn_restrictions = false, }, - default_mode = mode.cycling, - default_speed = default_speed, - walking_speed = walking_speed, - oneway_handling = true, - turn_penalty = 6, - turn_bias = 1.4, - use_public_transport = true, - - -- Exclude narrow ways, in particular to route with cargo bike - width = nil, -- Cargo bike could 0.5 width, in meters - exclude_cargo_bike = false, - - allowed_start_modes = Set { - mode.cycling, - mode.pushing_bike - }, + default_mode = mode.walking, + default_speed = walking_speed, + oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway' barrier_blacklist = Set { 'yes', @@ -52,120 +70,85 @@ function setup() access_tag_whitelist = Set { 'yes', + 'foot', 'permissive', 'designated' }, access_tag_blacklist = Set { 'no', - 'private', 'agricultural', 'forestry', + 'private', 'delivery', - -- When a way is tagged with `use_sidepath` a parallel way suitable for - -- cyclists is mapped and must be used instead (by law). This tag is - -- used on ways that normally may be used by cyclists, but not when - -- a signposted parallel cycleway is available. For purposes of routing - -- cyclists, this value should be treated as 'no access for bicycles'. - 'use_sidepath' }, restricted_access_tag_list = Set { }, restricted_highway_whitelist = Set { }, - -- tags disallow access to in combination with highway=service - service_access_tag_blacklist = Set { }, - - construction_whitelist = Set { - 'no', - 'widening', - 'minor', - }, + construction_whitelist = Set {}, access_tags_hierarchy = Sequence { - 'bicycle', - 'vehicle', + 'foot', 'access' }, - restrictions = Set { - 'bicycle' + -- tags disallow access to in combination with highway=service + service_access_tag_blacklist = Set { }, + + restrictions = Sequence { + 'foot' }, - cycleway_tags = Set { - 'track', - 'lane', - 'share_busway', - 'sharrow', - 'shared', - 'shared_lane' + -- list of suffixes to suppress in name change instructions + suffix_list = Set { + 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East' }, - opposite_cycleway_tags = Set { - 'opposite', - 'opposite_lane', - 'opposite_track', + avoid = Set { + 'impassable', + 'proposed' }, - -- reduce the driving speed by 30% for unsafe roads - -- only used for cyclability metric - unsafe_highway_list = { - primary = 0.5, - secondary = 0.65, - tertiary = 0.8, - primary_link = 0.5, - secondary_link = 0.65, - tertiary_link = 0.8, - }, + speeds = Sequence { + highway = { + primary = walking_speed, + primary_link = walking_speed, + secondary = walking_speed, + secondary_link = walking_speed, + tertiary = walking_speed, + tertiary_link = walking_speed, + unclassified = walking_speed, + residential = walking_speed, + road = walking_speed, + living_street = walking_speed, + service = walking_speed, + track = walking_speed, + path = walking_speed, + steps = walking_speed, + pedestrian = walking_speed, + platform = walking_speed, + footway = walking_speed, + pier = walking_speed, + }, - service_penalties = { - alley = 0.5, - }, + railway = { + platform = walking_speed + }, - bicycle_speeds = { - cycleway = default_speed, - primary = default_speed, - primary_link = default_speed, - secondary = default_speed, - secondary_link = default_speed, - tertiary = default_speed, - tertiary_link = default_speed, - residential = default_speed, - unclassified = default_speed, - living_street = default_speed, - road = default_speed, - service = default_speed, - track = 12, - path = 13 - }, + amenity = { + parking = walking_speed, + parking_entrance= walking_speed + }, - pedestrian_speeds = { - footway = walking_speed, - pedestrian = walking_speed, - steps = 2 - }, + man_made = { + pier = walking_speed + }, - railway_speeds = { - train = 10, - railway = 10, - subway = 10, - light_rail = 10, - monorail = 10, - tram = 10 - }, - - platform_speeds = { - platform = walking_speed - }, - - amenity_speeds = { - parking = 10, - parking_entrance = 10 - }, - - man_made_speeds = { - pier = walking_speed + leisure = { + track = walking_speed + } }, route_speeds = { @@ -173,487 +156,119 @@ function setup() }, bridge_speeds = { - movable = 5 }, surface_speeds = { - asphalt = default_speed, - chipseal = default_speed, - concrete = default_speed, - concrete_lanes = default_speed, - wood = 10, - metal = 10, - ["cobblestone:flattened"] = 10, - paving_stones = 10, - compacted = 10, - cobblestone = 7, - unpaved = 6, - fine_gravel = 10, - gravel = 6, - pebblestone = 6, - grass_paver = 6, - ground = 10, - dirt = 8, - earth = 6, - grass = 6, - mud = 3, - sand = 3, - woodchips = 3, - sett = 9 - }, - - classes = Sequence { - 'ferry', 'tunnel' - }, - - -- Which classes should be excludable - -- This increases memory usage so its disabled by default. - excludable = Sequence { --- Set {'ferry'} + fine_gravel = walking_speed*0.75, + gravel = walking_speed*0.75, + pebblestone = walking_speed*0.75, + mud = walking_speed*0.5, + sand = walking_speed*0.5 }, tracktype_speeds = { }, smoothness_speeds = { - }, - - avoid = Set { - 'impassable', - 'construction', - 'proposed' } } end -function process_node(profile, node, result) - -- parse access and barrier tags - local highway = node:get_value_by_key("highway") - local is_crossing = highway and highway == "crossing" +function calculate_pollution(lat, lon) + -- Calcular contaminación + local pollution_value = 0 + local total_weight = 0 + local weight = 0 + local p = 1.8 + local max_distance = 3 + if stations_data and stations_data.stations then + for _, station in ipairs(stations_data.stations) do + local station_lat = tonumber(station.lat) + local station_lon = tonumber(station.lon) + local latest_reading = tonumber(station.pollution) + if station_lat and station_lon and latest_reading then + -- Fórmula de distancia usando Haversine + local R = 6371 -- Radio de la Tierra en km + local dlat = math.rad(station_lat - lat) + local dlon = math.rad(station_lon - lon) + local a = math.sin(dlat / 2)^2 + + math.cos(math.rad(lat)) * math.cos(math.rad(station_lat)) * math.sin(dlon / 2)^2 + local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + local distance = R * c + + -- Ponderación ajustada + weight = 1 / ((distance + 1)) + weight = tonumber(string.format("%.6f", weight)) + pollution_value = pollution_value + (latest_reading * weight) + --total_weight = total_weight + weight + + end + end + --print(pollution_value) + return pollution_value + else + print("No station data available.") + return 0 + end +end + +function process_node(profile, node, result) + -- Parse access and barrier tags local access = find_access_tag(node, profile.access_tags_hierarchy) - if access and access ~= "" then - -- access restrictions on crossing nodes are not relevant for - -- the traffic on the road - if profile.access_tag_blacklist[access] and not is_crossing then + if access then + if profile.access_tag_blacklist[access] then result.barrier = true end else local barrier = node:get_value_by_key("barrier") - if barrier and "" ~= barrier then - if profile.barrier_blacklist[barrier] then + if barrier then + -- Make an exception for rising bollard barriers + local bollard = node:get_value_by_key("bollard") + local rising_bollard = bollard and "rising" == bollard + + if profile.barrier_blacklist[barrier] and not rising_bollard then result.barrier = true end end end - - if profile.exclude_cargo_bike then - local cargo_bike = node:get_value_by_key("cargo_bike") - if cargo_bike and cargo_bike == "no" then - result.barrier = true - end - end - - -- width - if profile.width then - -- From barrier=cycle_barrier or other barriers - local maxwidth_physical = node:get_value_by_key("maxwidth:physical") - local maxwidth_physical_meter = maxwidth_physical and Measure.parse_value_meters(maxwidth_physical) or 99 - local opening = node:get_value_by_key("opening") - local opening_meter = opening and Measure.parse_value_meters(opening) or 99 - local width_meter = math.min(maxwidth_physical_meter, opening_meter) - - if width_meter and width_meter < profile.width then - result.barrier = true - end - end - - -- check if node is a traffic light - result.traffic_lights = TrafficSignal.get_value(node) -end - -function handle_bicycle_tags(profile,way,result,data) - -- initial routability check, filters out buildings, boundaries, etc - data.route = way:get_value_by_key("route") - data.man_made = way:get_value_by_key("man_made") - data.railway = way:get_value_by_key("railway") - data.amenity = way:get_value_by_key("amenity") - data.public_transport = way:get_value_by_key("public_transport") - data.bridge = way:get_value_by_key("bridge") - - if (not data.highway or data.highway == '') and - (not data.route or data.route == '') and - (not profile.use_public_transport or not data.railway or data.railway=='') and - (not data.amenity or data.amenity=='') and - (not data.man_made or data.man_made=='') and - (not data.public_transport or data.public_transport=='') and - (not data.bridge or data.bridge=='') - then - return false - end - - -- access - data.access = find_access_tag(way, profile.access_tags_hierarchy) - if data.access and profile.access_tag_blacklist[data.access] then - return false - end - - -- other tags - data.junction = way:get_value_by_key("junction") - data.maxspeed = Measure.get_max_speed(way:get_value_by_key ("maxspeed")) or 0 - data.maxspeed_forward = Measure.get_max_speed(way:get_value_by_key("maxspeed:forward")) or 0 - data.maxspeed_backward = Measure.get_max_speed(way:get_value_by_key("maxspeed:backward")) or 0 - data.barrier = way:get_value_by_key("barrier") - data.oneway = way:get_value_by_key("oneway") - data.oneway_bicycle = way:get_value_by_key("oneway:bicycle") - data.cycleway = way:get_value_by_key("cycleway") - data.cycleway_left = way:get_value_by_key("cycleway:left") - data.cycleway_right = way:get_value_by_key("cycleway:right") - data.duration = way:get_value_by_key("duration") - data.service = way:get_value_by_key("service") - data.foot = way:get_value_by_key("foot") - data.foot_forward = way:get_value_by_key("foot:forward") - data.foot_backward = way:get_value_by_key("foot:backward") - data.bicycle = way:get_value_by_key("bicycle") - - speed_handler(profile,way,result,data) - - oneway_handler(profile,way,result,data) - - cycleway_handler(profile,way,result,data) - - bike_push_handler(profile,way,result,data) - - -- width should be after bike_push - width_handler(profile,way,result,data) - - -- maxspeed - limit( result, data.maxspeed, data.maxspeed_forward, data.maxspeed_backward ) - - -- not routable if no speed assigned - -- this avoid assertions in debug builds - if result.forward_speed <= 0 and result.duration <= 0 then - result.forward_mode = mode.inaccessible - end - if result.backward_speed <= 0 and result.duration <= 0 then - result.backward_mode = mode.inaccessible - end - - safety_handler(profile,way,result,data) end - -function speed_handler(profile,way,result,data) - - data.way_type_allows_pushing = false - - -- speed - local bridge_speed = profile.bridge_speeds[data.bridge] - if (bridge_speed and bridge_speed > 0) then - data.highway = data.bridge - if data.duration and durationIsValid(data.duration) then - result.duration = math.max( parseDuration(data.duration), 1 ) - end - result.forward_speed = bridge_speed - result.backward_speed = bridge_speed - data.way_type_allows_pushing = true - elseif profile.route_speeds[data.route] then - -- ferries (doesn't cover routes tagged using relations) - result.forward_mode = mode.ferry - result.backward_mode = mode.ferry - if data.duration and durationIsValid(data.duration) then - result.duration = math.max( 1, parseDuration(data.duration) ) - else - result.forward_speed = profile.route_speeds[data.route] - result.backward_speed = profile.route_speeds[data.route] - end - -- railway platforms (old tagging scheme) - elseif data.railway and profile.platform_speeds[data.railway] then - result.forward_speed = profile.platform_speeds[data.railway] - result.backward_speed = profile.platform_speeds[data.railway] - data.way_type_allows_pushing = true - -- public_transport platforms (new tagging platform) - elseif data.public_transport and profile.platform_speeds[data.public_transport] then - result.forward_speed = profile.platform_speeds[data.public_transport] - result.backward_speed = profile.platform_speeds[data.public_transport] - data.way_type_allows_pushing = true - -- railways - elseif profile.use_public_transport and data.railway and profile.railway_speeds[data.railway] and profile.access_tag_whitelist[data.access] then - result.forward_mode = mode.train - result.backward_mode = mode.train - result.forward_speed = profile.railway_speeds[data.railway] - result.backward_speed = profile.railway_speeds[data.railway] - elseif data.amenity and profile.amenity_speeds[data.amenity] then - -- parking areas - result.forward_speed = profile.amenity_speeds[data.amenity] - result.backward_speed = profile.amenity_speeds[data.amenity] - data.way_type_allows_pushing = true - elseif profile.bicycle_speeds[data.highway] then - -- regular ways - result.forward_speed = profile.bicycle_speeds[data.highway] - result.backward_speed = profile.bicycle_speeds[data.highway] - data.way_type_allows_pushing = true - elseif data.access and profile.access_tag_whitelist[data.access] then - -- unknown way, but valid access tag - result.forward_speed = profile.default_speed - result.backward_speed = profile.default_speed - data.way_type_allows_pushing = true - end -end - -function oneway_handler(profile,way,result,data) - -- oneway - data.implied_oneway = data.junction == "roundabout" or data.junction == "circular" or data.highway == "motorway" - data.reverse = false - - if data.oneway_bicycle == "yes" or data.oneway_bicycle == "1" or data.oneway_bicycle == "true" then - result.backward_mode = mode.inaccessible - elseif data.oneway_bicycle == "no" or data.oneway_bicycle == "0" or data.oneway_bicycle == "false" then - -- prevent other cases - elseif data.oneway_bicycle == "-1" then - result.forward_mode = mode.inaccessible - data.reverse = true - elseif data.oneway == "yes" or data.oneway == "1" or data.oneway == "true" then - result.backward_mode = mode.inaccessible - elseif data.oneway == "no" or data.oneway == "0" or data.oneway == "false" then - -- prevent other cases - elseif data.oneway == "-1" then - result.forward_mode = mode.inaccessible - data.reverse = true - elseif data.implied_oneway then - result.backward_mode = mode.inaccessible - end -end - -function cycleway_handler(profile,way,result,data) - -- cycleway - data.has_cycleway_forward = false - data.has_cycleway_backward = false - data.is_twoway = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible and not data.implied_oneway - - -- cycleways on normal roads - if data.is_twoway then - if data.cycleway and profile.cycleway_tags[data.cycleway] then - data.has_cycleway_backward = true - data.has_cycleway_forward = true - end - if (data.cycleway_right and profile.cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left]) then - data.has_cycleway_forward = true - end - if (data.cycleway_left and profile.cycleway_tags[data.cycleway_left]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right]) then - data.has_cycleway_backward = true - end - else - local has_twoway_cycleway = (data.cycleway and profile.opposite_cycleway_tags[data.cycleway]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left]) - local has_opposite_cycleway = (data.cycleway_left and profile.opposite_cycleway_tags[data.cycleway_left]) or (data.cycleway_right and profile.opposite_cycleway_tags[data.cycleway_right]) - local has_oneway_cycleway = (data.cycleway and profile.cycleway_tags[data.cycleway]) or (data.cycleway_right and profile.cycleway_tags[data.cycleway_right]) or (data.cycleway_left and profile.cycleway_tags[data.cycleway_left]) - - -- set cycleway even though it is an one-way if opposite is tagged - if has_twoway_cycleway then - data.has_cycleway_backward = true - data.has_cycleway_forward = true - elseif has_opposite_cycleway then - if not data.reverse then - data.has_cycleway_backward = true - else - data.has_cycleway_forward = true - end - elseif has_oneway_cycleway then - if not data.reverse then - data.has_cycleway_forward = true - else - data.has_cycleway_backward = true - end - - end - end - - if data.has_cycleway_backward then - result.backward_mode = mode.cycling - result.backward_speed = profile.bicycle_speeds["cycleway"] - end - - if data.has_cycleway_forward then - result.forward_mode = mode.cycling - result.forward_speed = profile.bicycle_speeds["cycleway"] - end -end - -function width_handler(profile,way,result,data) - if profile.exclude_cargo_bike then - local cargo_bike = way:get_value_by_key("cargo_bike") - if cargo_bike and cargo_bike == "no" then - result.forward_mode = mode.inaccessible - result.backward_mode = mode.inaccessible - end - end - - if profile.width then - local width = way:get_value_by_key("width") - if width then - local width_meter = Measure.parse_value_meters(width) - if width_meter and width_meter < profile.width then - result.forward_mode = mode.inaccessible - result.backward_mode = mode.inaccessible - end - end - end -end - -function bike_push_handler(profile,way,result,data) - -- pushing bikes - if no other mode found - if result.forward_mode == mode.inaccessible or result.backward_mode == mode.inaccessible or - result.forward_speed == -1 or result.backward_speed == -1 then - if data.foot ~= 'no' then - local push_forward_speed = nil - local push_backward_speed = nil - - if profile.pedestrian_speeds[data.highway] then - push_forward_speed = profile.pedestrian_speeds[data.highway] - push_backward_speed = profile.pedestrian_speeds[data.highway] - elseif data.man_made and profile.man_made_speeds[data.man_made] then - push_forward_speed = profile.man_made_speeds[data.man_made] - push_backward_speed = profile.man_made_speeds[data.man_made] - else - if data.foot == 'yes' then - push_forward_speed = profile.walking_speed - if not data.implied_oneway then - push_backward_speed = profile.walking_speed - end - elseif data.foot_forward == 'yes' then - push_forward_speed = profile.walking_speed - elseif data.foot_backward == 'yes' then - push_backward_speed = profile.walking_speed - elseif data.way_type_allows_pushing then - push_forward_speed = profile.walking_speed - if not data.implied_oneway then - push_backward_speed = profile.walking_speed - end - end - end - - if push_forward_speed and (result.forward_mode == mode.inaccessible or result.forward_speed == -1) then - result.forward_mode = mode.pushing_bike - result.forward_speed = push_forward_speed - end - if push_backward_speed and (result.backward_mode == mode.inaccessible or result.backward_speed == -1)then - result.backward_mode = mode.pushing_bike - result.backward_speed = push_backward_speed - end - - end - - end - - -- dismount - if data.bicycle == "dismount" then - result.forward_mode = mode.pushing_bike - result.backward_mode = mode.pushing_bike - result.forward_speed = profile.walking_speed - result.backward_speed = profile.walking_speed - end -end - -function safety_handler(profile,way,result,data) - -- convert duration into cyclability - if profile.properties.weight_name == 'cyclability' then - local safety_penalty = profile.unsafe_highway_list[data.highway] or 1. - local is_unsafe = safety_penalty < 1 - - -- primaries that are one ways are probably huge primaries where the lanes need to be separated - if is_unsafe and data.highway == 'primary' and not data.is_twoway then - safety_penalty = safety_penalty * 0.5 - end - if is_unsafe and data.highway == 'secondary' and not data.is_twoway then - safety_penalty = safety_penalty * 0.6 - end - - local forward_is_unsafe = is_unsafe and not data.has_cycleway_forward - local backward_is_unsafe = is_unsafe and not data.has_cycleway_backward - local is_undesireable = data.highway == "service" and profile.service_penalties[data.service] - local forward_penalty = 1. - local backward_penalty = 1. - if forward_is_unsafe then - forward_penalty = math.min(forward_penalty, safety_penalty) - end - if backward_is_unsafe then - backward_penalty = math.min(backward_penalty, safety_penalty) - end - - if is_undesireable then - forward_penalty = math.min(forward_penalty, profile.service_penalties[data.service]) - backward_penalty = math.min(backward_penalty, profile.service_penalties[data.service]) - end - - if result.forward_speed > 0 then - -- convert from km/h to m/s - result.forward_rate = result.forward_speed / 3.6 * forward_penalty - end - if result.backward_speed > 0 then - -- convert from km/h to m/s - result.backward_rate = result.backward_speed / 3.6 * backward_penalty - end - if result.duration > 0 then - result.weight = result.duration / forward_penalty - end - end -end - - - +-- main entry point for processsing a way function process_way(profile, way, result) - -- the initial filtering of ways based on presence of tags + -- the intial filtering of ways based on presence of tags -- affects processing times significantly, because all ways -- have to be checked. - -- to increase performance, prefetching and initial tag check - -- is done directly instead of via a handler. + -- to increase performance, prefetching and intial tag check + -- is done in directly instead of via a handler. - -- in general we should try to abort as soon as + -- in general we should try to abort as soon as -- possible if the way is not routable, to avoid doing -- unnecessary work. this implies we should check things that -- commonly forbids access early, and handle edge cases later. -- data table for storing intermediate values during processing - local data = { -- prefetch tags - highway = way:get_value_by_key('highway'), - - route = nil, - man_made = nil, - railway = nil, - amenity = nil, - public_transport = nil, - bridge = nil, - - access = nil, - - junction = nil, - maxspeed = nil, - maxspeed_forward = nil, - maxspeed_backward = nil, - barrier = nil, - oneway = nil, - oneway_bicycle = nil, - cycleway = nil, - cycleway_left = nil, - cycleway_right = nil, - duration = nil, - service = nil, - foot = nil, - foot_forward = nil, - foot_backward = nil, - bicycle = nil, - - way_type_allows_pushing = false, - has_cycleway_forward = false, - has_cycleway_backward = false, - is_twoway = true, - reverse = false, - implied_oneway = false + highway = way:get_value_by_key("highway"), } + -- Verificar si el objeto `way` está definido + if not way then + print("Error: way is nil.") + return + end + + + -- perform an quick initial check and abort if the way is + -- obviously not routable. here we require at least one + -- of the prefetched tags to be present, ie. the data table + -- cannot be empty + if next(data) == nil then -- is the data table empty? + return + end + local handlers = Sequence { -- set the default mode for this profile. if can be changed later -- in case it turns we're e.g. on a ferry @@ -664,61 +279,82 @@ function process_way(profile, way, result) -- toll=yes and oneway=reversible WayHandlers.blocked_ways, - -- our main handler - handle_bicycle_tags, + -- determine access status by checking our hierarchy of + -- access tags, e.g: motorcar, motor_vehicle, vehicle + WayHandlers.access, + + -- check whether forward/backward directons are routable + WayHandlers.oneway, + + -- check whether forward/backward directons are routable + WayHandlers.destinations, + + -- check whether we're using a special transport mode + WayHandlers.ferries, + WayHandlers.movables, -- compute speed taking into account way type, maxspeed tags, etc. + WayHandlers.speed, WayHandlers.surface, -- handle turn lanes and road classification, used for guidance WayHandlers.classification, - -- handle allowed start/end modes - WayHandlers.startpoint, - - -- handle roundabouts + -- handle various other flags WayHandlers.roundabouts, + WayHandlers.startpoint, -- set name, ref and pronunciation WayHandlers.names, - -- set classes - WayHandlers.classes, - -- set weight properties of the way - WayHandlers.weights + WayHandlers.weights, } WayHandlers.run(profile, way, result, data, handlers) end -function process_turn(profile, turn) - -- compute turn penalty as angle^2, with a left/right bias - local normalized_angle = turn.angle / 90.0 - if normalized_angle >= 0.0 then - turn.duration = normalized_angle * normalized_angle * profile.turn_penalty / profile.turn_bias - else - turn.duration = normalized_angle * normalized_angle * profile.turn_penalty * profile.turn_bias - end +function process_turn (profile, turn) + turn.duration = 0. - if turn.is_u_turn then - turn.duration = turn.duration + profile.properties.u_turn_penalty + if turn.direction_modifier == direction_modifier.u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = profile.properties.traffic_light_penalty end - if profile.properties.weight_name == 'cyclability' then - turn.weight = turn.duration - end - if turn.source_mode == mode.cycling and turn.target_mode ~= mode.cycling then - turn.weight = turn.weight + profile.properties.mode_change_penalty + if profile.properties.weight_name == 'routability' then + -- penalize turns from non-local access only segments onto local access only tags + if not turn.source_restricted and turn.target_restricted then + turn.weight = turn.weight + 3000 + end end end +function process_segment(profile, segment) + -- Extract coordinates of the start and end points + local source_lat, source_lon = segment.source.lat, segment.source.lon + local target_lat, target_lon = segment.target.lat, segment.target.lon + + -- Calculate pollution impact at source and target + local pollution_source = calculate_pollution(source_lat, source_lon) + local pollution_target = calculate_pollution(target_lat, target_lon) + + + -- Average pollution for the segment + local avg_pollution = (pollution_source + pollution_target) / 2 + --print(avg_pollution) + + -- Adjust weight and duration based on pollution level + segment.weight = segment.weight + (avg_pollution^1.4) +end + + return { setup = setup, - process_way = process_way, + process_way = process_way, process_node = process_node, - process_turn = process_turn + process_turn = process_turn, + process_segment = process_segment } diff --git a/profiles/car.lua b/profiles/car.lua index 076a93ee1..928bca319 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -1,376 +1,242 @@ --- Car profile -api_version = 4 +-- Foot profile +local http = require("socket.http") -- LuaSocket for HTTP requests +local json = require("cjson") + +api_version = 2 Set = require('lib/set') Sequence = require('lib/sequence') Handlers = require("lib/way_handlers") -Relations = require("lib/relations") -TrafficSignal = require("lib/traffic_signal") find_access_tag = require("lib/access").find_access_tag -limit = require("lib/maxspeed").limit -Utils = require("lib/utils") -Measure = require("lib/measure") +stations_data = nil + + +function fetch_pollution_data() + local url = "http://128.199.51.173:8000/routes/api/pollution/PM2.5/" + local response, status = http.request(url) + + if status == 200 and response then + print("Raw response:", response) + local success, data = pcall(json.decode, response) -- Manejar errores de JSON + if success and data and data.stations then + print("Pollution data fetched successfully.") + print("Number of stations:", #data.stations) + return data + else + print("Failed to decode JSON or missing 'stations' key.") + end + else + print("HTTP request failed. Status:", status) + end + + -- Fallback a datos vacíos si hay un error + return { stations = {} } +end + + function setup() + local walking_speed = 5 + stations_data = fetch_pollution_data() + + -- Check if data was successfully retrieved + if not stations_data or not stations_data.stations then + print("Warning: Pollution data could not be loaded. Defaulting to no pollution.") + stations_data = { stations = {} } -- Fallback to empty station data + else + print("Pollution data loaded successfully.") + end return { properties = { - max_speed_for_map_matching = 180/3.6, -- 180kmph -> m/s - -- For routing based on duration, but weighted for preferring certain roads - weight_name = 'routability', - -- For shortest duration without penalties for accessibility - -- weight_name = 'duration', - -- For shortest distance without penalties for accessibility - -- weight_name = 'distance', - process_call_tagless_node = false, - u_turn_penalty = 20, - continue_straight_at_waypoint = true, - use_turn_restrictions = true, - left_hand_driving = false, - traffic_light_penalty = 2, + weight_name = 'duration', + max_speed_for_map_matching = 40/3.6, -- kmph -> m/s + call_tagless_node_function = false, + traffic_light_penalty = 2, + u_turn_penalty = 2, + continue_straight_at_waypoint = false, + use_turn_restrictions = false, }, - default_mode = mode.driving, - default_speed = 10, - oneway_handling = true, - side_road_multiplier = 0.8, - turn_penalty = 7.5, - speed_reduction = 0.8, - turn_bias = 1.075, - cardinal_directions = false, + default_mode = mode.walking, + default_speed = walking_speed, + oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway' - -- Size of the vehicle, to be limited by physical restriction of the way - vehicle_height = 2.0, -- in meters, 2.0m is the height slightly above biggest SUVs - vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m - - -- Size of the vehicle, to be limited mostly by legal restriction of the way - vehicle_length = 4.8, -- in meters, 4.8m is the length of large or family car - vehicle_weight = 2000, -- in kilograms - - -- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other - suffix_list = { - 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea' - }, - - barrier_whitelist = Set { - 'cattle_grid', - 'border_control', - 'toll_booth', - 'sally_port', - 'gate', - 'lift_gate', - 'no', - 'entrance', - 'height_restrictor', - 'arch' + barrier_blacklist = Set { + 'yes', + 'wall', + 'fence' }, access_tag_whitelist = Set { 'yes', - 'motorcar', - 'motor_vehicle', - 'vehicle', + 'foot', 'permissive', - 'designated', - 'hov' + 'designated' }, access_tag_blacklist = Set { 'no', 'agricultural', 'forestry', - 'emergency', - 'psv', - 'customers', 'private', 'delivery', - 'destination' }, - -- tags disallow access to in combination with highway=service - service_access_tag_blacklist = Set { - 'private' - }, + restricted_access_tag_list = Set { }, - restricted_access_tag_list = Set { - 'private', - 'delivery', - 'destination', - 'customers', - }, + restricted_highway_whitelist = Set { }, + + construction_whitelist = Set {}, access_tags_hierarchy = Sequence { - 'motorcar', - 'motor_vehicle', - 'vehicle', + 'foot', 'access' }, - service_tag_forbidden = Set { - 'emergency_access' - }, + -- tags disallow access to in combination with highway=service + service_access_tag_blacklist = Set { }, restrictions = Sequence { - 'motorcar', - 'motor_vehicle', - 'vehicle' + 'foot' }, - classes = Sequence { - 'toll', 'motorway', 'ferry', 'restricted', 'tunnel' - }, - - -- classes to support for exclude flags - excludable = Sequence { - Set {'toll'}, - Set {'motorway'}, - Set {'ferry'} + -- list of suffixes to suppress in name change instructions + suffix_list = Set { + 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East' }, avoid = Set { - 'area', - -- 'toll', -- uncomment this to avoid tolls - 'reversible', 'impassable', - 'hov_lanes', - 'steps', - 'construction', 'proposed' }, speeds = Sequence { highway = { - motorway = 90, - motorway_link = 45, - trunk = 85, - trunk_link = 40, - primary = 65, - primary_link = 30, - secondary = 55, - secondary_link = 25, - tertiary = 40, - tertiary_link = 20, - unclassified = 25, - residential = 25, - living_street = 10, - service = 15 + primary = walking_speed, + primary_link = walking_speed, + secondary = walking_speed, + secondary_link = walking_speed, + tertiary = walking_speed, + tertiary_link = walking_speed, + unclassified = walking_speed, + residential = walking_speed, + road = walking_speed, + living_street = walking_speed, + service = walking_speed, + track = walking_speed, + path = walking_speed, + steps = walking_speed, + pedestrian = walking_speed, + platform = walking_speed, + footway = walking_speed, + pier = walking_speed, + }, + + railway = { + platform = walking_speed + }, + + amenity = { + parking = walking_speed, + parking_entrance= walking_speed + }, + + man_made = { + pier = walking_speed + }, + + leisure = { + track = walking_speed } }, - service_penalties = { - alley = 0.5, - parking = 0.5, - parking_aisle = 0.5, - driveway = 0.5, - ["drive-through"] = 0.5, - ["drive-thru"] = 0.5 - }, - - restricted_highway_whitelist = Set { - 'motorway', - 'motorway_link', - 'trunk', - 'trunk_link', - 'primary', - 'primary_link', - 'secondary', - 'secondary_link', - 'tertiary', - 'tertiary_link', - 'residential', - 'living_street', - 'unclassified', - 'service' - }, - - construction_whitelist = Set { - 'no', - 'widening', - 'minor', - }, - route_speeds = { - ferry = 5, - shuttle_train = 10 + ferry = 5 }, bridge_speeds = { - movable = 5 }, - -- surface/trackype/smoothness - -- values were estimated from looking at the photos at the relevant wiki pages - - -- max speed for surfaces surface_speeds = { - asphalt = nil, -- nil mean no limit. removing the line has the same effect - concrete = nil, - ["concrete:plates"] = nil, - ["concrete:lanes"] = nil, - paved = nil, - - cement = 80, - compacted = 80, - fine_gravel = 80, - - paving_stones = 60, - metal = 60, - bricks = 60, - - grass = 40, - wood = 40, - sett = 40, - grass_paver = 40, - gravel = 40, - unpaved = 40, - ground = 40, - dirt = 40, - pebblestone = 40, - tartan = 40, - - cobblestone = 30, - clay = 30, - - earth = 20, - stone = 20, - rocky = 20, - sand = 20, - - mud = 10 + fine_gravel = walking_speed*0.75, + gravel = walking_speed*0.75, + pebblestone = walking_speed*0.75, + mud = walking_speed*0.5, + sand = walking_speed*0.5 }, - -- max speed for tracktypes tracktype_speeds = { - grade1 = 60, - grade2 = 40, - grade3 = 30, - grade4 = 25, - grade5 = 20 }, - -- max speed for smoothnesses smoothness_speeds = { - intermediate = 80, - bad = 40, - very_bad = 20, - horrible = 10, - very_horrible = 5, - impassable = 0 - }, - - -- http://wiki.openstreetmap.org/wiki/Speed_limits - maxspeed_table_default = { - urban = 50, - rural = 90, - trunk = 110, - motorway = 130 - }, - - -- List only exceptions - maxspeed_table = { - ["at:rural"] = 100, - ["at:trunk"] = 100, - ["be:motorway"] = 120, - ["be-bru:rural"] = 70, - ["be-bru:urban"] = 30, - ["be-vlg:rural"] = 70, - ["bg:motorway"] = 140, - ["by:urban"] = 60, - ["by:motorway"] = 110, - ["ca-on:rural"] = 80, - ["ch:rural"] = 80, - ["ch:trunk"] = 100, - ["ch:motorway"] = 120, - ["cz:trunk"] = 0, - ["cz:motorway"] = 0, - ["de:living_street"] = 7, - ["de:rural"] = 100, - ["de:motorway"] = 0, - ["dk:rural"] = 80, - ["es:trunk"] = 90, - ["fr:rural"] = 80, - ["gb:nsl_single"] = (60*1609)/1000, - ["gb:nsl_dual"] = (70*1609)/1000, - ["gb:motorway"] = (70*1609)/1000, - ["nl:rural"] = 80, - ["nl:trunk"] = 100, - ['no:rural'] = 80, - ['no:motorway'] = 110, - ['ph:urban'] = 40, - ['ph:rural'] = 80, - ['ph:motorway'] = 100, - ['pl:rural'] = 100, - ['pl:trunk'] = 120, - ['pl:motorway'] = 140, - ["ro:trunk"] = 100, - ["ru:living_street"] = 20, - ["ru:urban"] = 60, - ["ru:motorway"] = 110, - ["uk:nsl_single"] = (60*1609)/1000, - ["uk:nsl_dual"] = (70*1609)/1000, - ["uk:motorway"] = (70*1609)/1000, - ['za:urban'] = 60, - ['za:rural'] = 100, - ["none"] = 140 - }, - - relation_types = Sequence { - "route" - }, - - -- classify highway tags when necessary for turn weights - highway_turn_classification = { - }, - - -- classify access tags when necessary for turn weights - access_turn_classification = { } } end -function process_node(profile, node, result, relations) - -- parse access and barrier tags +function calculate_pollution(lat, lon) + -- Calcular contaminación + local pollution_value = 0 + local total_weight = 0 + local weight = 0 + local p = 1.8 + local max_distance = 3 + if stations_data and stations_data.stations then + for _, station in ipairs(stations_data.stations) do + local station_lat = tonumber(station.lat) + local station_lon = tonumber(station.lon) + local latest_reading = tonumber(station.pollution) + + if station_lat and station_lon and latest_reading then + -- Fórmula de distancia usando Haversine + local R = 6371 -- Radio de la Tierra en km + local dlat = math.rad(station_lat - lat) + local dlon = math.rad(station_lon - lon) + local a = math.sin(dlat / 2)^2 + + math.cos(math.rad(lat)) * math.cos(math.rad(station_lat)) * math.sin(dlon / 2)^2 + local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + local distance = R * c + + -- Ponderación ajustada + weight = 1 / ((distance + 1)) + weight = tonumber(string.format("%.6f", weight)) + pollution_value = pollution_value + (latest_reading * weight) + --total_weight = total_weight + weight + + end + end + --print(pollution_value) + return pollution_value + else + print("No station data available.") + return 0 + end +end + +function process_node(profile, node, result) + -- Parse access and barrier tags local access = find_access_tag(node, profile.access_tags_hierarchy) if access then - if profile.access_tag_blacklist[access] and not profile.restricted_access_tag_list[access] then + if profile.access_tag_blacklist[access] then result.barrier = true end else local barrier = node:get_value_by_key("barrier") if barrier then - -- check height restriction barriers - local restricted_by_height = false - if barrier == 'height_restrictor' then - local maxheight = Measure.get_max_height(node:get_value_by_key("maxheight"), node) - restricted_by_height = maxheight and maxheight < profile.vehicle_height - end - - -- make an exception for rising bollard barriers + -- Make an exception for rising bollard barriers local bollard = node:get_value_by_key("bollard") local rising_bollard = bollard and "rising" == bollard - -- make an exception for lowered/flat barrier=kerb - -- and incorrect tagging of highway crossing kerb as highway barrier - local kerb = node:get_value_by_key("kerb") - local highway = node:get_value_by_key("highway") - local flat_kerb = kerb and ("lowered" == kerb or "flush" == kerb) - local highway_crossing_kerb = barrier == "kerb" and highway and highway == "crossing" - - if not profile.barrier_whitelist[barrier] - and not rising_bollard - and not flat_kerb - and not highway_crossing_kerb - or restricted_by_height then + if profile.barrier_blacklist[barrier] and not rising_bollard then result.barrier = true end end end - - -- check if node is a traffic light - result.traffic_lights = TrafficSignal.get_value(node) end -function process_way(profile, way, result, relations) + +-- main entry point for processsing a way +function process_way(profile, way, result) -- the intial filtering of ways based on presence of tags -- affects processing times significantly, because all ways -- have to be checked. @@ -385,21 +251,25 @@ function process_way(profile, way, result, relations) -- data table for storing intermediate values during processing local data = { -- prefetch tags - highway = way:get_value_by_key('highway'), - bridge = way:get_value_by_key('bridge'), - route = way:get_value_by_key('route') + highway = way:get_value_by_key("highway"), } + -- Verificar si el objeto `way` está definido + if not way then + print("Error: way is nil.") + return + end + + -- perform an quick initial check and abort if the way is - -- obviously not routable. - -- highway or route tags must be in data table, bridge is optional - if (not data.highway or data.highway == '') and - (not data.route or data.route == '') - then + -- obviously not routable. here we require at least one + -- of the prefetched tags to be present, ie. the data table + -- cannot be empty + if next(data) == nil then -- is the data table empty? return end - handlers = Sequence { + local handlers = Sequence { -- set the default mode for this profile. if can be changed later -- in case it turns we're e.g. on a ferry WayHandlers.default_mode, @@ -408,108 +278,83 @@ function process_way(profile, way, result, relations) -- routable. this includes things like status=impassable, -- toll=yes and oneway=reversible WayHandlers.blocked_ways, - WayHandlers.avoid_ways, - WayHandlers.handle_height, - WayHandlers.handle_width, - WayHandlers.handle_length, - WayHandlers.handle_weight, -- determine access status by checking our hierarchy of -- access tags, e.g: motorcar, motor_vehicle, vehicle WayHandlers.access, - -- check whether forward/backward directions are routable + -- check whether forward/backward directons are routable WayHandlers.oneway, - -- check a road's destination + -- check whether forward/backward directons are routable WayHandlers.destinations, -- check whether we're using a special transport mode WayHandlers.ferries, WayHandlers.movables, - -- handle service road restrictions - WayHandlers.service, - - -- handle hov - WayHandlers.hov, - -- compute speed taking into account way type, maxspeed tags, etc. WayHandlers.speed, - WayHandlers.maxspeed, WayHandlers.surface, - WayHandlers.penalties, - - -- compute class labels - WayHandlers.classes, -- handle turn lanes and road classification, used for guidance - WayHandlers.turn_lanes, WayHandlers.classification, -- handle various other flags WayHandlers.roundabouts, WayHandlers.startpoint, - WayHandlers.driving_side, -- set name, ref and pronunciation WayHandlers.names, -- set weight properties of the way WayHandlers.weights, - - -- set classification of ways relevant for turns - WayHandlers.way_classification_for_turn } - WayHandlers.run(profile, way, result, data, handlers, relations) - - if profile.cardinal_directions then - Relations.process_way_refs(way, relations, result) - end + WayHandlers.run(profile, way, result, data, handlers) end -function process_turn(profile, turn) - -- Use a sigmoid function to return a penalty that maxes out at turn_penalty - -- over the space of 0-180 degrees. Values here were chosen by fitting - -- the function to some turn penalty samples from real driving. - local turn_penalty = profile.turn_penalty - local turn_bias = turn.is_left_hand_driving and 1. / profile.turn_bias or profile.turn_bias +function process_turn (profile, turn) + turn.duration = 0. + + if turn.direction_modifier == direction_modifier.u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + end if turn.has_traffic_light then - turn.duration = profile.properties.traffic_light_penalty + turn.duration = profile.properties.traffic_light_penalty end - - if turn.number_of_roads > 2 or turn.source_mode ~= turn.target_mode or turn.is_u_turn then - if turn.angle >= 0 then - turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 / turn_bias) * turn.angle/180 - 6.5*turn_bias))) - else - turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 * turn_bias) * -turn.angle/180 - 6.5/turn_bias))) - end - - if turn.is_u_turn then - turn.duration = turn.duration + profile.properties.u_turn_penalty - end - end - - -- for distance based routing we don't want to have penalties based on turn angle - if profile.properties.weight_name == 'distance' then - turn.weight = 0 - else - turn.weight = turn.duration - end - if profile.properties.weight_name == 'routability' then -- penalize turns from non-local access only segments onto local access only tags if not turn.source_restricted and turn.target_restricted then - turn.weight = constants.max_turn_weight + turn.weight = turn.weight + 3000 end end end +function process_segment(profile, segment) + -- Extract coordinates of the start and end points + local source_lat, source_lon = segment.source.lat, segment.source.lon + local target_lat, target_lon = segment.target.lat, segment.target.lon + + -- Calculate pollution impact at source and target + local pollution_source = calculate_pollution(source_lat, source_lon) + local pollution_target = calculate_pollution(target_lat, target_lon) + + + -- Average pollution for the segment + local avg_pollution = (pollution_source + pollution_target) / 2 + --print(avg_pollution) + + -- Adjust weight and duration based on pollution level + segment.weight = segment.weight + (avg_pollution^1.4) +end + + return { setup = setup, - process_way = process_way, + process_way = process_way, process_node = process_node, - process_turn = process_turn + process_turn = process_turn, + process_segment = process_segment } diff --git a/profiles/foot.lua b/profiles/foot.lua index e8149f197..e32ba23dd 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -1,3 +1,4 @@ + -- Foot profile local http = require("socket.http") -- LuaSocket for HTTP requests local json = require("cjson") @@ -8,43 +9,44 @@ Set = require('lib/set') Sequence = require('lib/sequence') Handlers = require("lib/way_handlers") find_access_tag = require("lib/access").find_access_tag +stations_data = nil -function fetch_pollution_data(location) - -- Convert location userdata to a string - local location_str = tostring(location) - -- Check if the location is "(undefined,undefined)" - if location_str == "(undefined,undefined)" then - print("Location is undefined. Skipping pollution data fetch.") - return 0 -- Return 0 for undefined locations - end - - -- Extract lat and lon from the location string - local lat, lon = location_str:match("%(([^,]+),([^%)]+)%)") - if lat and lon then - lat = tonumber(lat) - lon = tonumber(lon) - else - print("Invalid location format: " .. location_str) - return 0 -- Return 0 if the format is invalid - end - - -- Fetch pollution data - local url = string.format("http://localhost:8008/routes/api/pollution?lat=%f&lon=%f", lat, lon) +function fetch_pollution_data() + local url = "http://128.199.51.173:8000/routes/api/pollution/NO2" local response, status = http.request(url) - if status == 200 then - local data = json.decode(response) - return data.pollution -- Return the pollution weight from the backend + if status == 200 and response then + print("Raw response:", response) + local success, data = pcall(json.decode, response) -- Manejar errores de JSON + if success and data and data.stations then + print("Pollution data fetched successfully.") + print("Number of stations:", #data.stations) + return data + else + print("Failed to decode JSON or missing 'stations' key.") + end else - print("Failed to fetch pollution data. HTTP status: " .. tostring(status)) - return 0 -- Return 0 if the request fails + print("HTTP request failed. Status:", status) end + + -- Fallback a datos vacíos si hay un error + return { stations = {} } end + function setup() local walking_speed = 5 + stations_data = fetch_pollution_data() + + -- Check if data was successfully retrieved + if not stations_data or not stations_data.stations then + print("Warning: Pollution data could not be loaded. Defaulting to no pollution.") + stations_data = { stations = {} } -- Fallback to empty station data + else + print("Pollution data loaded successfully.") + end return { properties = { weight_name = 'duration', @@ -172,8 +174,47 @@ function setup() } end +function calculate_pollution(lat, lon) + -- Calcular contaminación + local pollution_value = 0 + local total_weight = 0 + local weight = 0 + local p = 1.8 + local max_distance = 3 + if stations_data and stations_data.stations then + for _, station in ipairs(stations_data.stations) do + local station_lat = tonumber(station.lat) + local station_lon = tonumber(station.lon) + local latest_reading = tonumber(station.pollution) + + if station_lat and station_lon and latest_reading then + -- Fórmula de distancia usando Haversine + local R = 6371 -- Radio de la Tierra en km + local dlat = math.rad(station_lat - lat) + local dlon = math.rad(station_lon - lon) + local a = math.sin(dlat / 2)^2 + + math.cos(math.rad(lat)) * math.cos(math.rad(station_lat)) * math.sin(dlon / 2)^2 + local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + local distance = R * c + + -- Ponderación ajustada + weight = 1 / ((distance + 1)) + weight = tonumber(string.format("%.6f", weight)) + pollution_value = pollution_value + (latest_reading * weight) + --total_weight = total_weight + weight + + end + end + --print(pollution_value) + return pollution_value + else + print("No station data available.") + return 0 + end +end + function process_node(profile, node, result) - -- parse access and barrier tags + -- Parse access and barrier tags local access = find_access_tag(node, profile.access_tags_hierarchy) if access then if profile.access_tag_blacklist[access] then @@ -182,7 +223,7 @@ function process_node(profile, node, result) else local barrier = node:get_value_by_key("barrier") if barrier then - -- make an exception for rising bollard barriers + -- Make an exception for rising bollard barriers local bollard = node:get_value_by_key("bollard") local rising_bollard = bollard and "rising" == bollard @@ -191,20 +232,9 @@ function process_node(profile, node, result) end end end - local location = node:location() - local pollution = fetch_pollution_data(location) - print(pollution) - --result.weight = result.weight + pollution - - - -- check if node is a traffic light - local tag = node:get_value_by_key("highway") - if "traffic_signals" == tag then - -- Direction should only apply to vehicles - result.traffic_lights = true - end end + -- main entry point for processsing a way function process_way(profile, way, result) -- the intial filtering of ways based on presence of tags @@ -302,9 +332,29 @@ function process_turn (profile, turn) end end +function process_segment(profile, segment) + -- Extract coordinates of the start and end points + local source_lat, source_lon = segment.source.lat, segment.source.lon + local target_lat, target_lon = segment.target.lat, segment.target.lon + + -- Calculate pollution impact at source and target + local pollution_source = calculate_pollution(source_lat, source_lon) + local pollution_target = calculate_pollution(target_lat, target_lon) + + + -- Average pollution for the segment + local avg_pollution = (pollution_source + pollution_target) / 2 + --print(avg_pollution) + + -- Adjust weight and duration based on pollution level + segment.weight = segment.weight + (avg_pollution^1.4) +end + + return { setup = setup, process_way = process_way, process_node = process_node, - process_turn = process_turn -} \ No newline at end of file + process_turn = process_turn, + process_segment = process_segment +}