Module:Sandbox/Matroc/Mapdraw2

From Wikivoyage
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/Matroc/Mapdraw2/doc

-- This is an experimental module by Matroc - 1/11/2018
-- Used in conjunction with template that is making use of {{#tag:mapframe}} and {{#tag:maplink}}
-- Will change name as more shapes further developed....
-- Conversion of some of the Mapshapes for general use and further development probably desired by more skilled
-- Scribunto - Lua programmers
-- Shapes built using different coding approaches thus need to combine and simplify as much as possible
-- Probably change coordinates to data or something like that.
-- NEED TO WORK OUT USING lat and long if lat and long not found in wikidata in Module and template as well
-- Latitude and Longitude are recalculated to position correctly for mercator type maps - thus can draw shapes
-- without curvature distortion.

-- 26 Aug -- many wikidata entries do not have lat long - if lat and long are provided as parameters then
-- going to get around getting the coordinates by putting those parameters 1st then wikidata lat long
-- JSON errors will still happen - at least this is a work around getting so that they can be corrected

local p = {}
-- CONVERT NEWLATITTUDE

local function newlat(a)
    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
    if newlatitude < -89.5 then point = -89.5 end -- END if
    return newlatitude
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

-- TEST ADD LEFT _ RIGHT _ CENTER  for Description
local function aligndesc(description,descattr)
if description ~= nil and description ~= "" then
	if descattr == "l" then
	      description = "<div style='font-size:14px; text-align:left;'>" .. description .. "</div>"
	elseif descattr == "r" then
	      description = "<div style='font-size:14px; text-align:right;'>" .. description .. "</div>"
	elseif descattr == "c" then
	      description = "<div style='font-size:14px; text-align:center;'>" .. description .. "</div>"
	else
		  description = description
    end
end	
   description = string.gsub(description,'"','\\"')   -- change " to \" for Kartographer
   return description
end

-- NEW FUNCTION TO BE TESTED

local function latlongcheck(lat,long)
if lat == nil then error("Missing argument lat!") end
if long == nil then error("Missing argument long!") end
if tonumber(lat) > 90 or tonumber(lat) < -90 then error("Latitude must be between 90 and -90!") end
if tonumber(long) > 180 or tonumber(long) < -180 then error("Longitude must be between 180 and -180!") end	
	return ""	
end

-- TESTING ADDING fillopacity,strokeopacity and strokewidth FUTURE
local function partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)


-- Maplink content LineString
       
        local part1a = '\n{"type": "Feature","geometry": {"type":"LineString", "coordinates":\n'
       local part1b = '\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
       local part1b = part1b .. '\t\t"description": "' .. description .. '",\n'
       local part1b = part1b .. '\t\t"stroke-opacity":' .. strokeopacity .. ',\n'
       local part1b = part1b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":' .. strokewidth .. '\n}}\n'

 -- Maplink content Polygon	   
        local part2a = '\n{"type": "Feature","geometry": { "type":"Polygon", \t"coordinates":\n'
        local part2b = '\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"fill-opacity":' .. fillopacity .. ',\n'
        local part2b = part2b .. '\t\t"stroke-opacity":' .. strokeopacity .. ',\n'
        local part2b = part2b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":' .. strokewidth .. '\n}}\n'

 -- Mapframe content LineString
        local part3a = '\n{"type": "FeatureCollection",\n\t"features": [\n\t\t{\n\t\t"type": "Feature",\n\t\t"geometry": {\n\t\t"type":"LineString", "coordinates":\n'
        local part3b = '\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
        local part3b = part3b .. '\t\t"description": "' .. description .. '",\n'
        local part3b = part3b .. '\t\t"stroke-opacity":' .. strokeopacity .. ',\n'
        local part3b = part3b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":' .. strokewidth .. '\n}\n}]}\n' 

 -- Mapframe content Polygon		
        local part4a = '\n{"type": "FeatureCollection",\n\t"features": [\n\t\t{\n\t\t"type": "Feature",\n\t\t"geometry": {\n\t\t"type":"Polygon", "coordinates":\n'
        local part4b = '\n\t"properties": {\n\t\t"title": "' .. title .. '",\n'
        local part4b = part4b .. '\t\t"description": "' .. description .. '",\n\t\t"fill": "' .. fill .. '",\n'
        local part4b = part4b .. '\t\t"fill-opacity":' .. fillopacity .. ',\n'
        local part4b = part4b .. '\t\t"stroke-opacity":' .. strokeopacity .. ',\n'
        local part4b = part4b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":' .. strokewidth .. '\n}\n}]}\n'			

        return part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b
end

local function parts(lat,long,group,title,description,fill,stroke)
	
--        local xprogcomment = '\n\t\t"__xprogcomment__" : "Mapdraw",\n\t\t"__xprogcomment__date__" : "' .. os.date("%m/%d/%Y -- %I:%M:%S") .. '",\n'
-- ERROR SPOT PART1A MAYBE AS THIS WAS MISSING PIECE PROBABLY DELETED SOMEWHERE DURING DEVELOPMENT
-- WILL HAVE TO TEST VARIOUS PIECES TO INSURE THIS HAS BEEN CORRECTED
-- Put together content for template

-- Maplink content LineString
       
        local part1a = '\n{"type": "Feature","geometry": {"type":"LineString", "coordinates":\n'
       local part1b = '\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
       local part1b = part1b .. '\t\t"description": "' .. description .. '",\n'
       local part1b = part1b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}}\n'

 -- Maplink content Polygon	   
        local part2a = '\n{"type": "Feature","geometry": { "type":"Polygon", \t"coordinates":\n'
        local part2b = '\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'

 -- Mapframe content LineString
        local part3a = '\n{"type": "FeatureCollection",\n\t"features": [\n\t\t{\n\t\t"type": "Feature",\n\t\t"geometry": {\n\t\t"type":"LineString", "coordinates":\n'
        local part3b = '\n\t"properties":{\n\t\t"title": "' .. title .. '",\n'
        local part3b = part3b .. '\t\t"description": "' .. description .. '",\n'
        local part3b = part3b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}\n}]}\n' 

 -- Mapframe content Polygon		
        local part4a = '\n{"type": "FeatureCollection",\n\t"features": [\n\t\t{\n\t\t"type": "Feature",\n\t\t"geometry": {\n\t\t"type":"Polygon", "coordinates":\n'
        local part4b = '\n\t"properties": {\n\t\t"title": "' .. title .. '",\n'
        local part4b = part4b .. '\t\t"description": "' .. description .. '",\n\t\t"fill": "' .. fill .. '",\n'
        local part4b = part4b .. '\t\t"stroke":"' .. stroke .. '",\n\t\t"stroke-width":1\n}\n}]}\n'			

        return part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b
end

-- For other functions if to be added from original Module Mapdraw
-- table of positions for specific shapes
local function positions(shape)
      local positions = {}

      positions['star6'] = {30,60,90,120,150,180,210,240,270,300,330,360}
      positions['star2'] = {36,72,108,144,180,216,252,288,324,360}
      positions['cross'] = {15,45,75,105,135,165,195,225,255,285,315,345}
      positions['xshape'] = {30,60,90,120,150,180,210,240,270,300,330,360}
      positions['bar'] = {90,270}
      positions['keystone'] = {35,26,55,160,200,305,334,325}
      positions['cog'] = {45,90,135,180,225,270,315,360}
      positions['quad'] = {360,90,180,270} 
      positions['arrow'] = {360,45,90,135,180,225,270,315}
      positions['pentagram'] = {360,144,288,72,216}
      
      return positions[shape]

end

-- FUTURE CHANGE TO CHECK AND IF NEED BE CREATE DEFAULT fill AND stroke
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

-- Several variants of code being concatted depending upon the shape - only used for p.arrow right now
-- [[-3600,90], [3600, 90], [3600,-90], [-3600,-90], [-3600,90]], future to add shaded area around shape
-- Need to add 'shading' if we want this shaded area
local function putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)
        if mapframe == "y" or mapframe == "yes" then
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part4a .. coordinates .. part4b
                else
                        coordinates  = '[' .. coordinates .. ']},'
                        coordinates = part3a .. coordinates .. part3b
                end
        else
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part2a .. coordinates .. part2b
                else
                        coordinates  = '[' .. coordinates .. ']},'
                        coordinates = part1a .. coordinates .. part1b
                end
        end


      return coordinates
