Mapdraw
[edit]- Initial BETA Module to draw circle
- See Module Talk page
Function | Arguments | Argument Description |
---|---|---|
p.circle | (maplink or mapframe output can be very large) - built from a circle center point | |
lat | Required latitude (see id below) - ie. lat=27.0 | |
long | Required longitude (see id below) - ie. long=28.0 | |
id | Wikidata ID to look up coordinates instead of using lat and long parameters | |
type | "line" or "poly" default is "line" | |
group | group name to be used as "show" argument in <mapframe> - default is "circle" | |
title | title to be used in <maplink> -- default is "A circle" | |
desc | description default is "" | |
radius | radius of a circle. - default is .5, MAX set at 10 -- and can not be less than or equal to 0 -- .00010 is about 40 meters, 3 is about 50 km | |
fill | default set to #ccef64 if missing | |
stroke | default set to #0000ff | |
mapframe | To create a mapframe insted of a maplink - use mapframe=y or mapframe=yes | |
marker | y or yes - create a marker - at input lat long | |
{{safesubst:#invoke:Mapdraw|circle|lat=22.35|long=70.07|type=poly|radius=10|fill=#000000|stroke=#0000cc}} | ||
-- keeping original shape for a circle -- Matroc
-- other shapes etc. moved to a Sandbox
local p = {}
local function newlat(a)
-- newlat = math.log(math.tan((90 + a) * math.pi / 360)) / (math.pi / 180) -- worked this code elsewhere in function can remove
newlatitude = 180/math.pi * (2 * math.atan(math.exp( a * math.pi/180)) - math.pi/2 )
if newlatitude > 89.5 then point = 89.5 end -- END if -- straight line at top of map
if newlatitude < -89.5 then point = -89.5 end -- END if -- straight line at bottom of map
return newlatitude
end
local function checkhex(fill,stroke)
if string.len(fill) ~= 7 then error("Incorrect length for argument fill!") end
if string.gsub(fill,"#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]","") ~= "" then
error("Incorrect hexidecimal format for argument fill!") end
if string.len(stroke) ~= 7 then error("Incorrect length for argument stroke!") end
if string.gsub(stroke,"#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]","") ~= "" then
error("Incorrect hexidecimal format for argument stroke!") end
end
local function checkid(id)
id = string.gsub(id,"q","Q")
id = string.gsub(id,"%s+","")
if string.gsub(id,"^[Q]%d+$","") ~= "" then error("Bad format for parameter id!") end
return id
end
-- GET LATITUDE
local function latitude(wikidata)
local latitude = ""
local entity = mw.wikibase.getEntityObject(wikidata)
if entity == nil then error("Wikidata ID " .. wikidata .. " not found!") end
local claims = entity.claims
if claims == nil then error("Wikidata ID found No Data!") end
if claims.P625 ~= nil then
latitude = entity.claims.P625[1].mainsnak.datavalue.value.latitude
return latitude
end
if latitude == "" then error("Latitude not found in Wikidata!") end
return latitude
end
-- GET LONGITUDE -- P625
local function longitude(wikidata)
local longitude = ""
local entity = mw.wikibase.getEntityObject(wikidata)
if entity == nil then error("Wikidata ID " .. wikidata .. " not found!") end
local claims = entity.claims
if claims == nil then error("Wikidata ID found No Data!") end
if claims.P625 ~= nil then
longitude = entity.claims.P625[1].mainsnak.datavalue.value.longitude
return longitude
end
if longitude == "" then error("Longitude not found in Wikidata!") end
return longitude
end
local function parts(lat,long,group,title,description,fill,stroke)
local part1a = '<maplink class="no-icon" text="" latitude="' .. lat .. '" longitude="' .. long .. '" '
local part1a = part1a .. 'zoom="5" group="' .. group .. '">\n{"type": "Feature","geometry":\t{"coordinates":\n'
local part2a = '\n\t\t"type":"LineString"},\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
local part2a = part2a .. '\t\t"description": "' .. description .. '",\n'
local part2a = part2a .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}}\n</maplink>\n'
local part1b = '<maplink class="no-icon" text="" latitude="' .. lat .. '" longitude="' .. long .. '" '
local part1b = part1b .. 'zoom="5" group="' .. group .. '">\n{"type": "Feature","geometry":\t{"coordinates":\n'
local part2b = '\n\t\t"type":"Polygon"},\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
local part2b = part2b .. '\t\t"description": "' .. description .. '",\n\t\t"fill": "' .. fill .. '",\n'
local part2b = part2b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}}\n</maplink>\n'
local part1c = '<mapframe text="" latitude="' .. lat .. '" longitude="' .. long .. '" '
local part1c = part1c .. 'zoom="5" group="' .. group .. '" width="600" height="400" >\n{"type": "FeatureCollection",\n\t"features": [\n\t\t{\n\t\t"type": "Feature",\n\t\t"geometry": {"coordinates":\n'
local part2ca = '\n\t\t"type":"LineString"},\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
local part2ca = part2ca .. '\t\t"description": "' .. description .. '",\n\t\t"fill": "' .. fill .. '",\n'
local part2ca = part2ca .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}\n}]}\n</mapframe>\n'
local part2cb = '\n\t\t"type":"Polygon"},\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
local part2cb = part2cb .. '\t\t"description": "' .. description .. '",\n\t\t"fill": "' .. fill .. '",\n'
local part2cb = part2cb .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}\n}]}\n</mapframe>\n'
return part1a,part2a,part1b,part2b,part1c,part2ca,part2cb
end
-- CIRCLE
function p.circle(frame)
local shape = "circle"
local id = frame.args['id'] or ""
local lat,long = "",""
local x,y = 0,0
if id == nil or id == "" then
if frame.args['lat'] == nil then error("Missing argument lat!") end
if frame.args['long'] == nil then error("Missing argument long!") end
lat = frame.args['lat']
long = frame.args['long']
if tonumber(frame.args['lat']) > 90 or tonumber(frame.args['lat']) < -90 then
error("Latitude must be between 90 and -90!") end
if tonumber(frame.args['long']) > 180 or tonumber(frame.args['long']) < -180 then
error("Longitude must be between 180 and -180!") end
else
id = checkid(id)
lat = latitude(id)
long = longitude(id)
end
x = string.format("%.6f",lat)
y = string.format("%.6f",long)
local marker = frame.args['marker'] or "no"
if marker == nil or marker == "" then marker = "no" end
local mapframe = frame.args['mapframe'] or "no"
if mapframe == nill or mapframe == "" then mapframe = "no" end -- FUTURE USE
if tonumber(lat) > 85.35 or tonumber(lat) < -85.35 then
error("Latitude must be between 85.35 and -85.35!") end -- END if
-- I set this as a default - function will not handle the polar circles yet will still handle areas within the majority of a map
if tonumber(long) > 180 or tonumber(long) < -180 then
error("Longitude must be between 180 and -180!") end -- END if
-- this will draw a full circle at 0 lat and 180 long
local group = frame.args['group'] or 'circle'
local title = frame.args['title'] or 'A circle'
local description = frame.args['desc'] or ''
local r = frame.args['radius'] or ".5" -- default
-- radius of 10 is approx. 500 km - futz with sizes - below 3 would probably be adequate
-- .1 is about 20km - .0001 is about 30 m
r = tonumber(r)
if r > 10 then error("10 for radius is MAX") end -- END if - my default
if r <= 0 then error("radius has to be greater than 0") end -- END if
local fill = frame.args['fill'] or "#ccef64"
local stroke = frame.args['stroke'] or "#0000ff"
checkhex(fill,stroke)
local data = {}
local coordinates = ""
local ptx,pty,angle = 0,0,0
local type = frame.args['type'] or "line" -- default line for LineString
if type ~= "line" then
type = "poly"
end -- END if
local part1a,part2a,part1b,part2b,part1c,part2ca,part2cb = parts(lat,long,group,title,description,fill,stroke)
if tonumber(x) >= 10.5 then
x = math.log(math.tan((90 + x) * math.pi/360)) / (math.pi/180)
elseif tonumber(x) <= -10.5 then
x = math.log(math.tan((90 + x) * math.pi/360)) / (math.pi/180)
end -- END if ELSEIF
for i = 1, 360 do
angle = i * math.pi / 180
ptx = x + r * math.cos( angle )
pty = y + r * math.sin( angle )
-- ptx, pty = x + r * math.cos( angle ), y + r * math.sin( angle ) -- original code split for readability above
if tonumber(x) >= 10.5 then
ptx = newlat(ptx) -- makes correction to make circle show up on map - upper latitudes
end -- END if
if tonumber(x) <= -10.5 then
ptx = newlat(ptx) -- makes correction to make circle show up on map - lower latitudes
end -- END if
data[i] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
end -- END for
for i = 5,359, 5 do
data[i] = data[i] .. "@@@@@"
end -- END for
-- cycle through array and build single string of all coordinates to be output
for i = 1,360, 1 do
coordinates = coordinates .. data[i]
end -- END for
coordinates = coordinates.gsub(coordinates,'%]%[','],[')
coordinates = coordinates.gsub(coordinates,'%]@@@@@%[','],\n[')
coordinates = "[" .. coordinates .. ',' .. data[1] .. "]," -- close the circle extra precautionary measure
if mapframe == "y" or mapframe == "yes" then
if type == "poly" then
coordinates = string.gsub(coordinates,'%]%,$',']],')
coordinates = part1c .. string.gsub(coordinates,'^%[','[[') .. part2cb
else
coordinates = part1c .. coordinates .. part2ca
end -- END if
else
if type == "poly" then
coordinates = string.gsub(coordinates,'%]%,$',']],')
coordinates = part1b .. string.gsub(coordinates,'^%[','[[') .. part2b
else
coordinates = part1a .. coordinates .. part2a
end -- END if
end
if marker == "yes" or marker == "y" then
coordinates = coordinates .. '\n* {{marker|type=vicinity|name=Center Circle|lat=' .. lat .. "|long=" .. long .. '}}\n'
end
return coordinates
end
-- END MODULE
return p