Giving user responses in Maps is a very common reply of various assistants. Android and iOS clients of SUSI.AI can Render their own custom map views but there is a challenge in doing that in Bots and other clients which can only render Images.
The MapServlet in SUSI-Server is a servlet that takes the constraints of a map as input parameters and returns PNG Image of the rendered map.
This is a simple HttpServlet. Since it does not requires any auth or user rights we do not extend AbstactAPIHandler in this class.
public class MapServlet extends HttpServlet {
This is to method which runs whenever the Servlet receives a GET Query. After getting the query the function call another function “process(…)” which processes the input parameters.
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Query post = RemoteAccess.evaluate(request);
This line is the for DDOS Protection. It checks if the user query rate is too high and rate limit his queries. If Server suspects that the post is a DDOS then it returns a 503 error.
if (post.isDoS_blackout()) { response.sendError(503, "your request frequency is too high"); return; } process(request, response, post);
The process method get the zoom, latitude, longitude, width and the height of the map and checks for the errors in them.
if (map.getHeight() > height || map.getWidth() > width) { BufferedImage bi = map.getImage(); int xoff = (map.getWidth() - width) / 2; int yoff = (map.getHeight() - height) / 2; bi = bi.getSubimage(xoff, yoff, width, height); map = new RasterPlotter(width, height, RasterPlotter.DrawMode.MODE_REPLACE, "FFFFFF"); map.insertBitmap(bi, 0, 0); }
Then we compute our image using RasterPlotter.
map.setDrawMode(DrawMode.MODE_SUB); map.setColor(0xffffff); if (text.length() > 0) PrintTool.print(map, 6, 12, 0, uppercase ? text.toUpperCase() : text, -1, false, 100); PrintTool.print(map, map.getWidth() - 6, map.getHeight() - 6, 0, "MADE WITH LOKLAK.ORG", 1, false, 50);
Here we calculate the height of the map. If a user passed a height and width in get parameters, we scale the map according to that but if not its 256×256.
int mx = (int) (map.getWidth() * (lon - west_lon) / (east_lon - west_lon)); int my = (int) (map.getHeight() * (lat - north_lat) / (south_lat - north_lat)); // the marker has a height of 40 pixel and a width of 25 pixel final BufferedImage logo = ImageIO.read(FileSystems.getDefault().getPath("html").resolve("artwork").resolve("marker-red.png").toFile()); map.insertBitmap(logo, Math.min(map.getWidth() - 25, Math.max(0, mx - 12)), Math.min(map.getHeight() - 40, Math.max(0, my - 40)), FilterMode.FILTER_ANTIALIASING);
We use the code below to set some text on the map for example the name of the place or the city etc.
map.setDrawMode(DrawMode.MODE_SUB); map.setColor(0xffffff); if (text.length() > 0) PrintTool.print(map, 6, 12, 0, uppercase ? text.toUpperCase() : text, -1, false, 100); PrintTool.print(map, map.getWidth() - 6, map.getHeight() - 6, 0, "MADE WITH LOKLAK.ORG", 1, false, 50);
Finally we draw a marker on map
int mx = (int) (map.getWidth() * (lon - west_lon) / (east_lon - west_lon)); int my = (int) (map.getHeight() * (lat - north_lat) / (south_lat - north_lat)); final BufferedImage logo = ImageIO.read(FileSystems.getDefault().getPath("html").resolve("artwork").resolve("marker-red.png").toFile()); map.insertBitmap(logo, Math.min(map.getWidth() - 25, Math.max(0, mx - 12)), Math.min(map.getHeight() - 40, Math.max(0, my - 40)), FilterMode.FILTER_ANTIALIASING);
At last we set the copyright message of OPENSTREETMAP at the bottom left.
PrintTool.print(map, 6, map.getHeight() - 6, 0, "(C) OPENSTREETMAP CONTRIBUTORS", -1, false, 100);
At the end we write the image and set the headers for Cross Origin Access.
response.addHeader("Access-Control-Allow-Origin", "*"); RemoteAccess.writeImage(fileType, response, post, map); post.finalize(); } }
The servlet can be tested locally at
http://localhost:4000/vis/map.png?text=Test&mlat=1.28373&mlon=103.84379&zoom=18
Or on the live SUSI Server
http://api.susi.ai/vis/map.png?text=Test&mlat=1.28373&mlon=103.84379&zoom=18
Output:
References:
https://www.openstreetmap.org/