end

function p.id(frame)
--    if frame.args[1]~=nil and frame.args[1]~='' then
--        return frame.args[1]
--    end
	local arg1 = frame.args[1]
    local entity = mw.wikibase.getEntityObject(arg1)	
--	local entity = mw.wikibase.getEntityObject()
	if entity == nil then return end    		
    return entity.id
end

-- GET LATITUDE -- P625 as standalone function

function p.latitude(frame)
--    if frame.args[1]~=nil and frame.args[1]~='' then
--        return frame.args[1]
--    end
	local latitude = ""
	local arg1 = frame.args[1]
    local entity = mw.wikibase.getEntityObject(arg1)	
--	local entity = mw.wikibase.getEntityObject()
	if entity == nil then return latitude end    		
	local claims = entity.claims
	if claims == nil then
		return latitude
	end	
	if claims.P625 ~= nil then
		latitude = entity.claims.P625[1].mainsnak.datavalue.value.latitude
		return latitude
	end
	return latitude
end

--  GET LONGITUDE -- P625 as standalone function

function p.longitude(frame)
--    if frame.args[1]~=nil and frame.args[1]~='' then
--        return frame.args[1]
--    end
	local longitude = ""
	local arg1 = frame.args[1]
    local entity = mw.wikibase.getEntityObject(arg1)	
--	local entity = mw.wikibase.getEntityObject()
	if entity == nil then return longitude end    		
	local claims = entity.claims
	if claims == nil then
		return longitude
	end	
	if claims.P625 ~= nil then
		longitude = entity.claims.P625[1].mainsnak.datavalue.value.longitude
		return longitude
	end
	return longitude
end

-- ARROW -- only creates a Polygon with a stroke thickness of 3 and fill-opacity of 1.0

function p.arrow(frame)
	   local shape = "arrow"
	   local id = frame.args['id']	or ""
	   
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end
  

        local latitude = lat -- for marker points to
        local longitude = long -- for marker points to
        local direction = frame.args['direction'] or "1"
           if direction == nil or direction == "" then direction = "1" end
--           if string.gsub(direction,"[1-8]","") ~= "" then error("Numbers 1-8 only in direction!") end           
           if string.gsub(direction,"^[1-8]$","") ~= "" then direction="1" end
           if tonumber(direction) < 1 or tonumber(direction) > 8 then direction = "1" end
           direction = tonumber(direction)
        local group = frame.args['group'] or 'arrow'
        local title = frame.args['title'] or 'An arrow'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end   -- exception for bar only
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .50
        local r3 = r * .475
        local fill = frame.args['fill'] or "#000000"             -- fill arg - default is black
            if fill == nil or fill == "" then fill = "#000000" end
        local stroke = frame.args['stroke'] or "#000000"         -- stroke arg - default is black
            if stroke == nil or stroke == "" then stroke = fill end
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "poly" -- default is polygon
        if type ~= "poly" then
                type = "line"
        end

      local angle,ptx,pty = 0,0,0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      angle = (compass[direction]) * math.pi / 180
      ptx = lat - (r*1.05) * math.cos( angle )
      pty = long - (r*1.05) * math.sin( angle )
      lat,long = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

          local matrix = {}
-- 1
          angle = (compass[direction] - 18) * math.pi / 180
          ptx = lat + r2 * math.cos( angle )
          pty = long + r2 * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[1] = "[" .. pty .. "," .. ptx .. "]@@@@@"
-- 2
          angle = compass[direction] * math.pi / 180
          ptx = lat + r * math.cos( angle )
          pty = long + r * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[2] = "[" .. pty .. "," .. ptx .. "]@@@@@"
--3
          angle = (compass[direction] + 18) * math.pi / 180
          ptx = lat + r2 * math.cos( angle )
          pty = long + r2 * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[3] = "[" .. pty .. "," .. ptx .. "]@@@@@"

-- 4
          angle = (compass[direction] - 2) * math.pi / 180
          ptx = lat + r3 * math.cos( angle )
          pty = long + r3 * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[4] = "[" .. pty .. "," .. ptx .. "]@@@@@"

-- 5
          angle = (compass[direction] + 181) * math.pi / 180
          ptx = lat + r * math.cos( angle )
          pty = long + r * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[5] = "[" .. pty .. "," .. ptx .. "]@@@@@"
-- 6
          angle = (compass[direction] + 179) * math.pi / 180
          ptx = lat + r * math.cos( angle )
          pty = long + r * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[6] = "[" .. pty .. "," .. ptx .. "]@@@@@"
-- 7
          angle = (compass[direction] + 2) * math.pi / 180
          ptx = lat + r3 * math.cos( angle )
          pty = long + r3 * math.sin( angle )
          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
          matrix[7] = "[" .. pty .. "," .. ptx .. "]@@@@@"

        for i=1,table.getn(matrix),1 do
                coordinates = coordinates .. matrix[i]
        end
        coordinates = coordinates .. matrix[1]
        coordinates = string.gsub(coordinates,'@@@@@$','')
        coordinates = string.gsub(coordinates,'@@@@@',',')

        lat = string.format("%.6f",newlat(lat))

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

        -- Make thickness of 3

        coordinates = string.gsub(coordinates,'stroke%-width%":1','fill-opacity": 1.0,\n\t\t"stroke-width":4')

      return coordinates

end


-- BOX - Square

function p.box(frame)
	   local shape = frame.args['box'] or "box"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   
-- Future : local shading = frame.args['shading'] or 'n'	   
        local group = frame.args['group'] or 'box'
        local title = frame.args['title'] or 'A box'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local name = frame.args['name'] or "A Center Box"
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local angle1,angle2,angle3,angle4 = 0,0,0,0
        local ptx,ptx2,ptx3,ptx4 = 0,0,0,0
        local pty,pty2,pty3,pty4 = 0,0,0,0
        local a = 45
        local b = 135
        local c = 225
        local d = 315
        
        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4 = lat + r * math.cos( angle4 )
        pty4 = long + r * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"

-- ADD SHADING to call
        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end

-- EQUITRI

function p.equitri(frame)
	   local shape = "equitri"
	   local id = frame.args['id']	or ""
	   
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end

        local group = frame.args['group'] or 'equitri'
        local title = frame.args['title'] or 'An equilateral triangle'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
                r = r * 2
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""

        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

        local direction = frame.args['direction'] or "1"
              if direction == nil or direction == "" then direction="1" end
              if string.gsub(direction,"^[1-4]$","") ~= "" then direction="1" end              
--              direction = string.gsub(direction,"%..*","")
              direction = tonumber(direction)
              if direction <= 0 or direction >=5 then error("direction should be a number from 1 to 4!") end

        local factors = {}
        factors[1] = "360,120,240"
        factors[2] = "90,210,330"
        factors[3] = "180,300,60"
        factors[4] = "270,150,30"

        local points = factors[direction]
        a = string.gsub(points,'%,.*$','')
        b = string.gsub(points,'(%d+%,)(%d+)(%,%d+)',"%2")
        c = string.gsub(points,'^.*,','')
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )

        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)

        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[" .. pty .. "," .. ptx .. "]"

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end

-- STAR -- to be reworked for vertical placement of top of star 

function p.star(frame)
       local shape = "star"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end
  

        local latitude = string.format("%.6f",lat)
        local longitude = string.format("%.6f",long)		
        local group = frame.args['group'] or 'star'
        local title = frame.args['title'] or 'A star'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING  
