package tim.prune.function.search; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import tim.prune.App; import tim.prune.I18nManager; import tim.prune.data.DataPoint; import tim.prune.data.Distance; import tim.prune.data.Field; import tim.prune.data.Latitude; import tim.prune.data.Longitude; import tim.prune.data.SourceInfo; import tim.prune.data.UnitSetLibrary; import tim.prune.load.MediaLinkInfo; /** * Function to search mapillary for photos */ public class SearchMapillaryFunction extends GenericDownloaderFunction { /** Maximum number of results to get */ private static final int MAX_RESULTS = 20; /** * Constructor * @param inApp app object */ public SearchMapillaryFunction(App inApp) { super(inApp); } @Override public String getNameKey() { return "function.mapillary"; } @Override protected String getColumnKey(int inColNum) { if (inColNum == 0) return "dialog.wikipedia.column.name"; return "dialog.wikipedia.column.distance"; } /** * Run method, for searching in a separate thread */ public void run() { _statusLabel.setText(I18nManager.getText("confirm.running")); // Get coordinates from current point (if any) or from centre of screen double lat = 0.0, lon = 0.0; DataPoint currentPoint = _app.getTrackInfo().getCurrentPoint(); if (currentPoint == null) { double[] coords = _app.getViewport().getBounds(); lat = (coords[0] + coords[2]) / 2.0; lon = (coords[1] + coords[3]) / 2.0; } else { lat = currentPoint.getLatitude().getDouble(); lon = currentPoint.getLongitude().getDouble(); } // Construct URL final String urlString = "http://api.mapillary.com/v1/im/close?lat=" + lat + "&lon=" + lon + "&distance=1000&limit=" + MAX_RESULTS; //System.out.println(urlString); InputStream inStream = null; try { inStream = new URL(urlString).openStream(); StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch = inStream.read()) >= 0) { sb.append((char) ch); } //System.out.println("Got answer: '" + sb.toString() + "'"); ArrayList resultList = new ArrayList(); for (String result : sb.toString().split("\\},\\{")) { //System.out.println("Result: '" + result + "'"); SearchResult sr = new SearchResult(); for (String prop : result.split(",")) { String key = getKey(prop); if (key == null) {continue;} if (key.equals("key")) { final String value = getValue(prop); sr.setDownloadLink("http://images.mapillary.com/" + value + "/thumb-1024.jpg"); sr.setWebUrl("http://www.mapillary.com/map/im/" + value); sr.setTrackName(value); } else if (key.equals("lat")) { sr.setLatitude(getValue(prop)); } else if (key.equals("lon")) { sr.setLongitude(getValue(prop)); } } if (sr.getLatitude() != null && sr.getLongitude() != null && sr.getTrackName() != null) { // Calculate distance away from current point and set this in sr.setLength DataPoint resultPoint = new DataPoint(new Latitude(sr.getLatitude()), new Longitude(sr.getLongitude()), null); if (resultPoint.isValid() && currentPoint != null && currentPoint.isValid()) { double radianDist = DataPoint.calculateRadiansBetween(currentPoint, resultPoint); double metresAway = Distance.convertRadiansToDistance(radianDist, UnitSetLibrary.UNITS_METRES); sr.setLength(metresAway); } // If there's a valid result, add it to the temporary list if (sr.getTrackName() != null) { resultList.add(sr); } } } // Add all the results to the table model in one go if (!resultList.isEmpty()) { _trackListModel.addTracks(resultList); } } catch (Exception e) { _errorMessage = e.getClass().getName() + " - " + e.getMessage(); } // Close stream and ignore errors try { inStream.close(); } catch (Exception e) {} // Set status label according to error or "none found", leave blank if ok if (_errorMessage == null && _trackListModel.isEmpty()) { _errorMessage = I18nManager.getText("dialog.mapillary.nonefound"); } _statusLabel.setText(_errorMessage == null ? "" : _errorMessage); } /** * From a JSON key:value string, return just the key * @param inString string to parse * @return just the key without the surrounding quotes, or null if not found */ private static String getKey(String inString) { if (inString == null || inString.equals("")) {return null;} final int colonPos = inString.indexOf(':'); if (colonPos <= 0) {return null;} int startPos = 0; char c; while ((c = inString.charAt(startPos)) == '[' || c == '{' || c == '\"') { startPos++; } int endPos = colonPos; while ((c = inString.charAt(endPos-1)) == '\"') { endPos--; } return inString.substring(startPos, endPos); } /** * From a JSON key:value string, return just the value * @param inString string to parse * @return just the value without the surrounding quotes */ private static String getValue(String inString) { final int colonPos = inString.indexOf(':'); if (colonPos <= 0 || colonPos >= inString.length()) {return null;} int startPos = colonPos+1; char c; while ((c = inString.charAt(startPos)) == '\"') { startPos++; } int endPos = inString.length()-1; while ((c = inString.charAt(endPos-1)) == '\"' || c == '}' || c == ']') { endPos--; } return inString.substring(startPos, endPos); } @Override protected void loadSelected() { // Find the row(s) selected in the table and get the corresponding track int numSelected = _trackTable.getSelectedRowCount(); if (numSelected < 1) return; int[] rowNums = _trackTable.getSelectedRows(); String[][] pointData = new String[numSelected][]; String[] linkArray = new String[numSelected]; // Loop over each of the selected points for (int i=0; i= 0 && rowNum < _trackListModel.getRowCount()) { SearchResult result = _trackListModel.getTrack(rowNum); //String url = result.getDownloadLink(); pointData[i][0] = result.getLatitude(); pointData[i][1] = result.getLongitude(); pointData[i][2] = "1"; // all points have a new segment linkArray[i] = result.getDownloadLink(); } } // Prepare the data for the app final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.NEW_SEGMENT}; _app.autoAppendNextFile(); _app.informDataLoaded(fields, pointData, null, new SourceInfo("mapillary", SourceInfo.FILE_TYPE.JSON), null, new MediaLinkInfo(linkArray)); // Close the dialog _cancelled = true; _dialog.dispose(); } }