description = aligndesc(description,descattr)    
        local radius = frame.args['radius'] or ".5" 
                radius = tonumber(radius)
                if radius > 10 then error("10 for radius is MAX") end  
                if radius <= 0 then error("radius has to be greater than 0") end
        local radius2 = radius * 3;
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)

        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end  -- FUTURE USE          
        latitude = math.log(math.tan((90 + latitude) * math.pi/360)) / (math.pi/180)
        local ra,angle = 0,0
        local points = {}
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
		
      for i = 1,10, 1 do
         mod = math.mod(i,2)
         if mod == 1 then ra = radius else ra = radius2 end
         angle =  ((2 * math.pi / 10)) * i
         points[i] =  '[' ..  string.format("%.6f",longitude + (ra * math.cos(angle))) .. ","
         points[i] = points[i] .. string.format("%.6f",newlat(latitude + (ra * math.sin(angle)))) .. "],"
      end

      for i = 1,10, 1 do
         coordinates = coordinates .. points[i] .. "\n"
      end

      coordinates = coordinates .. points[1]

	  if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[[') .. part4b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part3a .. string.gsub(coordinates,'^%[','[[') .. part3b
           end
	   else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[[') .. part2b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part1a .. string.gsub(coordinates,'^%[','[[') .. part1b
           end	   
	   
	   end

      return coordinates

end
-- STAR2 -- reworked star pointing North 

function p.star2(frame)
	   local shape = "star2"
	   local id = frame.args['id']	or ""
	   
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

	   
	   
        local x = tonumber(lat)
        local y = tonumber(long)
        local latitude = string.format("%.6f",lat)
        local longitude = string.format("%.6f",long)		
        local group = frame.args['group'] or 'star2'
        local title = frame.args['title'] or 'A star(2)'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local radius = frame.args['radius'] or ".5" 
                radius = tonumber(radius)
                if radius > 10 then error("10 for radius is MAX") end 
                if radius <= 0 then error("radius has to be greater than 0") end
        local radius2 = radius * 3;
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end  -- FUTURE USE          
        local ra,angle,ptx,pty = 0,0,0,0
        local compass = {}
        local points = {}
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        x = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
	compass = positions(shape)

      for i = 1,table.getn(compass), 1 do
        mod = math.mod(i,2)
        if mod == 1 then r = radius else r = radius2 end
        angle = compass[i] * math.pi / 180
        ptx = x + r * math.cos( angle )
        pty = y + r * math.sin( angle )
        ptx = newlat(ptx)
-- TEST BELOW FIX        points[i] = '[' ..  string.format("%.6f",pty) .. pty .. "," .. string.format("%.6f",ptx) .. "],"
        points[i] = '[' ..  string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. "],"

      end

      for i = 1,table.getn(points), 1 do
         coordinates = coordinates .. points[i] .. "\n"
      end

      coordinates = coordinates .. points[1]

	  if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[[') .. part4b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part3a .. string.gsub(coordinates,'^%[','[[') .. part3b
           end
	   else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[[') .. part2b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part1a .. string.gsub(coordinates,'^%[','[[') .. part1b
           end	   
	   
	   end

      return coordinates

end

-- MULTISIDE  - create multi-sided regular polygon - if number of sides > 20 can use to replace circle with its 360 points

function p.multiside(frame)
           local shape = "multiside"
           local sides = frame.args['sides'] or "3"
              if sides == nil or sides == "" then sides = "3" end
                 sides = tonumber(sides)
              if sides < 3 or sides > 360 then sides = 3 end  -- as number of sides grow - can use to make a rough circle above 20 
           local increment = 360/sides
           local inbetween = increment/2
	   local id = frame.args['id'] or "" 
              id = string.gsub(id,"%,+","@")
              id = string.gsub(id,"%s+",'')
              id = string.gsub(id,"%@+",'@')
           local lat = frame.args['lat'] or ""
           local long = frame.args['long'] or ""
           local matrix = {}
           local coordinates = ""
           local count = 1
           local type = frame.args['type'] or "line"
           if type ~= "poly" then type = "line" end 
	   if id == nil or id == "" then
               if lat == "" or lat == nil then error("Missing argument lat!") end
               if long == "" or long == nil then error("Missing argument long!") end
               if tonumber( lat ) > 90 or tonumber( lat ) < -90 then
           	          error("Latitudes must be between 90 and -90!") end
               if tonumber(long) > 180 or tonumber(long) < -180 then
           	          error("Longitudes must be between 180 and -180!") end
   	    else
                id = checkid(id)
                lat = latitude(id)
                long = longitude(id)	
	   end	
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local group = frame.args['group'] or 'multiside'
        local title = frame.args['title'] or 'A Multi-sided shape'
        local description = frame.args['desc'] or ""
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
           if description == nil then description = "" end
        local fill = frame.args['fill'] or "#ffff00"
        local stroke = frame.args['stroke'] or "#000000"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
            if mapframe == nil or mapframe == "" then mapframe = "no" end 
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        local angle,ptx,pty = 0,0,0
        local latitude = lat
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
        local count = 0
        
        for i = increment,360, increment do
             angle = (i + inbetween) * math.pi / 180
             ptx = lat + r * math.cos( angle )
             pty = long + r * math.sin( angle )
             ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
             count = count + 1
             matrix[count] = "[" .. pty  .. "," .. ptx .. "]@@@@@"
        end

        for i = 1,table.getn(matrix), 1 do
          coordinates = coordinates .. matrix[i]
        end

        coordinates = coordinates .. matrix[1]
        coordinates = string.gsub(coordinates,"@@@@@",",")
        coordinates = string.gsub(coordinates,",$",'')

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

       return coordinates

end


-- ELLIPSE

function p.ellipse(frame)
	  local shape = "ellipse"
	  local id = frame.args['id']	or ""
	  local x,y = 0,0
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	  
	  

        x = string.format("%.6f",lat)  
        y = string.format("%.6f",long)          
        local group = frame.args['group'] or 'ellipse'
        local title = frame.args['title'] or 'An ellipse'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("radius has to be greater than 0") end
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end -- FUTURE USE              
        local direction = frame.args['direction'] or "h"
              if direction == nil or direction == "" then direction = "h" end
              if direction ~= "v" then direction = "h" end -- if not v (ie. other garbage then force direction to be h)
        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
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = 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

        for i = 1, 360 do
           angle = i * math.pi / 180
           ptx = x + r * math.cos( angle )
           if direction == "v" then
                pty = y - 0.5 * r * math.sin( angle ) -- for ellipse vertical
             elseif direction == "h" then
                pty = y + 2.0 * r * math.sin(angle) -- for ellipse horizontal
           end

        if tonumber(x) >= 10.5 then
         ptx = newlat(ptx) -- makes correction to make ellipse show up on map
        end

        if tonumber(x) <= -10.5 then
          ptx = newlat(ptx) -- makes correction to make ellipse show up on map
        end

          data[i] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
        end

        for i = 5,359, 5 do
                data[i] = data[i] .. "@@@@@"
        end

        for i = 1,360, 1 do
        coordinates = coordinates .. data[i]
        end

        coordinates = coordinates.gsub(coordinates,'%]%[','],[')
        coordinates = coordinates.gsub(coordinates,'%]@@@@@%[','],\n[')
        coordinates = "[" .. coordinates .. ',' .. data[1] .. "],"  

        if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[') .. part4b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part3a .. coordinates .. part3b
           end
		else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[') .. part2b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part1a .. coordinates .. part1b
           end		
		end
		
        return coordinates

end

-- BOX FRAME

function p.boxframe(frame)
	   local shape = "box"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   
	   

        local group = frame.args['group'] or 'boxframe'
        local title = frame.args['title'] or 'A boxframe'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5"  
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .85
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
        
        -- line to become MultiLineString
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local angle1,angle2,angle3,angle4 = 0,0,0,0
        local ptx,ptx2,ptx3,ptx4 = 0,0,0,0
        local pty,pty2,pty3,pty4 = 0,0,0,0
        local ptxa,ptxb,ptxc,ptxd = 0,0,0,0
        local ptya,ptyb,ptyc,ptyd = 0,0,0,0        
        local a = 45
        local b = 135
        local c = 225
        local d = 315
        
        angle1 = a * math.pi / 180
        ptx,ptxa = lat + r * math.cos( angle1 ),lat + r2 * math.cos( angle1 )
        pty,ptya = long + r * math.sin( angle1 ),long + r2 * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2,ptxb = lat + r * math.cos( angle2 ),lat + r2 * math.cos( angle2 )
        pty2,ptyb = long + r * math.sin( angle2 ),long + r2 * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3,ptxc = lat + r * math.cos( angle3 ),lat + r2 * math.cos( angle3 )
        pty3,ptyc = long + r * math.sin( angle3 ),long + r2 * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4,ptxd = lat + r * math.cos( angle4 ),lat + r2 * math.cos( angle4 )
        pty4,ptyd = long + r * math.sin( angle4 ),long + r2 * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        
        ptxa,ptya = string.format("%.6f",newlat(ptxa)),string.format("%.6f",ptya)
        ptxb,ptyb = string.format("%.6f",newlat(ptxb)),string.format("%.6f",ptyb)
        ptxc,ptyc = string.format("%.6f",newlat(ptxc)),string.format("%.6f",ptyc)
        ptxd,ptyd = string.format("%.6f",newlat(ptxd)),string.format("%.6f",ptyd)      
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"
        coordinates = coordinates .. "],[" ..  "[" .. ptya .. "," .. ptxa .. "],[" .. ptyb .. "," .. ptxb .. "],[" .. ptyc .. "," .. ptxc .. "],[".. ptyd .. "," .. ptxd .. "],[" .. ptya .. "," .. ptxa .. "]"
        if mapframe == "y" or mapframe == "yes" then
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part4a .. coordinates .. part4b
                else
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part3a .. coordinates .. part3b
                        coordinates = string.gsub(coordinates,'"type":"LineString"','"type":"MultiLineString"')   
                end
        else
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part2a .. coordinates .. part2b
                else
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part1a .. coordinates .. part1b
                        coordinates = string.gsub(coordinates,'"type":"LineString"','"type":"MultiLineString"')                        
                        
                end
        end

      return coordinates

end

-- CRESCENT

function p.crescent(frame)
	local shape = "crescent"
        local id = frame.args['id']	or ""
--        local lat,long = "",""
        local x,y,x2,y2 = 0,0,0,0
        local newcenterx,newcentery = 0,0
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end        

           x = string.format("%.6f",lat)  
           y = string.format("%.6f",long)          
           local group = frame.args['group'] or 'crescent'
           local title = frame.args['title'] or 'A crescent'
           local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
           local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("radius has to be greater than 0") end
           local fill = frame.args['fill'] or "#ccef64"
           local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
           checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end -- FUTURE USE              
        local data = {}
        local data2 = {}
        local coordinates = ""
        local coordinates2 = ""
        local ptx,pty,angle,ptx2,pty2 = 0,0,0,0,0
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        x = math.log(math.tan((90 + x) * math.pi/360)) / (math.pi/180)
        x2 = x
        y2 = y
        for i = 1, 360 do
           angle = i * math.pi / 180
           ptx = x + r * math.cos( angle )
           pty = y + 1.5 * r * math.sin(angle) -- for ellipse horizontal

           ptx2 = x2 + r * math.cos (angle)
           pty2 = y2 + r * math.sin (angle)

        if i == 90 then
           newcenterx = x + r * math.cos( angle )
           newcentery = y + 1.25 * r * math.sin (angle)
           newcenterx = newlat(newcenterx)
           newcenterx = string.format("%.6f",newcenterx)
           newcentery = string.format("%.6f",newcentery)
        end

           ptx = newlat(ptx) -- makes correction to make ellipse show up on map
           ptx2 = newlat(ptx2)

           data[i] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
           data2[i] = '[' .. string.format("%.6f",pty2) .. "," .. string.format("%.6f",ptx2) .. ']'
       end

        for i = 5,360, 5 do
            data[i] = data[i] .. "@@@@@"
            data2[i] = data2[i] .. "@@@@@"
        end

        for i = 1,180, 1 do
        coordinates = coordinates .. data[i]
        end

        for i = 180,1, -1 do
        coordinates2 = coordinates2 .. data2[i]
        end

        coordinates = coordinates .. coordinates2
        coordinates = coordinates.gsub(coordinates,'%]%[','],[')
        coordinates = coordinates.gsub(coordinates,'@@@@@$','')
        coordinates = coordinates.gsub(coordinates,'%]@@@@@%[','],\n[')
        coordinates = "[" .. coordinates .. ',' .. data[1] .. "],"  

        if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[') .. part4b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part3a .. coordinates .. part3b
           end
		else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[') .. part2b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part1a .. coordinates .. part1b
           end		
		end
		
    return coordinates

end

-- CROSS

function p.cross(frame)
	   local shape = "cross"
	   local id = frame.args['id']	or ""
--	   local lat,long = "",""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end

	   
-- to work with template Mapdraw2 which supplies an id of Q97 to make it work which reactes a lat long
-- but is ignoring an input lat and long which is to take precedence over input of an id in the template

--if latxxx ~= nil and latxxx ~= "" then
--	lat = latxxx
--	end
--if longxxx ~= nil and longxxx ~= "" then
--	long = longxxx
--	end
        local group = frame.args['group'] or 'cross'
        local title = frame.args['title'] or 'A Cross'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5"
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .25
        local fill = frame.args['fill'] or "#ff0000"
        local stroke = frame.args['stroke'] or "#ffffff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

      local angle = 0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      for i = 1,table.getn(compass), 1 do
          angle = compass[i] * math.pi / 180
             if compass[i] == 45 or compass[i] == 135 or compass[i] == 225 or compass[i] == 315 then
                ptx = lat + r2 * math.cos( angle )
                pty = long + r2 * math.sin( angle )
             else
                ptx = lat + r * math.cos( angle )
                pty = long + r * math.sin( angle )
             end

          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

          coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end  
          coordinates = coordinates .. string.gsub(coordinates,'@@@@@.*','')
          coordinates = string.gsub(coordinates,'@@@@@',',')

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates
end

function p.rhombus(frame)
	   local shape = "rhombus"
	   local direction = frame.args['direction'] or "v"
	   if direction == nil or direction == "" then direction = "v" end
	   if direction ~= "h" then direction = "v" end
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

-- latlongcheck(lat,long) -- Future?	

--	   local lat,long = "",""
--  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
        local group = frame.args['group'] or 'rhombus'
        local title = frame.args['title'] or 'A rhombus'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING   
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * 2
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)

        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local angle1,angle2,angle3,angle4 = 0,0,0,0
        local ptx,ptx2,ptx3,ptx4 = 0,0,0,0
        local pty,pty2,pty3,pty4 = 0,0,0,0
        local a,b,c,d = 0,0,0,0
        if direction == "h" then
            a,b,c,d = 360,90,180,270
          else
          	a,b,c,d = 90,180,270,360
        end

        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r2 * math.cos( angle2 )
        pty2 = long + r2 * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4 = lat + r2 * math.cos( angle4 )
        pty4 = long + r2 * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end

-- DIAMOND

function p.diamond(frame)
	   local shape = "diamond"
	   local id = frame.args['id']	or ""
	   
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   


        local group = frame.args['group'] or 'diamond'
        local title = frame.args['title'] or 'A diamond'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING     
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5"
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local a = 360
        local b = 90
        local c = 180
        local d = 270
        
        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4 = lat + r * math.cos( angle4 )
        pty4 = long + r * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end
-- SUN - draw circle with spikes as rays from sun

function p.sun(frame)
           local shape = "sun"
           local sunburst = frame.args['sunburst'] or "10"
                if sunburst == nil or sunburst == "" then sunburst = "10" end
                sunburst = tonumber(sunburst)
                if sunburst < 10 or sunburst > 30 then sunburst = 10 end
           local increment = 360/sunburst
           local inbetween = increment/2
	       local id = frame.args['id'] or "" 
              id = string.gsub(id,"%,+","@")
              id = string.gsub(id,"%s+",'')
              id = string.gsub(id,"%@+",'@')
           local lat = frame.args['lat'] or ""
           local long = frame.args['long'] or ""
           local matrix = {}
           local coordinates = ""
           local count = 1
           local type = frame.args['type'] or "line"
           if type ~= "poly" then type = "line" end 
	          if id == nil or id == "" then
                if lat == "" or lat == nil then error("Missing argument lat!") end
                if long == "" or long == nil then error("Missing argument long!") end
                if tonumber( lat ) > 90 or tonumber( lat ) < -90 then
           	          error("Latitudes must be between 90 and -90!") end
               if tonumber(long) > 180 or tonumber(long) < -180 then
           	         error("Longitudes must be between 180 and -180!") end
   	         else
                id = checkid(id)
                lat = latitude(id)
                long = longitude(id)	
	    end	
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .45
        local group = frame.args['group'] or 'sun'
        local title = frame.args['title'] or 'A sun'
        local description = frame.args['desc'] or ""
    local descattr = frame.args['descattr'] or 'l' -- TESTING        
           if description == nil then description = "" end
description = aligndesc(description,descattr)           
        local fill = frame.args['fill'] or "#ffff00"
        local stroke = frame.args['stroke'] or "#000000"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
            if mapframe == nil or mapframe == "" then mapframe = "no" end 
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)            
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        local angle,ptx,pty = 0,0,0
        local latitude = lat
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
        local count = 0
        
        for i = increment,360, increment do
             angle = i * math.pi / 180
             ptx = lat - r2 * math.cos( angle )
             pty = long - r2 * math.sin( angle )
             ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
             count = count + 1
             matrix[count] = "[" .. pty  .. "," .. ptx .. "]@@@@@"

             angle = (i + inbetween) * math.pi / 180
             ptx = lat - r * math.cos( angle )
             pty = long - r * math.sin( angle )
             ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
             count = count + 1
             matrix[count] = "[" .. pty  .. "," .. ptx .. "]@@@@@"
        end

        for i = 1,table.getn(matrix), 1 do
          coordinates = coordinates .. matrix[i]
        end

        coordinates = coordinates .. matrix[1]
        coordinates = string.gsub(coordinates,"@@@@@",",")
        coordinates = string.gsub(coordinates,",$",'')
        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

       return coordinates

end


-- STADIUM or pill capsule shape -- reduced number of coordinates for circular shape

function p.stadium(frame)
	local shape = "stadium"
        local id = frame.args['id'] or ""
        local x,y,x2,y2 = 0,0,0,0
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end
  
           lat = string.format("%.6f",lat)  
           long = string.format("%.6f",long)          
           local group = frame.args['group'] or 'stadium'
           local title = frame.args['title'] or 'A Stadium'
           local description = frame.args['desc'] or ''
     local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)     
           local r = frame.args['radius'] or ".5"  
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("radius has to be greater than 0") end
           local fill = frame.args['fill'] or "#ccef64"
           local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
           checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end        
        local data = {}
        local data2 = {}
        local coordinates = ""
        local coordinates2 = ""
        local ptx,pty,angle,ptx2,pty2 = 0,0,0,0,0
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        x = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)       
        angle = 90 * math.pi / 180
        x = x + (r*1.5) * math.cos( angle )
        y = long + (r*1.5) * math.sin (angle)
        x = newlat(x)

        x2 = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
        angle = 270 * math.pi / 180
        x = x + (r*1.5) * math.cos( angle )
        y2 = long + (r*1.5) * math.sin (angle )
        x2 = newlat(x2)

        x = math.log(math.tan((90 + x) * math.pi/360)) / (math.pi/180)
        x2 =math.log(math.tan((90 + x2) * math.pi/360)) / (math.pi/180)
        local count = 1

        for i = -2, 180, 2 do
           angle = i * math.pi / 180
           ptx = x + r * math.cos( angle )
           pty = y + r * math.sin(angle)
           ptx = newlat(ptx)
           data[count] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
           count = count + 1
        end


        count = 1
        for i = 178,360, 2 do
           angle = i * math.pi / 180
           ptx = x2 + r * math.cos( angle )
           pty = y2 + r * math.sin(angle)

           ptx = newlat(ptx) 
           data2[count] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
           count = count + 1
        end

        for i = 1,table.getn(data), 1 do
            coordinates = coordinates .. data[i]
        end

        for i = 1,table.getn(data2), 1 do
            coordinates2 = coordinates2 .. data2[i]
        end

        coordinates = coordinates .. coordinates2
        coordinates = coordinates.gsub(coordinates,'%]%[','],[')
        coordinates = coordinates.gsub(coordinates,'@@@@@$','')
        coordinates = coordinates.gsub(coordinates,'%]@@@@@%[','],\n[')
        coordinates = "[" .. coordinates .. ',' .. data[1] .. "],"
 
        if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[') .. part4b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part3a .. coordinates .. part3b
           end
		else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[') .. part2b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part1a .. coordinates .. part1b
           end		
		end
		
    return coordinates

end
-- STAR6 -- 6 pointed star - six sided star

function p.star6(frame)
	   local shape = "star6"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end
  

        local x = tonumber(lat)
        local y = tonumber(long)
        local latitude = string.format("%.6f",lat)
        local longitude = string.format("%.6f",long)		
        local group = frame.args['group'] or 'star6'
        local title = frame.args['title'] or '6 pointed star'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
        local radius = frame.args['radius'] or ".5" 
                radius = tonumber(radius)
                if radius > 10 then error("10 for radius is MAX") end 
                if radius <= 0 then error("radius has to be greater than 0") end
        local radius2 = radius * 3;
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end        
        local ra,angle,ptx,pty = 0,0,0,0
        local compass = {}
        local points = {}
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        x = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
	compass = positions(shape)

      for i = 1,table.getn(compass), 1 do
        mod = math.mod(i,2)
        if mod == 1 then r = radius else r = radius2 end
        angle = compass[i] * math.pi / 180
        ptx = x + r * math.cos( angle )
        pty = y + r * math.sin( angle )
        ptx = newlat(ptx)
-- TEST BELOW FIX        points[i] = '[' ..  string.format("%.6f",pty) .. pty .. "," .. string.format("%.6f",ptx) .. "],"
        points[i] = '[' ..  string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. "],"

      end

      for i = 1,table.getn(points), 1 do
         coordinates = coordinates .. points[i] .. "\n"
      end

      coordinates = coordinates .. points[1]

	  if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[[') .. part4b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part3a .. string.gsub(coordinates,'^%[','[[') .. part3b
           end
	   else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[[') .. part2b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part1a .. string.gsub(coordinates,'^%[','[[') .. part1b
           end	   
	   
	   end

      return coordinates

end

-- BAR -- only creates a LineString with thickness of 4

function p.bar(frame)
	   local shape = "bar"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   
	   

        local direction = frame.args['direction'] or "h"
        if direction == nil or direction == "" then direction = "h" end
           if direction ~= "h" then direction = "v" end
        local group = frame.args['group'] or 'bar'
        local title = frame.args['title'] or 'A bar'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING  
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 40 then error("40 for length is MAX") end  -- 40 for bar shape only
                if r <= 0 then error("r has to be greater than 0") end
--        local fill = frame.args['fill'] or "#000000"             -- fill not used - keep anyhow for time being
        local fill = "#000000"
        local stroke = frame.args['stroke'] or "#000000"           -- change color with stroke
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "line"
        end

      local angle = 0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      for i = 1,table.getn(compass), 1 do
          if direction == "v" then compass[i] = compass[i] + 90 end
          angle = compass[i] * math.pi / 180
          ptx = lat + r * math.cos( angle )
          pty = long + r * math.sin( angle )

          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

          coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end  

          coordinates = string.gsub(coordinates,'@@@@@',',')
        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)
        coordinates = string.gsub(coordinates,'stroke%-width%":1','stroke-width":3')

      return coordinates
end

-- KITE - Shield

function p.kite(frame)
	   local shape = "kite"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local group = frame.args['group'] or 'kite'
        local title = frame.args['title'] or 'A kite'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING   
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)       
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local a = 360
        local b = 60
        local c = 180
        local d = 300
        
        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4 = lat + r * math.cos( angle4 )
        pty4 = long + r * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end


-- ANNULUS - 2 circles forming a donut shape

function p.annulus(frame)
	   local shape = "annulus"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

           x = string.format("%.6f",lat)
           y = string.format("%.6f",long)                   
        
        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 
        if tonumber(long) > 180 or tonumber(long) < -180 then
        	error("Longitude must be between 180 and -180!") end -- END if

        local group = frame.args['group'] or 'annulus'
        local title = frame.args['title'] or 'An annulus'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("radius has to be greater than 0") end 
        local r2 = r * .65
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local data = {}
        local data2 = {}
        local coordinates = ""
        local coordinates2 = ""
        local ptx,pty,angle,ptx2,pty2 = 0,0,0,0,0
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end 
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = 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 

        for i = 1, 360 do
           angle = i * math.pi / 180
           ptx = x + r * math.cos( angle )
           pty = y + r * math.sin( angle )
           ptx2 = x + r2 * math.cos( angle )
           pty2 = y + r2 * math.sin( angle )

        if tonumber(x) >= 10.5 then
         ptx = newlat(ptx) 
         ptx2 = newlat(ptx2)
        end 

        if tonumber(x) <= -10.5 then
          ptx = newlat(ptx) 
          ptx2 = newlat(ptx2)
        end 

          data[i] = '[' .. string.format("%.6f",pty) .. "," .. string.format("%.6f",ptx) .. ']'
          data2[i] = '[' .. string.format("%.6f",pty2) .. "," .. string.format("%.6f",ptx2) .. ']'          
        end 

        for i = 5,359, 5 do
                data[i] = data[i] .. "@@@@@"
                data2[i] = data2[i] .. "@@@@@"
        end 

-- cycle through array and build single string of all coordinates to be output

        for i = 1,360, 1 do
               coordinates = coordinates .. data[i]
               coordinates2 = coordinates2 .. data2[i]
        end 

        coordinates = coordinates.gsub(coordinates,'%]%[','],[')
        coordinates2 = coordinates2.gsub(coordinates2,'%]%[','],[')
        coordinates = coordinates.gsub(coordinates,'%]@@@@@%[','],\n[')
        coordinates2 = coordinates2.gsub(coordinates2,'%]@@@@@%[','],\n[')        
        coordinates = "[" .. coordinates .. ',' .. data[1] .. "],"  
        coordinates2 = "[" .. coordinates2 .. ',' .. data2[1] .. "]],["  
        coordinates = coordinates2 .. coordinates
        coordinates = string.gsub(coordinates,'%]%]%],%[%[%[',']],[[')
        
        if mapframe == "y" or mapframe == "yes" then
			if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[') .. part4b
			else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = string.gsub(coordinates,'^%[','[[')                
                coordinates = part3a .. coordinates .. part3b
                coordinates = string.gsub(coordinates,'LineString','MultiLineString')
			end 
		else
			if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[') .. part2b
			else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = string.gsub(coordinates,'^%[','[[')
                coordinates = part1a .. coordinates .. part1b
                coordinates = string.gsub(coordinates,'LineString','MultiLineString')                
			end 	
		
		end

        return coordinates

end

-- WEDGE

function p.wedge(frame)
	   local shape = "wedge"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local latitude = lat
        local longitude = long

        local group = frame.args['group'] or 'wedge'
        local title = frame.args['title'] or 'A wedge'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * 2
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
      local direction = frame.args['direction'] or "1"
            if direction == nil or direction == "" then direction = "1" end
            direction = string.gsub(direction,'%..*','')
           if string.gsub(direction,"^[1-8]$","") ~= "" then direction="1" end            
            direction = tonumber(direction)
            if direction <= 0 or direction >= 9 then error("Direction should be a number from 1 to 8!") end

      local angle1,angle2,angle3 = 0,0,0
      local ptx,ptx2,ptx3 = 0,0,0
      local pty,pty2,pty3 = 0,0,0

      local factor = {'340,360,20','25,45,65','70,90,110','115,135,155','160,180,200','205,225,245','250,270,290','295,315,335'}
      
      local a = string.gsub(factor[direction],'(%d+)(,)(%d+)(,)(%d+)','%1')      
      local b = string.gsub(factor[direction],'(%d+)(,)(%d+)(,)(%d+)','%3')     
      local c = string.gsub(factor[direction],'(%d+)(,)(%d+)(,)(%d+)','%5')
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--       local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
        angle = b * math.pi / 180
        ptx = lat + (r*.02) * math.cos( angle )
        pty = long + (r*.02) * math.sin( angle )
        lat,long = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        angle1 = a * math.pi / 180
        ptx = lat + r2 * math.cos( angle1 )
        pty = long + r2 * math.sin( angle1 )

        angle2 = b * math.pi /180                -- used to compute center of wedge
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r2 * math.cos( angle3 )
        pty3 = long + r2 * math.sin( angle3 )

        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" ..  pty3 .. "," .. ptx3 .. "],[" .. long .. "," .. lat .. "],[" .. pty .. "," .. ptx .. "]"  

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates
end

-- KEYSTONE

function p.keystone(frame)
	   local shape = "keystone"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local group = frame.args['group'] or 'keystone'
        local title = frame.args['title'] or 'A keystone'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .65
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

      local angle = 0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      for i = 1,table.getn(compass), 1 do
          angle = compass[i] * math.pi / 180
          if compass[i] == 26 or compass[i] == 334 then
               ptx = lat + r2 * math.cos( angle )
               pty = long + r2 * math.sin( angle )
            else
              ptx = lat + r * math.cos( angle )
              pty = long + r * math.sin( angle )
          end

          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

          coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end  

        coordinates = coordinates .. string.gsub(coordinates,'@@@@@.*','')
        coordinates = string.gsub(coordinates,'@@@@@',',')

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates
end


-- COG  -- gear shape

function p.cog(frame)
	   local shape = "cog"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local group = frame.args['group'] or 'cog'
        local title = frame.args['title'] or 'A cog'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .85
        local r3 = r * .30
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1" 
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local coordinates2 = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

      local angle = 0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--       local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      for i = 1,table.getn(compass), 1 do

            angle = (compass[i] - 33.5) * math.pi / 180
            ptx = lat + r2 * math.cos( angle )
            pty = long + r2 * math.sin( angle )
            ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
            coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

            angle = (compass[i] - 11) * math.pi / 180
            ptx = lat + r2 * math.cos( angle )
            pty = long + r2 * math.sin( angle )
            ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
            coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

            angle = (compass[i] -11.25) * math.pi / 180
            ptx = lat + r * math.cos( angle )
            pty = long + r * math.sin( angle )
            ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
            coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

            angle = (compass[i] + 11.25) * math.pi / 180
            ptx = lat + r * math.cos( angle )
            pty = long + r * math.sin( angle )
            ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
            coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end  

        coordinates = coordinates .. string.gsub(coordinates,'@@@@@.*','')
        coordinates = string.gsub(coordinates,'@@@@@',',')

        compass = positions('quad')

      for i = 1,table.getn(compass), 1 do
          angle = compass[i] * math.pi / 180
          ptx = lat + r3 * math.cos( angle )
          pty = long + r3 * math.sin( angle )

          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

          coordinates2 = coordinates2 .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end
        coordinates2 = coordinates2 .. string.gsub(coordinates2,'@@@@@.*','')
        coordinates2 = string.gsub(coordinates2,'@@@@@',',')
        coordinates = coordinates .. "],[" .. coordinates2
 
        if mapframe == "y" or mapframe == "yes" then
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part4a .. coordinates .. part4b
                else
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part3a .. coordinates .. part3b
                        coordinates = string.gsub(coordinates,'LineString','MultiLineString')
                end
        else
                if type == "poly" then
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part2a .. coordinates .. part2b
                else
                        coordinates  = '[[' .. coordinates .. ']]},'
                        coordinates = part1a .. coordinates .. part1b
                        coordinates = string.gsub(coordinates,'LineString','MultiLineString')
                end
        end

      return coordinates
end
-- PENTAGRAM - Line String only -- Poly fills in the tips - lines still there

function p.pentagram(frame)
	   local shape = "pentagram"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   
	   

        local x = tonumber(lat)
        local y = tonumber(long)
        local latitude = string.format("%.6f",lat)
        local longitude = string.format("%.6f",long)		
        local group = frame.args['group'] or 'pentagram'
        local title = frame.args['title'] or 'A pentagram'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                if r == nil or r == "" then r = "0.5" end
                r = tonumber(r)
                if r > 10 then error("10 for radius is MAX") end 
                if r <= 0 then error("radius has to be greater than 0") end
        local fill = frame.args['fill'] or "#000000"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end  -- FUTURE USE          
        local angle,ptx,pty = 0,0,0
        local compass = {}
        local points = {}
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "poly" then
                type = "line"
        end
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        x = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
	compass = positions(shape)

      for i = 1,table.getn(compass), 1 do
        angle = compass[i] * math.pi / 180
        ptx = x + r * math.cos( angle )
        pty = y + r * math.sin( angle )
        ptx = newlat(ptx)      
        points[i] = '[' ..  string.format("%.6f",pty) ..  "," .. string.format("%.6f",ptx) .. "],"

      end

      for i = 1,table.getn(points), 1 do
         coordinates = coordinates .. points[i] .. "\n"
      end

      coordinates = coordinates .. points[1]

	  if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[[') .. part4b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part3a .. string.gsub(coordinates,'^%[','[[') .. part3b
           end
	   else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[[') .. part2b
           else
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part1a .. string.gsub(coordinates,'^%[','[[') .. part1b
           end	   
	   
	   end

      return coordinates

end

-- X_SHAPE 

function p.x(frame)
	   local shape = "xshape"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   


        local group = frame.args['group'] or 'xshape'
        local title = frame.args['title'] or 'An X'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local r2 = r * .375
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

      local angle = 0

      local compass = positions(shape)
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

      lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)
      for i = 1,table.getn(compass), 1 do
          angle = compass[i] * math.pi / 180
             if compass[i] == 90 or compass[i] == 180 or compass[i] == 270 or compass[i] == 360 then
                ptx = lat + r2 * math.cos( angle )
                pty = long + r2 * math.sin( angle )
             else
                ptx = lat + r * math.cos( angle )
                pty = long + r * math.sin( angle )
             end

          ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)

          coordinates = coordinates .. "[" .. pty .. "," .. ptx .. "]@@@@@"

       end  
          coordinates = coordinates .. string.gsub(coordinates,'@@@@@.*','')
          coordinates = string.gsub(coordinates,'@@@@@',',')

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates
end

-- RECTANGLE - simple styled rectangle which makes it limited

function p.rectangle(frame)
	   local shape = frame.args['rectangle'] or "rectangle"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local group = frame.args['group'] or 'rectangle'
        local title = frame.args['title'] or 'A set rectangle'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING 
description = aligndesc(description,descattr)
        local name = frame.args['name'] or "A Center Rectangle"
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                r = r + r
                if r > 10 then error("10 for radius is MAX") end  
                if r <= 0 then error("r has to be greater than 0") end
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
 local strokewidth = frame.args['strokewidth'] or "1" 
 local strokeopacity = frame.args['strokeopacity'] or "0.5"
 local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
              if mapframe == nill or mapframe == "" then mapframe = "no" end
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end

local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)
        
        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        local angle1,angle2,angle3,angle4 = 0,0,0,0
        local ptx,ptx2,ptx3,ptx4 = 0,0,0,0
        local pty,pty2,pty3,pty4 = 0,0,0,0
--        local a = 45
--        local b = 135
--        local c = 225
--        local d = 315     
        
        local a = 60
        local b = 120
        local c = 240
        local d = 300
        
        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r * math.cos( angle3 )
        pty3 = long + r * math.sin( angle3 )
        
        angle4 = d * math.pi /180
        ptx4 = lat + r * math.cos( angle4 )
        pty4 = long + r * math.sin( angle4 )
        
        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. pty3 .. "," .. ptx3 .. "],[".. pty4 .. "," .. ptx4 .. "],[" .. pty .. "," .. ptx .. "]"

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates

end

-- POINT

function p.point(frame)
--	local partof = ""
	local t = {}
	local entity = ''
	local claims = ''
	local coordinates = ""
    local image = frame.args['image'] or ""
    	if image ~= nil and image ~= "" then
	     image = '[[File:' .. image .. '|center|border|280x280px|link=]]'
     end
	local code = ""
	local count = 0
	local lat = frame.args['lat'] or ""
	local long = frame.args['long'] or ""
	local id = frame.args['id'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	
	

	local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
	local color = frame.args['color'] or "#ff0000"
         if string.len(color) ~= 7 then error("Incorrect length for argument color") end
         if string.gsub(color,"#[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 color") end
	local title = frame.args['title'] or ""
	local symbol = frame.args['symbol'] or "city"
	local size = frame.args['size'] or "medium" 
	
    if id ~= nil and id ~= '' and id ~= "" then
       entity = mw.wikibase.getEntityObject(id)	
	   claims = entity.claims
	   if image == nil or image == "" then
		    if pcall(function () t = claims.P18 end) then
			   if pcall(function () t = entity.claims.P18[1].mainsnak.datavalue.value end ) then		
				  image = entity.claims.P18[1].mainsnak.datavalue.value
				  if image ~= nil and image ~= "" then
				     image = '[[File:' .. image .. '|center|border|280x280px|link=]]'
				  end
			    end
		    end
        end
		t = {}
		if pcall(function () t = claims.P296 end) then
			if pcall(function () t = entity.claims.P296[1].mainsnak.datavalue.value end ) then		
				code = entity.claims.P296[1].mainsnak.datavalue.value
			end
		end
	 end

     if count == 0 then       -- #description has no beginning image then use image from wikidata if any
        if image ~= nil and image ~= "" then
             description = image .. description
          end
     end
     description = aligndesc(description,descattr)

	
-- Special Case - adding code (abbrev) to title while testing train stations - symbol rail trigger
    if symbol == "rail" then
	   if title ~= nil and title ~= "" then
		  if code ~= nil and code ~= "" then
			title = title .. ' (' .. code .. ')'
			end
	   end
    end
    
    coordinates = "{\n" ..  '\t"type": "Feature",\n' .. '\t\t"geometry": { "type": "Point", "coordinates": [' .. long .. "," .. lat .. ']},\n'
coordinates = coordinates .. '\t\t"properties": {\n' ..  '\t\t\t"description": "' .. description .. '",\n' ..  '\t\t\t"title": "' .. title .. '",\n'
coordinates = coordinates ..  '\t\t\t"marker-color": "' .. color .. '",\n' ..  '\t\t\t"marker-symbol": "' .. symbol  .. '",\n' ..  '\t\t\t"marker-size": "' .. size .. '",\n'
coordinates = coordinates .. '\t\t}' .. '}\n'

return coordinates

end
-- POINTER

function p.pointer(frame)
	   local shape = "pointer"
	   local id = frame.args['id']	or ""
local lat=frame.args['lat'] or ""
local long=frame.args['long'] or ""
if lat == "" or lat == nil or long == "" or long == nil then
  id = checkid(id)
  lat = latitude(id)
  long = longitude(id)		   
  end	   

        local latitude = lat
        local longitude = long

        local group = frame.args['group'] or 'pointer'
        local title = frame.args['title'] or 'A pointer'
        local description = frame.args['desc'] or ''
    local descattr = frame.args['descattr'] or 'l' -- TESTING
description = aligndesc(description,descattr)    
        local r = frame.args['radius'] or ".5" 
                r = tonumber(r)
                if r > 10 then error("10 for length is MAX") end 
                if r <= 0 then error("r has to be greater than 0") end
                r = r * 2
        local r2 = r/2
        local r3 = r/3
        local fill = frame.args['fill'] or "#ccef64"
        local stroke = frame.args['stroke'] or "#0000ff"
local strokewidth = frame.args['strokewidth'] or "1"
local strokeopacity = frame.args['strokeopacity'] or "0.5"
local fillopacity = frame.args['fillopacity'] or "0.5"
        checkhex(fill,stroke)
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""
        local type = frame.args['type'] or "line" -- default line for LineString
        if type ~= "line" then
                type = "poly"
        end
      local direction = frame.args['direction'] or "1"
           if direction == nil or direction == "" then direction = "1" end      
            direction = string.gsub(direction,'%..*','')
            if string.gsub(direction,"^[1-8]$","") ~= "" then direction="1" end
            direction = tonumber(direction)
            if direction <= 0 or direction >= 9 then error("Direction should be a number from 1 to 8!") end

      local angle1,angle2,angle3,angle4 = 0,0,0,0
      local ptx,ptx2,ptx3,ptx4 = 0,0,0,0
      local pty,pty2,pty3,pty4 = 0,0,0,0

      local factor = {'20,360,340','25,45,65','70,90,110','115,135,155','160,180,200','205,225,245','250,270,290','295,315,335'}
      local a = string.gsub(factor[direction],'%,.*$','') -- eat everything after a comma - hungry
      local b = string.gsub(factor[direction],'^.*%,','') -- eat everything up to a comma - hungry
      local c = string.gsub(factor[direction],'(%d+)(,)(%d+)(,)(%d+)','%3')
-- MISSING FIX
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat,long,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity)      
--        local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = parts(lat,long,group,title,description,fill,stroke)

        lat = math.log(math.tan((90 + lat) * math.pi/360)) / (math.pi/180)

        angle1 = a * math.pi / 180
        ptx = lat + r * math.cos( angle1 )
        pty = long + r * math.sin( angle1 )

        angle2 = b * math.pi /180
        ptx2 = lat + r * math.cos( angle2 )
        pty2 = long + r * math.sin( angle2 )

        angle3 = c * math.pi /180
        ptx3 = lat + r2 * math.cos( angle3 )
        pty3 = long + r2 * math.sin( angle3 )

        angle4 = c * math.pi /180
        ptx4 = lat + r3 * math.cos( angle3 )
        pty4 = long + r3 * math.sin( angle3 )

        ptx,pty = string.format("%.6f",newlat(ptx)),string.format("%.6f",pty)
        ptx2,pty2 = string.format("%.6f",newlat(ptx2)),string.format("%.6f",pty2)
        ptx3,pty3 = string.format("%.6f",newlat(ptx3)),string.format("%.6f",pty3)
        ptx4,pty4 = string.format("%.6f",newlat(ptx4)),string.format("%.6f",pty4)
        lat,long = string.format("%.6f",newlat(lat)),string.format("%.6f",long)

        coordinates = "[" .. pty .. "," .. ptx .. "],[" .. pty3 .. "," .. ptx3 .. "],[" .. pty2 .. "," .. ptx2 .. "],[" .. long .. "," .. lat .. "],[" .. pty .. "," .. ptx .. "]"  

        coordinates = putittogether(mapframe,type,part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b,coordinates)

      return coordinates
end

-- External from OpenStreetMap

function p.external(frame)
	local id = frame.args['id'] or 'Q20'
	local title = frame.args['title'] or ""
	local fill = frame.args['fill'] or "#87deaa"
	local stroke = frame.args['stroke'] or "#000000"
    local strokewidth = frame.args['strokewidth'] or "1"
    local strokeopacity = frame.args['strokeopacity'] or "0.5"
    local fillopacity = frame.args['fillopacity'] or "0.5"
	local description = frame.args['desc'] or ""
	local descattr = frame.args['descattr'] or "l"
	local file = frame.args['file'] or ""
	local geotype = frame.args['geotype'] or "geoshape"

description = aligndesc(description,descattr)	

    if geotype == "page" then
       coordinates = '{'
       coordinates = coordinates .. '"type": "ExternalData",'
       coordinates = coordinates ..   '\t\t "service": "' .. geotype .. '",'       
       coordinates = coordinates .. '\t\t"title": "' .. file .. '"'
       coordinates = coordinates .. '}'
    else
	coordinates = '{'
	coordinates = coordinates ..  '"type": "ExternalData",\n'
	coordinates = coordinates ..  '\t  "properties": {\n'
	coordinates = coordinates ..  '\t\t"title": "' .. title .. '",\n'
	coordinates = coordinates ..  '\t\t"description": "' .. description .. '",\n'
	coordinates = coordinates ..  '\t\t"fill": "' .. fill .. '",\n'
	coordinates = coordinates ..  '\t\t"fill-opacity":' .. fillopacity .. ',\n'	
	coordinates = coordinates ..  '\t\t"stroke": "' .. stroke .. '",\n'
	coordinates = coordinates ..  '\t\t"stroke-opacity":' .. strokeopacity .. ',\n'		
	coordinates = coordinates ..  '\t\t"stroke-width":' .. strokewidth .. ',\n'
	coordinates = coordinates ..  '\t\t},\n'
	coordinates = coordinates ..  '\t\t "service": "' .. geotype .. '",\n'
    coordinates = coordinates ..  '\t\t"ids": "' .. id .. '"\n'
	coordinates = coordinates .. '}'    
	end

	return coordinates
	
end

-- External from OpenStreetMap

function p.background(frame)
	local title = frame.args['title'] or ""
	local fill = frame.args['fill'] or "#baf326"
	local stroke = "#000000"
    local strokewidth = "4"
    local strokeopacity = frame.args['strokeopacity'] or "0.5"
    local fillopacity = frame.args['fillopacity'] or "0.025"
	local description = ""
	local coordinates = ""

coordinates = '{"type": "Feature","geometry": { "type":"Polygon", 	"coordinates":'
coordinates = coordinates .. '[[[-3600,90], [3600, 90], [3600,-90], [-3600,-90], [-3600,90]]]},\n'
coordinates = coordinates .. '\t\t"properties":{\n'
coordinates = coordinates .. '\t\t"title": "' .. title .. '",\n'
coordinates = coordinates .. '\t\t"description": "' .. description .. '",\n'
coordinates = coordinates .. '\t\t"fill": "' .. fill .. '",\n'
coordinates = coordinates .. '\t\t"stroke":"' .. stroke .. '",\n'
coordinates = coordinates .. '\t\t"fill-opacity":' .. fillopacity .. ',\n'
coordinates = coordinates .. '\t\t"stroke-width":' .. strokewidth .. '\n'
coordinates = coordinates .. '}}'

	return coordinates
	
end

function p.empty(frame)
	
	return ""

end

-- LINE
-- MAKE LINE2 which will take 2 sets of coordinates to build a line instead of IDs
function p.line(frame)
	    local shape = "line"
        local id = frame.args['id'] or ""
        local id2 = frame.args['id2'] or ""
        if id == nil or id == "" then error("Missing id!") end
        if id2 == nil or id2 == "" then error("Missing id!") end
		     checkid(id)
			 checkid(id2)		
        local lat1,long1,lat2,long2 = "","","",""
		lat1 = latitude(id)
		lat2 = latitude(id2)
		long1 = longitude(id)
		long2 = longitude(id2)
        local type = "line" 
        local title = frame.args['title'] or 'A line'
		local group = frame.args['group'] or "line"
        local description = frame.args['desc'] or ''
     local descattr = frame.args['descattr'] or 'l' -- TESTING       
        local mapframe = frame.args['mapframe'] or "no"
                if mapframe == nill or mapframe == "" then mapframe = "no" end              
        local coordinates = ""		
		local fill = frame.args['fill'] or "#000000" 
		local fillopacity = frame.args['fillopacity'] or "0.5"
        local stroke = frame.args['stroke'] or "#0000ff"
        local strokeopacity = frame.args['strokeopacity'] or "0.5"
		local strokewidth = frame.args['strokewidth'] or "1"
		local data = {}
        data[1] = "[" .. long1 .. "," .. lat1 .. "]"
        data[2] = "[" .. long2 .. "," .. lat2 .. "]"
        coordinates = "[" .. data[1] .. "," .. data[2] .. "]},"
local part1a,part1b,part2a,part2b,part3a,part3b,part4a,part4b = partsnew(lat1,long1,group,title,description,fill,fillopacity,stroke,strokewidth,strokeopacity) 
        if mapframe == "y" or mapframe == "yes" then
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part4a .. string.gsub(coordinates,'^%[','[[') .. part4b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part3a .. coordinates .. part3b
           end
		else
           if type == "poly" then
                coordinates  = string.gsub(coordinates,'%]%,$',']]},')
                coordinates = part2a .. string.gsub(coordinates,'^%[','[[') .. part2b
           else
                coordinates = string.gsub(coordinates,'%]%,$',']},')
                coordinates = part1a .. coordinates .. part1b
           end		
		end

        return coordinates
end


-- END MODULE


return p