Squashed commit of the following:
commit9a8a4e16b2
Author: simon <myhosting2012@gmail.com> Date: Thu Sep 3 00:13:28 2020 +0300 server refactoring1 commite47493a229
Author: simon <myhosting2012@gmail.com> Date: Wed Sep 2 23:31:12 2020 +0300 server refactoring commit6a95630076
Author: simon <myhosting2012@gmail.com> Date: Wed Sep 2 18:40:42 2020 +0300 api router mapactivity changes commite6a345e0e9
Author: simon <myhosting2012@gmail.com> Date: Mon Aug 31 18:10:11 2020 +0300 add variables lat lon zoom commit04bb04f21c
Author: simon <myhosting2012@gmail.com> Date: Mon Aug 31 16:45:54 2020 +0300 tiles by lat lon commit3019e35d04
Author: simon <myhosting2012@gmail.com> Date: Mon Aug 31 15:45:53 2020 +0300 changing resourceManager commit8a8fcd8d58
Author: simon <myhosting2012@gmail.com> Date: Mon Aug 31 15:26:28 2020 +0300 cleanup commit3f9b0f03d4
Author: simon <myhosting2012@gmail.com> Date: Mon Aug 31 11:35:00 2020 +0300 display loaded tile commitdb49b925ca
Author: simon <myhosting2012@gmail.com> Date: Thu Aug 27 14:29:57 2020 +0300 saving tile response commitef2bc3677c
Author: simon <myhosting2012@gmail.com> Date: Tue Aug 25 13:17:33 2020 +0300 markers coloured
|
@ -2,6 +2,8 @@ package net.osmand.data;
|
||||||
|
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class RotatedTileBox {
|
public class RotatedTileBox {
|
||||||
|
|
||||||
/// primary fields
|
/// primary fields
|
||||||
|
@ -69,6 +71,57 @@ public class RotatedTileBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
RotatedTileBox tileBox = (RotatedTileBox) o;
|
||||||
|
return this.compare(tileBox.lat, lat) &&
|
||||||
|
this.compare(tileBox.lon, lon) &&
|
||||||
|
this.compare(tileBox.rotate, rotate) &&
|
||||||
|
this.compare(tileBox.density, density) &&
|
||||||
|
zoom == tileBox.zoom &&
|
||||||
|
this.compare(tileBox.mapDensity, mapDensity) &&
|
||||||
|
this.compare(tileBox.zoomAnimation, zoomAnimation) &&
|
||||||
|
this.compare(tileBox.zoomFloatPart, zoomFloatPart) &&
|
||||||
|
cx == tileBox.cx &&
|
||||||
|
cy == tileBox.cy &&
|
||||||
|
pixWidth == tileBox.pixWidth &&
|
||||||
|
pixHeight == tileBox.pixHeight &&
|
||||||
|
this.compare(tileBox.zoomFactor, zoomFactor) &&
|
||||||
|
this.compare(tileBox.rotateCos, rotateCos) &&
|
||||||
|
this.compare(tileBox.rotateSin, rotateSin) &&
|
||||||
|
this.compare(tileBox.oxTile, oxTile) &&
|
||||||
|
this.compare(tileBox.oyTile, oyTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double E = 0.0001;
|
||||||
|
|
||||||
|
private boolean compare(float lon, float lon1) {
|
||||||
|
return Math.abs(lon1-lon) < E;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compare(double lon, double lon1) {
|
||||||
|
return Math.abs(lon1-lon) < E;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1 + (int)lat +
|
||||||
|
3* (int)(lon*1/E) +
|
||||||
|
5* (int)(rotate*1/E) +
|
||||||
|
7* (int)(density*1/E) +
|
||||||
|
11* zoom +
|
||||||
|
13* (int)(mapDensity*1/E) +
|
||||||
|
17* (int)(zoomAnimation*1/E) +
|
||||||
|
19* (int)(zoomFloatPart*1/E) +
|
||||||
|
23* cx +
|
||||||
|
29* cy +
|
||||||
|
31* pixWidth +
|
||||||
|
37* pixHeight;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void calculateDerivedFields() {
|
public void calculateDerivedFields() {
|
||||||
zoomFactor = Math.pow(2, zoomAnimation + zoomFloatPart) * 256 * mapDensity;
|
zoomFactor = Math.pow(2, zoomAnimation + zoomFloatPart) * 256 * mapDensity;
|
||||||
double rad = Math.toRadians(this.rotate);
|
double rad = Math.toRadians(this.rotate);
|
||||||
|
|
57
OsmAnd/assets/server/css/leaflet.awesome-markers.css
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Author: L. Voogdt
|
||||||
|
License: MIT
|
||||||
|
Version: 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Marker setup */
|
||||||
|
.awesome-marker {
|
||||||
|
margin-top:-42px;
|
||||||
|
margin-left: -17px;
|
||||||
|
position:absolute;
|
||||||
|
left:0;
|
||||||
|
top:0;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.awesome-marker .material-icons {
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.awesome-marker-shadow {
|
||||||
|
background: url('/images/markers-shadow.png') no-repeat 0 0;
|
||||||
|
width: 36px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retina displays */
|
||||||
|
@media (min--moz-device-pixel-ratio: 1.5),(-o-min-device-pixel-ratio: 3/2),
|
||||||
|
(-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5),(min-resolution: 1.5dppx) {
|
||||||
|
.awesome-marker-shadow {
|
||||||
|
background-image: url('/images/markers-shadow@2x.png');
|
||||||
|
background-size: 35px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.awesome-marker i {
|
||||||
|
color: #333;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.awesome-marker .icon-white {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Colors */
|
||||||
|
|
||||||
|
.awesome-marker-background {
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.awesome-marker:hover {
|
||||||
|
top: 2px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
101
OsmAnd/assets/server/go.html
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="cache-control" content="max-age=0"/>
|
||||||
|
<meta http-equiv="cache-control" content="no-cache"/>
|
||||||
|
<meta http-equiv="expires" content="0"/>
|
||||||
|
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"/>
|
||||||
|
<meta http-equiv="pragma" content="no-cache"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>OsmAnd - Offline Mobile Maps and Navigation</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/site.css?v=4"/>
|
||||||
|
<!-- <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /> -->
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.1.0/dist/leaflet.css"/>
|
||||||
|
<script src="https://unpkg.com/leaflet@1.1.0/dist/leaflet.js"></script>
|
||||||
|
<script type="text/javascript" src="/scripts/jquery-3.1.0.min.js"></script>
|
||||||
|
<!--
|
||||||
|
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
|
||||||
|
-->
|
||||||
|
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/1.5.2/css/ionicons.min.css">
|
||||||
|
<link rel="stylesheet" href="css/leaflet.awesome-markers.css">
|
||||||
|
<script src="/scripts/leaflet.awesome-markers.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/scripts/js.cookie.js"></script>
|
||||||
|
<script type="text/javascript" src="/scripts/go.js?v=5"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function getMarkerContent(feature) {
|
||||||
|
var p = feature.properties;
|
||||||
|
var popupContent = p.title;
|
||||||
|
if (p.opr_id) {
|
||||||
|
popupContent += " (" + p.opr_id + ") ";
|
||||||
|
}
|
||||||
|
if (p.tags) {
|
||||||
|
for (var t in p.tags) {
|
||||||
|
popupContent += "<br>" + t + " " + p.tags[t];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.opr_id) {
|
||||||
|
popupContent += "<br><a href=\'/api/admin?view=objects&browse=type&type=opr.place&subtype=id&key=" +
|
||||||
|
p.opr_id + "\'>OpenPlaceReviews</a>";
|
||||||
|
}
|
||||||
|
if (p.osm_id) {
|
||||||
|
popupContent += "<br><a href=\'https://www.openstreetmap.org/" +
|
||||||
|
p.osm_type + "/" + p.osm_id + "\'>OpenStreetMap</a>";
|
||||||
|
}
|
||||||
|
return popupContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
function markerClick(e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMarkers() {
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: "/favorites",
|
||||||
|
async: false,
|
||||||
|
contentType: "application/json",
|
||||||
|
dataType: 'json',
|
||||||
|
complete: function (r) {
|
||||||
|
var points = JSON.parse(r.responseText);
|
||||||
|
points.forEach(e => {
|
||||||
|
window.goMap.map.addPopupMarker(e, markerClick);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert("Error happened while getting favourite points " + e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
setupMarkers();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="gocontainer" id="gocontainer">
|
||||||
|
<div class="goheader">
|
||||||
|
<a href="/"><img src="/images/logo-grey.png" class="logo"/></a>
|
||||||
|
<div class="coordinatescontainer">
|
||||||
|
<div><span class="title">LAT</span><span class="coordinate latitude"></span></div>
|
||||||
|
<div><span class="title">LON</span><span class="coordinate longitude"></span></div>
|
||||||
|
</div>
|
||||||
|
<div class="clear:both;"></div>
|
||||||
|
</div>
|
||||||
|
<div id="map"></div>
|
||||||
|
<div class="overlay" style="display:none;"></div>
|
||||||
|
<div class="popup" style="display:none;">
|
||||||
|
<div class="logo"></div>
|
||||||
|
<h1>Did you know</h1>
|
||||||
|
<p>OsmAnd has an iOS application</p>
|
||||||
|
<a class="button yes" href="javascript:void(0);">Yep, I've already got it</a>
|
||||||
|
<a class="button no" href="javascript:void(0);">Nope, but I'd love to try it</a>
|
||||||
|
<a class="button cancel" href="javascript:void(0);">Leave me alone</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
OsmAnd/assets/server/images/markers-matte.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
OsmAnd/assets/server/images/markers-matte@2x.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
OsmAnd/assets/server/images/markers-plain.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
OsmAnd/assets/server/images/markers-shadow.png
Normal file
After Width: | Height: | Size: 535 B |
BIN
OsmAnd/assets/server/images/markers-shadow@2x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
OsmAnd/assets/server/images/markers-soft.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
OsmAnd/assets/server/images/markers-soft@2x.png
Normal file
After Width: | Height: | Size: 65 KiB |
273
OsmAnd/assets/server/scripts/go.js
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
var requestUtils={
|
||||||
|
'getParamValue':function(paramName){
|
||||||
|
let value= (location.search.split(paramName + '=')[1]||'').split('&')[0];
|
||||||
|
if (value && value.length > 0){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
'isIOS':function(){
|
||||||
|
return /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
|
||||||
|
},
|
||||||
|
'redirect':function(newUrl){
|
||||||
|
document.location = newUrl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var goMap = {
|
||||||
|
'config':{
|
||||||
|
'containerid': 'gocontainer',
|
||||||
|
'defaults':{
|
||||||
|
'lat':50.27,
|
||||||
|
'lon':30.30,
|
||||||
|
'zoom':13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'utils':{
|
||||||
|
'getPointFromUrl':function(){
|
||||||
|
let point = {};
|
||||||
|
point.lat = requestUtils.getParamValue('lat');
|
||||||
|
point.lon = requestUtils.getParamValue('lon');
|
||||||
|
point.zoom = requestUtils.getParamValue('z');
|
||||||
|
return point;
|
||||||
|
},
|
||||||
|
'isPointComplete':function(point){
|
||||||
|
if (!point.lat || !point.lon){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
'extendPoint':function(initialPoint, newPoint){
|
||||||
|
let point={};
|
||||||
|
point.lat=newPoint.lat;
|
||||||
|
if (!point.lat || point.lat == null){
|
||||||
|
point.lat = initialPoint.lat;
|
||||||
|
}
|
||||||
|
point.lon=newPoint.lon;
|
||||||
|
if (!point.lon || point.lon == null){
|
||||||
|
point.lon = initialPoint.lon;
|
||||||
|
}
|
||||||
|
point.zoom=newPoint.zoom;
|
||||||
|
if (!point.zoom || point.zoom == null){
|
||||||
|
point.zoom = initialPoint.zoom;
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'init': function(config){
|
||||||
|
if (config && typeof (config) == 'object') {
|
||||||
|
$.extend(goMap.config, config);
|
||||||
|
}
|
||||||
|
goMap.$container = $('#' + goMap.config.containerid);
|
||||||
|
goMap.$footer = goMap.$container.find('.gofooter');
|
||||||
|
goMap.$latitude = goMap.$container.find('.latitude');
|
||||||
|
goMap.$longitude = goMap.$container.find('.longitude');
|
||||||
|
|
||||||
|
let inputPoint = goMap.utils.getPointFromUrl();
|
||||||
|
goMap.point = goMap.utils.extendPoint(goMap.config.defaults, inputPoint);
|
||||||
|
goMap.refreshCoordinates();
|
||||||
|
|
||||||
|
goMap.map =$.mapwidget();
|
||||||
|
goMap.map.showPoint(goMap.point);
|
||||||
|
|
||||||
|
let inputComplete = goMap.utils.isPointComplete(inputPoint);
|
||||||
|
if (inputComplete){
|
||||||
|
goMap.map.addMarker(goMap.point);
|
||||||
|
}
|
||||||
|
goMap.point = goMap.utils.getPointFromUrl();
|
||||||
|
},
|
||||||
|
'refreshCoordinates':function(){
|
||||||
|
goMap.$latitude.text(goMap.point.lat);
|
||||||
|
goMap.$longitude.text(goMap.point.lon);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function toColor(num) {
|
||||||
|
num >>>= 0;
|
||||||
|
var b = num & 0xFF,
|
||||||
|
g = (num & 0xFF00) >>> 8,
|
||||||
|
r = (num & 0xFF0000) >>> 16,
|
||||||
|
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
|
||||||
|
return "rgba(" + [r, g, b, a].join(",") + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
$.mapwidget = function(config) {
|
||||||
|
var loc = goMap.point.lat + '/' + goMap.point.lon;
|
||||||
|
var lparams = '?mlat='+goMap.point.lat + '&mlon=' + goMap.point.lon;
|
||||||
|
var mapobj={
|
||||||
|
config: $.extend({
|
||||||
|
'mapid':'map',
|
||||||
|
'maxzoom':20,
|
||||||
|
'maxnativezoom':19,
|
||||||
|
'sourceurl':'https://tile.osmand.net/hd/{z}/{x}/{y}.png',
|
||||||
|
'attribution':'© <a href="https://www.openstreetmap.org/'+lparams+'#map=15/'+loc+'">OpenStreetMap</a> contributors'
|
||||||
|
}, config),
|
||||||
|
init:function(){
|
||||||
|
mapobj.map = L.map(mapobj.config.mapid);
|
||||||
|
L.tileLayer(mapobj.config.sourceurl, {
|
||||||
|
attribution: mapobj.config.attribution,
|
||||||
|
maxZoom: mapobj.config.maxzoom,
|
||||||
|
maxNativeZoom: mapobj.config.maxnativezoom
|
||||||
|
}).addTo(mapobj.map);
|
||||||
|
},
|
||||||
|
showPoint:function(point){
|
||||||
|
mapobj.map.setView([point.lat, point.lon], point.zoom);
|
||||||
|
},
|
||||||
|
addMarker:function(point){
|
||||||
|
L.marker([point.lat, point.lon]).addTo(mapobj.map);
|
||||||
|
},
|
||||||
|
addPopupMarker:function(favorite,onClickEvent){
|
||||||
|
window.point = favorite;
|
||||||
|
var point = {};
|
||||||
|
point.lat = favorite.latitude;
|
||||||
|
point.lon = favorite.longitude;
|
||||||
|
var popup = L.popup().setContent(
|
||||||
|
"name: <b>" + favorite.name + "</b><br/>" +
|
||||||
|
"address: <i>" + favorite.address + "</i><br/>"
|
||||||
|
+ "category: " + favorite.category);
|
||||||
|
var customMarker = L.AwesomeMarkers.icon({
|
||||||
|
icon: 'home',
|
||||||
|
markerColor: toColor(favorite.color),
|
||||||
|
iconColor: toColor(favorite.color)
|
||||||
|
});
|
||||||
|
L.marker([point.lat, point.lon],{icon: customMarker})
|
||||||
|
.bindPopup(popup)
|
||||||
|
.addTo(mapobj.map)
|
||||||
|
.on('click', function(e) {
|
||||||
|
onClickEvent(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mapobj.init();
|
||||||
|
return {
|
||||||
|
showPoint: mapobj.showPoint,
|
||||||
|
addMarker: mapobj.addMarker,
|
||||||
|
addPopupMarker: mapobj.addPopupMarker
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
$.timer=function(config){
|
||||||
|
var timerobj={
|
||||||
|
config: $.extend({
|
||||||
|
'timeoutInMs':300,
|
||||||
|
'maxActionDelayInMs':2000,
|
||||||
|
'action':function(){},
|
||||||
|
'actionparams':null
|
||||||
|
}, config),
|
||||||
|
init:function(){
|
||||||
|
timerobj.timer = null;
|
||||||
|
timerobj.startDate = null;
|
||||||
|
},
|
||||||
|
start:function(){
|
||||||
|
timerobj.cancel();
|
||||||
|
timerobj.startDate = new Date();
|
||||||
|
timerobj.timer=setTimeout(timerobj.onTimer, timerobj.config.timeoutInMs);
|
||||||
|
},
|
||||||
|
cancel:function(){
|
||||||
|
if (timerobj.timer != null){
|
||||||
|
clearTimeout(timerobj.timer);
|
||||||
|
timerobj.timer = null;
|
||||||
|
timerobj.startDate = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTimer:function(){
|
||||||
|
timerobj.timer= null;
|
||||||
|
let now = new Date();
|
||||||
|
if(now - timerobj.startDate < timerobj.config.maxActionDelayInMs){
|
||||||
|
timerobj.config.action(timerobj.config.actionparams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timerobj.init();
|
||||||
|
return {
|
||||||
|
start:timerobj.start,
|
||||||
|
cancel:timerobj.cancel
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
var iosAppRedirect = {
|
||||||
|
config:{
|
||||||
|
appPrefix:'osmandmaps://',
|
||||||
|
containerid:'gocontainer',
|
||||||
|
cookieName:'OsmAndInstalled',
|
||||||
|
cookieNoExpirationTimeoutInDays:30
|
||||||
|
},
|
||||||
|
init:function(config){
|
||||||
|
if (config && typeof (config) == 'object') {
|
||||||
|
$.extend(iosAppRedirect.config, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestUtils.isIOS()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iosAppRedirect.$container = $('#' + iosAppRedirect.config.containerid);
|
||||||
|
iosAppRedirect.$overlay = iosAppRedirect.$container.find('.overlay');
|
||||||
|
iosAppRedirect.$popup = iosAppRedirect.$container.find('.popup');
|
||||||
|
iosAppRedirect.$yesBtn = iosAppRedirect.$container.find('.yes');
|
||||||
|
iosAppRedirect.$noBtn = iosAppRedirect.$container.find('.no');
|
||||||
|
iosAppRedirect.$cancelBtn = iosAppRedirect.$container.find('.cancel');
|
||||||
|
iosAppRedirect.applestorelink = iosAppRedirect.$container.find('.gobadges .apple a').attr('href');
|
||||||
|
iosAppRedirect.applink = iosAppRedirect.config.appPrefix + document.location.search;
|
||||||
|
|
||||||
|
|
||||||
|
if (iosAppRedirect.isAppInstalled() === "yes"){
|
||||||
|
iosAppRedirect.redirectToApp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (iosAppRedirect.isAppInstalled() === "no"){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iosAppRedirect.$yesBtn.on('click', function(){
|
||||||
|
iosAppRedirect.redirectToApp();
|
||||||
|
iosAppRedirect.closePopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
iosAppRedirect.$noBtn.on('click', function(){
|
||||||
|
iosAppRedirect.setCookie(true);
|
||||||
|
iosAppRedirect.closePopup();
|
||||||
|
window.open(iosAppRedirect.applestorelink , '_blank');
|
||||||
|
});
|
||||||
|
|
||||||
|
iosAppRedirect.$cancelBtn.on('click', function(){
|
||||||
|
iosAppRedirect.setCookie(false);
|
||||||
|
iosAppRedirect.closePopup();
|
||||||
|
});
|
||||||
|
iosAppRedirect.openPopup();
|
||||||
|
},
|
||||||
|
isAppInstalled:function(){
|
||||||
|
return Cookies.get('OsmAndInstalled');
|
||||||
|
},
|
||||||
|
redirectToApp:function(){
|
||||||
|
iosAppRedirect.timer = $.timer({action:iosAppRedirect.clearCookie});
|
||||||
|
iosAppRedirect.timer.start();
|
||||||
|
requestUtils.redirect(iosAppRedirect.applink);
|
||||||
|
},
|
||||||
|
setCookie:function(appInstalled){
|
||||||
|
if (appInstalled === true){
|
||||||
|
Cookies.set(iosAppRedirect.config.cookieName, "yes");
|
||||||
|
}else{
|
||||||
|
Cookies.set(iosAppRedirect.config.cookieName, "no", { expires: iosAppRedirect.config.cookieNoExpirationTimeoutInDays });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearCookie:function(){
|
||||||
|
Cookies.remove('OsmAndInstalled');
|
||||||
|
},
|
||||||
|
openPopup:function(){
|
||||||
|
iosAppRedirect.$overlay.show();
|
||||||
|
iosAppRedirect.$popup.show();
|
||||||
|
},
|
||||||
|
closePopup:function(){
|
||||||
|
iosAppRedirect.$overlay.hide();
|
||||||
|
iosAppRedirect.$popup.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$( document ).ready(function() {
|
||||||
|
goMap.init();
|
||||||
|
iosAppRedirect.init();
|
||||||
|
});
|
134
OsmAnd/assets/server/scripts/leaflet.awesome-markers.js
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
|
||||||
|
(c) 2012-2013, Lennard Voogdt
|
||||||
|
|
||||||
|
http://leafletjs.com
|
||||||
|
https://github.com/lvoogdt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*global L*/
|
||||||
|
|
||||||
|
(function (window, document, undefined) {
|
||||||
|
"use strict";
|
||||||
|
/*
|
||||||
|
* Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
L.AwesomeMarkers = {};
|
||||||
|
|
||||||
|
L.AwesomeMarkers.version = '2.0.1';
|
||||||
|
|
||||||
|
L.AwesomeMarkers.Icon = L.Icon.extend({
|
||||||
|
options: {
|
||||||
|
shadowAnchor: [10, 12],
|
||||||
|
shadowSize: [36, 16],
|
||||||
|
className: 'awesome-marker',
|
||||||
|
icon: 'block',
|
||||||
|
markerColor: 'white',
|
||||||
|
iconColor: 'white'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
options = L.Util.setOptions(this, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function () {
|
||||||
|
var options = L.Util.setOptions(this);
|
||||||
|
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||||
|
var path = document.createElementNS('http://www.w3.org/2000/svg', "path");
|
||||||
|
var backgroundCircle = document.createElementNS('http://www.w3.org/2000/svg', "circle");
|
||||||
|
var icongroup = document.createElementNS('http://www.w3.org/2000/svg', "g");
|
||||||
|
var icon = document.createElementNS('http://www.w3.org/2000/svg', "text");
|
||||||
|
|
||||||
|
svg.setAttribute('width', '31');
|
||||||
|
svg.setAttribute('height', '42');
|
||||||
|
svg.setAttribute('class', 'awesome-marker');
|
||||||
|
svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||||
|
|
||||||
|
backgroundCircle.setAttribute('cx', '15.5');
|
||||||
|
backgroundCircle.setAttribute('cy', '15');
|
||||||
|
backgroundCircle.setAttribute('r', '11');
|
||||||
|
backgroundCircle.setAttribute('fill', options.markerColor);
|
||||||
|
|
||||||
|
path.setAttributeNS(null, "d", "M15.6,1c-7.7,0-14,6.3-14,14c0,10.5,14,26,14,26s14-15.5,14-26C29.6,7.3,23.3,1,15.6,1z");
|
||||||
|
//path.setAttribute('class', 'awesome-marker-background');
|
||||||
|
path.setAttribute('stroke', 'white');
|
||||||
|
path.setAttribute('style', 'fill:' + options.markerColor)
|
||||||
|
|
||||||
|
icon.textContent = options.icon;
|
||||||
|
icon.setAttribute('x', '7');
|
||||||
|
icon.setAttribute('y', '23');
|
||||||
|
icon.setAttribute('class', 'material-icons');
|
||||||
|
icon.setAttribute('fill', options.iconColor);
|
||||||
|
icon.setAttribute('font-family', 'Material Icons');
|
||||||
|
|
||||||
|
svg.appendChild(path);
|
||||||
|
svg.appendChild(backgroundCircle);
|
||||||
|
icongroup.appendChild(icon);
|
||||||
|
svg.appendChild(icongroup);
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createInner: function() {
|
||||||
|
var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;
|
||||||
|
|
||||||
|
if (options.spin && typeof options.spinClass === "string") {
|
||||||
|
iconSpinClass = options.spinClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.iconColor) {
|
||||||
|
if (options.iconColor === 'white' || options.iconColor === 'black') {
|
||||||
|
iconColorClass = "icon-" + options.iconColor;
|
||||||
|
} else {
|
||||||
|
iconColorStyle = "style='color: " + options.iconColor + "' ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'></i>"
|
||||||
|
return options.extraClasses + " " + iconClass + " " + iconSpinClass + " " + iconColorClass;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setIconStyles: function (img, name) {
|
||||||
|
var options = this.options,
|
||||||
|
size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
|
||||||
|
anchor;
|
||||||
|
|
||||||
|
if (name === 'shadow') {
|
||||||
|
anchor = L.point(options.shadowAnchor || options.iconAnchor);
|
||||||
|
} else {
|
||||||
|
anchor = L.point(options.iconAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anchor && size) {
|
||||||
|
anchor = size.divideBy(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
img.className = 'awesome-marker-' + name + ' ' + options.className;
|
||||||
|
|
||||||
|
if (anchor) {
|
||||||
|
img.style.marginLeft = (-anchor.x) + 'px';
|
||||||
|
img.style.marginTop = (-anchor.y) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
img.style.width = size.x + 'px';
|
||||||
|
img.style.height = size.y + 'px';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createShadow: function () {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
|
||||||
|
this._setIconStyles(div, 'shadow');
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
L.AwesomeMarkers.icon = function (options) {
|
||||||
|
return new L.AwesomeMarkers.Icon(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
}(this, document));
|
||||||
|
|
||||||
|
|
||||||
|
|
7
OsmAnd/assets/server/scripts/leaflet.awesome-markers.min.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
|
||||||
|
(c) 2012-2013, Lennard Voogdt
|
||||||
|
|
||||||
|
http://leafletjs.com
|
||||||
|
https://github.com/lvoogdt
|
||||||
|
*//*global L*/(function(e,t,n){"use strict";L.AwesomeMarkers={};L.AwesomeMarkers.version="2.0.1";L.AwesomeMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"awesome-marker",prefix:"glyphicon",spinClass:"fa-spin",icon:"home",markerColor:"blue",iconColor:"white"},initialize:function(e){e=L.Util.setOptions(this,e)},createIcon:function(){var e=t.createElement("div"),n=this.options;n.icon&&(e.innerHTML=this._createInner());n.bgPos&&(e.style.backgroundPosition=-n.bgPos.x+"px "+ -n.bgPos.y+"px");this._setIconStyles(e,"icon-"+n.markerColor);return e},_createInner:function(){var e,t="",n="",r="",i=this.options;i.icon.slice(0,i.prefix.length+1)===i.prefix+"-"?e=i.icon:e=i.prefix+"-"+i.icon;i.spin&&typeof i.spinClass=="string"&&(t=i.spinClass);i.iconColor&&(i.iconColor==="white"||i.iconColor==="black"?n="icon-"+i.iconColor:r="style='color: "+i.iconColor+"' ");return"<i "+r+"class='"+i.prefix+" "+e+" "+t+" "+n+"'></i>"},_setIconStyles:function(e,t){var n=this.options,r=L.point(n[t==="shadow"?"shadowSize":"iconSize"]),i;t==="shadow"?i=L.point(n.shadowAnchor||n.iconAnchor):i=L.point(n.iconAnchor);!i&&r&&(i=r.divideBy(2,!0));e.className="awesome-marker-"+t+" "+n.className;if(i){e.style.marginLeft=-i.x+"px";e.style.marginTop=-i.y+"px"}if(r){e.style.width=r.x+"px";e.style.height=r.y+"px"}},createShadow:function(){var e=t.createElement("div");this._setIconStyles(e,"shadow");return e}});L.AwesomeMarkers.icon=function(e){return new L.AwesomeMarkers.Icon(e)}})(this,document);
|
|
@ -136,6 +136,7 @@ import net.osmand.plus.routing.TransportRoutingHelper.TransportRouteCalculationP
|
||||||
import net.osmand.plus.search.QuickSearchDialogFragment;
|
import net.osmand.plus.search.QuickSearchDialogFragment;
|
||||||
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab;
|
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab;
|
||||||
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchType;
|
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchType;
|
||||||
|
import net.osmand.plus.server.ApiRouter;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener;
|
import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
@ -309,6 +310,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
||||||
int h = dm.heightPixels - statusBarHeight;
|
int h = dm.heightPixels - statusBarHeight;
|
||||||
|
|
||||||
mapView = new OsmandMapTileView(this, w, h);
|
mapView = new OsmandMapTileView(this, w, h);
|
||||||
|
ApiRouter.mapActivity = this;
|
||||||
if (app.getAppInitializer().checkAppVersionChanged() && WhatsNewDialogFragment.SHOW) {
|
if (app.getAppInitializer().checkAppVersionChanged() && WhatsNewDialogFragment.SHOW) {
|
||||||
SecondSplashScreenFragment.SHOW = false;
|
SecondSplashScreenFragment.SHOW = false;
|
||||||
WhatsNewDialogFragment.SHOW = false;
|
WhatsNewDialogFragment.SHOW = false;
|
||||||
|
|
106
OsmAnd/src/net/osmand/plus/activities/ServerActivity.java
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
package net.osmand.plus.activities;
|
||||||
|
|
||||||
|
import android.net.TrafficStats;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
import android.text.format.Formatter;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.server.OsmAndHttpServer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ServerActivity extends AppCompatActivity {
|
||||||
|
private boolean initialized = false;
|
||||||
|
private OsmAndHttpServer server;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
enableStrictMode();
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.server_activity);
|
||||||
|
findViewById(R.id.Button01).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (!initialized) {
|
||||||
|
updateTextView("Click second button to deactivate server");
|
||||||
|
initServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
findViewById(R.id.Button03).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (initialized) {
|
||||||
|
updateTextView("Click first button to activate server");
|
||||||
|
deInitServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enableStrictMode() {
|
||||||
|
StrictMode.setThreadPolicy(
|
||||||
|
new StrictMode.ThreadPolicy.Builder()
|
||||||
|
.detectDiskReads()
|
||||||
|
.detectDiskWrites()
|
||||||
|
.detectNetwork()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
StrictMode.setVmPolicy(
|
||||||
|
new StrictMode.VmPolicy.Builder()
|
||||||
|
.detectLeakedSqlLiteObjects()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateTextView(String text) {
|
||||||
|
((TextView) findViewById(R.id.TextView02)).setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initServer() {
|
||||||
|
final int THREAD_ID = 10000;
|
||||||
|
TrafficStats.setThreadStatsTag(THREAD_ID);
|
||||||
|
OsmAndHttpServer.HOSTNAME = getDeviceAddress();
|
||||||
|
try {
|
||||||
|
server = new OsmAndHttpServer();
|
||||||
|
server.setAndroidApplication((OsmandApplication)this.getApplication());
|
||||||
|
initialized = true;
|
||||||
|
updateTextView("Server started at: http://" + getDeviceAddress() + ":" + OsmAndHttpServer.PORT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(this,
|
||||||
|
e.getLocalizedMessage(),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDeviceAddress() {
|
||||||
|
WifiManager wm = (WifiManager) this.getApplicationContext().getSystemService(WIFI_SERVICE);
|
||||||
|
String ip = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
|
||||||
|
return ip != null ? ip : "0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deInitServer() {
|
||||||
|
if (server != null){
|
||||||
|
server.closeAllConnections();
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
deInitServer();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
}
|
266
OsmAnd/src/net/osmand/plus/server/ApiRouter.java
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
package net.osmand.plus.server;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.webkit.MimeTypeMap;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import fi.iki.elonen.NanoHTTPD;
|
||||||
|
import net.osmand.data.FavouritePoint;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static fi.iki.elonen.NanoHTTPD.newFixedLengthResponse;
|
||||||
|
|
||||||
|
public class ApiRouter implements OsmandMapTileView.IMapImageDrawListener {
|
||||||
|
private OsmandApplication androidContext;
|
||||||
|
|
||||||
|
public OsmandApplication getAndroidContext() {
|
||||||
|
return androidContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String FOLDER_NAME = "server";
|
||||||
|
private Gson gson = new Gson();
|
||||||
|
private Map<String, ApiEndpoint> endpoints = new HashMap<>();
|
||||||
|
//change to weakreference
|
||||||
|
public static MapActivity mapActivity;
|
||||||
|
|
||||||
|
public ApiRouter() {
|
||||||
|
initRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initRoutes() {
|
||||||
|
ApiEndpoint favorites = new ApiEndpoint();
|
||||||
|
favorites.uri = "/favorites";
|
||||||
|
favorites.apiCall = new ApiEndpoint.ApiCall() {
|
||||||
|
@Override
|
||||||
|
public NanoHTTPD.Response call(NanoHTTPD.IHTTPSession session) {
|
||||||
|
return newFixedLengthResponse(getFavoritesJson());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
endpoints.put(favorites.uri, favorites);
|
||||||
|
|
||||||
|
final ApiEndpoint tile = new ApiEndpoint();
|
||||||
|
tile.uri = "/tile";
|
||||||
|
tile.apiCall = new ApiEndpoint.ApiCall() {
|
||||||
|
@Override
|
||||||
|
public NanoHTTPD.Response call(NanoHTTPD.IHTTPSession session) {
|
||||||
|
try {
|
||||||
|
return tileApiCall(session);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return ErrorResponses.response500;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
endpoints.put(tile.uri, tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(3);
|
||||||
|
|
||||||
|
Map<RotatedTileBox, Bitmap> hashMap = new HashMap<>();
|
||||||
|
Map<RotatedTileBox, Bitmap> map = Collections.synchronizedMap(hashMap);
|
||||||
|
|
||||||
|
private synchronized NanoHTTPD.Response tileApiCall(NanoHTTPD.IHTTPSession session) {
|
||||||
|
int zoom = 0;
|
||||||
|
double lat = 0;//50.901430;
|
||||||
|
double lon = 0;//34.801775;
|
||||||
|
try {
|
||||||
|
String fullUri = session.getUri().replace("/tile/", "");
|
||||||
|
Scanner s = new Scanner(fullUri).useDelimiter("/");
|
||||||
|
zoom = s.nextInt();
|
||||||
|
lat = s.nextDouble();
|
||||||
|
lon = s.nextDouble();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ErrorResponses.response500;
|
||||||
|
}
|
||||||
|
mapActivity.getMapView().setMapImageDrawListener(this);
|
||||||
|
Future<Pair<RotatedTileBox, Bitmap>> future;
|
||||||
|
final RotatedTileBox rotatedTileBox = new RotatedTileBox.RotatedTileBoxBuilder()
|
||||||
|
.setLocation(lat, lon)
|
||||||
|
.setZoom(zoom)
|
||||||
|
.setPixelDimensions(512, 512, 0.5f, 0.5f).build();
|
||||||
|
future = executor.submit(new Callable<Pair<RotatedTileBox, Bitmap>>() {
|
||||||
|
@Override
|
||||||
|
public Pair<RotatedTileBox, Bitmap> call() throws Exception {
|
||||||
|
Bitmap bmp;
|
||||||
|
while ((bmp = map.get(rotatedTileBox)) == null) {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
return Pair.create(rotatedTileBox, bmp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mapActivity.getMapView().setCurrentRotatedTileBox(rotatedTileBox);
|
||||||
|
try {
|
||||||
|
Pair<RotatedTileBox, Bitmap> pair = future.get();
|
||||||
|
Bitmap bitmap = pair.second;// mapActivity.getMapView().currentCanvas;
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
|
byte[] byteArray = stream.toByteArray();
|
||||||
|
ByteArrayInputStream str = new ByteArrayInputStream(byteArray);
|
||||||
|
return newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.OK,
|
||||||
|
"image/png",
|
||||||
|
str,
|
||||||
|
str.available());
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ErrorResponses.response500;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ErrorResponses.response500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAndroidContext(OsmandApplication androidContext) {
|
||||||
|
this.androidContext = androidContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NanoHTTPD.Response route(NanoHTTPD.IHTTPSession session) {
|
||||||
|
Log.d("SERVER", "URI: " + session.getUri());
|
||||||
|
String uri = session.getUri();
|
||||||
|
if (uri.equals("/")) return getStatic("/go.html");
|
||||||
|
if (uri.contains("/scripts/") ||
|
||||||
|
uri.contains("/images/") ||
|
||||||
|
uri.contains("/css/") ||
|
||||||
|
uri.contains("/fonts/") ||
|
||||||
|
uri.contains("/favicon.ico")
|
||||||
|
) return getStatic(uri);
|
||||||
|
if (isApiUrl(uri)) {
|
||||||
|
return routeApi(session);
|
||||||
|
} else {
|
||||||
|
return routeContent(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NanoHTTPD.Response routeApi(NanoHTTPD.IHTTPSession session) {
|
||||||
|
String uri = session.getUri();
|
||||||
|
//TODO rewrite
|
||||||
|
if (uri.contains("tile")) {
|
||||||
|
return endpoints.get("/tile").apiCall.call(session);
|
||||||
|
}
|
||||||
|
ApiEndpoint endpoint = endpoints.get(uri);
|
||||||
|
if (endpoint != null) {
|
||||||
|
return endpoint.apiCall.call(session);
|
||||||
|
}
|
||||||
|
return ErrorResponses.response404;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isApiUrl(String uri) {
|
||||||
|
for (String endpoint : endpoints.keySet()) {
|
||||||
|
//TODO rewrite contains
|
||||||
|
if (endpoint.equals(uri) || uri.contains("tile")) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NanoHTTPD.Response routeContent(NanoHTTPD.IHTTPSession session) {
|
||||||
|
String url = session.getUri();
|
||||||
|
//add index page
|
||||||
|
String responseText = getHtmlPage(url);
|
||||||
|
if (responseText != null) {
|
||||||
|
return newFixedLengthResponse(responseText);
|
||||||
|
} else {
|
||||||
|
return ErrorResponses.response404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NanoHTTPD.Response getStatic(String uri) {
|
||||||
|
InputStream is = null;
|
||||||
|
String mimeType = parseMimeType(uri);
|
||||||
|
if (androidContext != null) {
|
||||||
|
try {
|
||||||
|
is = androidContext.getAssets().open(FOLDER_NAME + uri);
|
||||||
|
if (is.available() == 0) {
|
||||||
|
return ErrorResponses.response404;
|
||||||
|
}
|
||||||
|
return newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.OK,
|
||||||
|
mimeType,
|
||||||
|
is,
|
||||||
|
is.available());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return ErrorResponses.response404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrorResponses.response500;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseMimeType(String url) {
|
||||||
|
String type = null;
|
||||||
|
if (url.endsWith(".js")) return "text/javascript";
|
||||||
|
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||||
|
if (extension != null) {
|
||||||
|
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readHTMLFromFile(String filename) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try {
|
||||||
|
InputStream is = androidContext.getAssets().open(FOLDER_NAME + filename);
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(is,
|
||||||
|
Charset.forName("UTF-8")));
|
||||||
|
String str;
|
||||||
|
while ((str = br.readLine()) != null) {
|
||||||
|
sb.append(str);
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHtmlPage(String name) {
|
||||||
|
String responseText = "";
|
||||||
|
if (androidContext != null) {
|
||||||
|
responseText = readHTMLFromFile(name);
|
||||||
|
}
|
||||||
|
if (responseText == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFavoritesJson() {
|
||||||
|
List<FavouritePoint> points = androidContext.getFavorites().getFavouritePoints();
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
for (FavouritePoint p : points) {
|
||||||
|
String json = jsonFromFavorite(p);
|
||||||
|
text.append(json);
|
||||||
|
text.append(",");
|
||||||
|
}
|
||||||
|
return "[" + text.substring(0, text.length() - 1) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jsonFromFavorite(FavouritePoint favouritePoint) {
|
||||||
|
return gson.toJson(favouritePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(RotatedTileBox viewport, Bitmap bmp) {
|
||||||
|
this.map.put(viewport, bmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ErrorResponses {
|
||||||
|
static NanoHTTPD.Response response404 =
|
||||||
|
newFixedLengthResponse(NanoHTTPD.Response.Status.NOT_FOUND,
|
||||||
|
NanoHTTPD.MIME_PLAINTEXT, "404 Not Found");
|
||||||
|
|
||||||
|
static NanoHTTPD.Response response500 =
|
||||||
|
newFixedLengthResponse(NanoHTTPD.Response.Status.INTERNAL_ERROR,
|
||||||
|
NanoHTTPD.MIME_PLAINTEXT, "500 Internal Server Error");
|
||||||
|
}
|
||||||
|
}
|
30
OsmAnd/src/net/osmand/plus/server/ServerSessionHandler.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package net.osmand.plus.server;
|
||||||
|
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
|
||||||
|
import fi.iki.elonen.NanoHTTPD;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
|
||||||
|
public class ServerSessionHandler {
|
||||||
|
private OsmandApplication androidApplication;
|
||||||
|
|
||||||
|
private ApiRouter router = new ApiRouter();
|
||||||
|
|
||||||
|
public OsmandApplication getAndroidApplication() {
|
||||||
|
return androidApplication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAndroidApplication(OsmandApplication androidApplication) {
|
||||||
|
this.androidApplication = androidApplication;
|
||||||
|
router.setAndroidContext(androidApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapActivity(MapActivity activity) {
|
||||||
|
//todo
|
||||||
|
router.mapActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NanoHTTPD.Response handle(NanoHTTPD.IHTTPSession session) {
|
||||||
|
return router.route(session);
|
||||||
|
}
|
||||||
|
}
|
124
OsmAnd/src/net/osmand/plus/server/map/LayersDraw.java
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.map.ITileSource;
|
||||||
|
import net.osmand.map.TileSourceManager;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.render.MapVectorLayer;
|
||||||
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
|
import net.osmand.plus.views.MapTileLayer;
|
||||||
|
import net.osmand.plus.views.layers.FavouritesLayer;
|
||||||
|
import net.osmand.plus.views.layers.GPXLayer;
|
||||||
|
import net.osmand.plus.views.layers.MapTextLayer;
|
||||||
|
import net.osmand.plus.views.layers.RouteLayer;
|
||||||
|
|
||||||
|
public class LayersDraw {
|
||||||
|
public static void createLayers(OsmandApplication app, Canvas canvas, final OsmandMapTileMiniView mapView) {
|
||||||
|
RoutingHelper routingHelper = app.getRoutingHelper();
|
||||||
|
// first create to make accessible
|
||||||
|
MapTextLayer mapTextLayer = new MapTextLayer();
|
||||||
|
// 5.95 all labels
|
||||||
|
//mapView.addLayer(mapTextLayer, 5.95f);
|
||||||
|
// 8. context menu layer
|
||||||
|
//ContextMenuLayer contextMenuLayer = new ContextMenuLayer(app);
|
||||||
|
//mapView.addLayer(contextMenuLayer, 8);
|
||||||
|
// mapView.addLayer(underlayLayer, -0.5f);
|
||||||
|
RotatedTileBox currentTileBlock = mapView.getCurrentRotatedTileBox();
|
||||||
|
// RotatedTileBox currentTileBlock = new RotatedTileBox.RotatedTileBoxBuilder()
|
||||||
|
// .setLocation(50.901430, 34.801775)
|
||||||
|
// .setZoom(15)
|
||||||
|
// .setPixelDimensions(canvas.getWidth(), canvas.getHeight(), 0.5f, 0.5f).build();
|
||||||
|
|
||||||
|
MapTileMiniLayer mapTileLayer = new MapTileMiniLayer(true);
|
||||||
|
mapView.addLayer(mapTileLayer, 0.0f);
|
||||||
|
|
||||||
|
ITileSource map = TileSourceManager.getMapillaryVectorSource();
|
||||||
|
mapTileLayer.setMap(map);
|
||||||
|
mapTileLayer.drawTileMap(canvas,currentTileBlock);
|
||||||
|
//mapView.setMainLayer(mapTileLayer);
|
||||||
|
// 0.5 layer
|
||||||
|
MapVectorMiniLayer mapVectorLayer = new MapVectorMiniLayer(mapTileLayer, false);
|
||||||
|
mapView.addLayer(mapVectorLayer, 0.5f);
|
||||||
|
// mapVectorLayer.onPrepareBufferImage(canvas,
|
||||||
|
// currentTileBlock,
|
||||||
|
// new OsmandMapMiniLayer.DrawSettings(false));
|
||||||
|
//DownloadedRegionsLayer downloadedRegionsLayer = new DownloadedRegionsLayer(activity);
|
||||||
|
//mapView.addLayer(downloadedRegionsLayer, 0.5f);
|
||||||
|
|
||||||
|
// 0.9 gpx layer
|
||||||
|
GPXLayer gpxLayer = new GPXLayer();
|
||||||
|
//mapView.addLayer(gpxLayer, 0.9f);
|
||||||
|
|
||||||
|
// 1. route layer
|
||||||
|
RouteLayer routeLayer = new RouteLayer(routingHelper);
|
||||||
|
//mapView.addLayer(routeLayer, 1);
|
||||||
|
|
||||||
|
// 2. osm bugs layer
|
||||||
|
// 3. poi layer
|
||||||
|
POIMapLayerMini poiMapLayer = new POIMapLayerMini(app);
|
||||||
|
mapView.addLayer(poiMapLayer, 3);
|
||||||
|
|
||||||
|
poiMapLayer.onPrepareBufferImage(canvas, currentTileBlock,
|
||||||
|
new OsmandMapMiniLayer.DrawSettings(false));
|
||||||
|
// 4. favorites layer
|
||||||
|
FavouritesLayer mFavouritesLayer = new FavouritesLayer();
|
||||||
|
//mapView.addLayer(mFavouritesLayer, 4);
|
||||||
|
// 4.6 measurement tool layer
|
||||||
|
//MeasurementToolLayer measurementToolLayer = new MeasurementToolLayer();
|
||||||
|
//mapView.addLayer(measurementToolLayer, 4.6f);
|
||||||
|
// 5. transport layer
|
||||||
|
//TransportStopsLayer transportStopsLayer = new TransportStopsLayer(activity);
|
||||||
|
//mapView.addLayer(transportStopsLayer, 5);
|
||||||
|
// 5.95 all text labels
|
||||||
|
// 6. point location layer
|
||||||
|
//PointLocationLayer locationLayer = new PointLocationLayer(activity.getMapViewTrackingUtilities());
|
||||||
|
//mapView.addLayer(locationLayer, 6);
|
||||||
|
// 7. point navigation layer
|
||||||
|
//PointNavigationLayer navigationLayer = new PointNavigationLayer(activity);
|
||||||
|
//mapView.addLayer(navigationLayer, 7);
|
||||||
|
// 7.3 map markers layer
|
||||||
|
//MapMarkersMiniLayer mapMarkersLayer = new MapMarkersMiniLayer(app);
|
||||||
|
//mapView.addLayer(mapMarkersLayer, 7.3f);
|
||||||
|
//MyCustomLayer layer = new MyCustomLayer();
|
||||||
|
//mapView.addLayer(layer,2);
|
||||||
|
|
||||||
|
// 7.5 Impassible roads
|
||||||
|
//ImpassableRoadsLayer impassableRoadsLayer = new ImpassableRoadsLayer(activity);
|
||||||
|
//mapView.addLayer(impassableRoadsLayer, 7.5f);
|
||||||
|
// 7.8 ruler control layer
|
||||||
|
//RulerControlLayer rulerControlLayer = new RulerControlLayer(activity);
|
||||||
|
//mapView.addLayer(rulerControlLayer, 7.8f);
|
||||||
|
// 8. context menu layer
|
||||||
|
// 9. map info layer
|
||||||
|
//MapInfoLayer mapInfoLayer = new MapInfoLayer(activity, routeLayer);
|
||||||
|
//mapView.addLayer(mapInfoLayer, 9);
|
||||||
|
// 11. route info layer
|
||||||
|
//MapControlsLayer mapControlsLayer = new MapControlsLayer(activity);
|
||||||
|
//mapView.addLayer(mapControlsLayer, 11);
|
||||||
|
// 12. quick actions layer
|
||||||
|
//MapQuickActionLayer mapQuickActionLayer = new MapQuickActionLayer(activity, contextMenuLayer);
|
||||||
|
//mapView.addLayer(mapQuickActionLayer, 12);
|
||||||
|
//contextMenuLayer.setMapQuickActionLayer(mapQuickActionLayer);
|
||||||
|
//mapControlsLayer.setMapQuickActionLayer(mapQuickActionLayer);
|
||||||
|
|
||||||
|
// StateChangedListener transparencyListener = new StateChangedListener<Integer>() {
|
||||||
|
// @Override
|
||||||
|
// public void stateChanged(Integer change) {
|
||||||
|
// mapTileLayer.setAlpha(change);
|
||||||
|
// mapVectorLayer.setAlpha(change);
|
||||||
|
// mapView.refreshMap();
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// app.getSettings().MAP_TRANSPARENCY.addListener(transparencyListener);
|
||||||
|
|
||||||
|
|
||||||
|
//OsmandPlugin.createLayers(mapView, activity);
|
||||||
|
//app.getAppCustomization().createLayers(mapView, activity);
|
||||||
|
//app.getAidlApi().registerMapLayers(activity);
|
||||||
|
|
||||||
|
//return OsmandPlugin.createLayers(mapView, app);
|
||||||
|
//app.getAppCustomization().createLayers(mapView, activity);
|
||||||
|
//app.getAidlApi().registerMapLayers(activity);
|
||||||
|
}
|
||||||
|
}
|
646
OsmAnd/src/net/osmand/plus/server/map/MapMarkersMiniLayer.java
Normal file
|
@ -0,0 +1,646 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PathMeasure;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffColorFilter;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.data.Amenity;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.PointDescription;
|
||||||
|
import net.osmand.data.QuadPoint;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.MapMarkersHelper;
|
||||||
|
import net.osmand.plus.MapMarkersHelper.MapMarker;
|
||||||
|
import net.osmand.plus.OsmAndConstants;
|
||||||
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.TargetPointsHelper.TargetPoint;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.Renderable;
|
||||||
|
import net.osmand.plus.views.layers.ContextMenuLayer;
|
||||||
|
import net.osmand.plus.views.layers.ContextMenuLayer.ApplyMovedObjectCallback;
|
||||||
|
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProvider;
|
||||||
|
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProviderSelection;
|
||||||
|
import net.osmand.plus.views.layers.geometry.GeometryWay;
|
||||||
|
import net.osmand.plus.views.mapwidgets.MapMarkersWidgetsFactory;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MapMarkersMiniLayer extends OsmandMapMiniLayer implements IContextMenuProvider,
|
||||||
|
IContextMenuProviderSelection, ContextMenuLayer.IMoveObjectProvider {
|
||||||
|
|
||||||
|
private static final long USE_FINGER_LOCATION_DELAY = 1000;
|
||||||
|
private static final int MAP_REFRESH_MESSAGE = OsmAndConstants.UI_HANDLER_MAP_VIEW + 6;
|
||||||
|
protected static final int DIST_TO_SHOW = 80;
|
||||||
|
private OsmandApplication application;
|
||||||
|
|
||||||
|
private OsmandMapTileMiniView view;
|
||||||
|
|
||||||
|
private MapMarkersWidgetsMiniFactory widgetsFactory;
|
||||||
|
|
||||||
|
private Paint bitmapPaint;
|
||||||
|
private Bitmap markerBitmapBlue;
|
||||||
|
private Bitmap markerBitmapGreen;
|
||||||
|
private Bitmap markerBitmapOrange;
|
||||||
|
private Bitmap markerBitmapRed;
|
||||||
|
private Bitmap markerBitmapYellow;
|
||||||
|
private Bitmap markerBitmapTeal;
|
||||||
|
private Bitmap markerBitmapPurple;
|
||||||
|
|
||||||
|
private Paint bitmapPaintDestBlue;
|
||||||
|
private Paint bitmapPaintDestGreen;
|
||||||
|
private Paint bitmapPaintDestOrange;
|
||||||
|
private Paint bitmapPaintDestRed;
|
||||||
|
private Paint bitmapPaintDestYellow;
|
||||||
|
private Paint bitmapPaintDestTeal;
|
||||||
|
private Paint bitmapPaintDestPurple;
|
||||||
|
private Bitmap arrowLight;
|
||||||
|
private Bitmap arrowToDestination;
|
||||||
|
private Bitmap arrowShadow;
|
||||||
|
private float[] calculations = new float[2];
|
||||||
|
|
||||||
|
private final TextPaint textPaint = new TextPaint();
|
||||||
|
private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine");
|
||||||
|
private final RenderingLineAttributes textAttrs = new RenderingLineAttributes("rulerLineFont");
|
||||||
|
private final RenderingLineAttributes planRouteAttrs = new RenderingLineAttributes("markerPlanRouteline");
|
||||||
|
private TrkSegment route;
|
||||||
|
|
||||||
|
private float textSize;
|
||||||
|
private int verticalOffset;
|
||||||
|
|
||||||
|
private List<Float> tx = new ArrayList<>();
|
||||||
|
private List<Float> ty = new ArrayList<>();
|
||||||
|
private Path linePath = new Path();
|
||||||
|
|
||||||
|
private LatLon fingerLocation;
|
||||||
|
private boolean hasMoved;
|
||||||
|
private boolean moving;
|
||||||
|
private boolean useFingerLocation;
|
||||||
|
private GestureDetector longTapDetector;
|
||||||
|
private Handler handler;
|
||||||
|
|
||||||
|
private ContextMenuLayer contextMenuLayer;
|
||||||
|
|
||||||
|
private boolean inPlanRouteMode;
|
||||||
|
private boolean defaultAppMode = true;
|
||||||
|
|
||||||
|
private List<Amenity> amenities = new ArrayList<>();
|
||||||
|
|
||||||
|
public MapMarkersMiniLayer(OsmandApplication app) {
|
||||||
|
this.application = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapMarkersWidgetsMiniFactory getWidgetsFactory() {
|
||||||
|
return widgetsFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInPlanRouteMode() {
|
||||||
|
return inPlanRouteMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInPlanRouteMode(boolean inPlanRouteMode) {
|
||||||
|
this.inPlanRouteMode = inPlanRouteMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultAppMode(boolean defaultAppMode) {
|
||||||
|
this.defaultAppMode = defaultAppMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initUI() {
|
||||||
|
bitmapPaint = new Paint();
|
||||||
|
bitmapPaint.setAntiAlias(true);
|
||||||
|
bitmapPaint.setFilterBitmap(true);
|
||||||
|
markerBitmapBlue = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_blue);
|
||||||
|
markerBitmapGreen = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_green);
|
||||||
|
markerBitmapOrange = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_orange);
|
||||||
|
markerBitmapRed = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_red);
|
||||||
|
markerBitmapYellow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_yellow);
|
||||||
|
markerBitmapTeal = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_teal);
|
||||||
|
markerBitmapPurple = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_purple);
|
||||||
|
|
||||||
|
arrowLight = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p1_light);
|
||||||
|
arrowToDestination = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p2_color);
|
||||||
|
arrowShadow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p3_shadow);
|
||||||
|
bitmapPaintDestBlue = createPaintDest(R.color.marker_blue);
|
||||||
|
bitmapPaintDestGreen = createPaintDest(R.color.marker_green);
|
||||||
|
bitmapPaintDestOrange = createPaintDest(R.color.marker_orange);
|
||||||
|
bitmapPaintDestRed = createPaintDest(R.color.marker_red);
|
||||||
|
bitmapPaintDestYellow = createPaintDest(R.color.marker_yellow);
|
||||||
|
bitmapPaintDestTeal = createPaintDest(R.color.marker_teal);
|
||||||
|
bitmapPaintDestPurple = createPaintDest(R.color.marker_purple);
|
||||||
|
|
||||||
|
widgetsFactory = new MapMarkersWidgetsMiniFactory(application);
|
||||||
|
|
||||||
|
//contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class);
|
||||||
|
|
||||||
|
textSize = application.getResources().getDimensionPixelSize(R.dimen.guide_line_text_size);
|
||||||
|
verticalOffset = application.getResources().getDimensionPixelSize(R.dimen.guide_line_vertical_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Paint createPaintDest(int colorId) {
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setDither(true);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setFilterBitmap(true);
|
||||||
|
int color = ContextCompat.getColor(application, colorId);
|
||||||
|
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
|
||||||
|
return paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Paint getMarkerDestPaint(int colorIndex) {
|
||||||
|
switch (colorIndex) {
|
||||||
|
case 0:
|
||||||
|
return bitmapPaintDestBlue;
|
||||||
|
case 1:
|
||||||
|
return bitmapPaintDestGreen;
|
||||||
|
case 2:
|
||||||
|
return bitmapPaintDestOrange;
|
||||||
|
case 3:
|
||||||
|
return bitmapPaintDestRed;
|
||||||
|
case 4:
|
||||||
|
return bitmapPaintDestYellow;
|
||||||
|
case 5:
|
||||||
|
return bitmapPaintDestTeal;
|
||||||
|
case 6:
|
||||||
|
return bitmapPaintDestPurple;
|
||||||
|
default:
|
||||||
|
return bitmapPaintDestBlue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap getMapMarkerBitmap(int colorIndex) {
|
||||||
|
switch (colorIndex) {
|
||||||
|
case 0:
|
||||||
|
return markerBitmapBlue;
|
||||||
|
case 1:
|
||||||
|
return markerBitmapGreen;
|
||||||
|
case 2:
|
||||||
|
return markerBitmapOrange;
|
||||||
|
case 3:
|
||||||
|
return markerBitmapRed;
|
||||||
|
case 4:
|
||||||
|
return markerBitmapYellow;
|
||||||
|
case 5:
|
||||||
|
return markerBitmapTeal;
|
||||||
|
case 6:
|
||||||
|
return markerBitmapPurple;
|
||||||
|
default:
|
||||||
|
return markerBitmapBlue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoute(TrkSegment route) {
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileMiniView view) {
|
||||||
|
this.view = view;
|
||||||
|
//handler = new Handler();
|
||||||
|
initUI();
|
||||||
|
// longTapDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||||
|
// @Override
|
||||||
|
// public void onLongPress(MotionEvent e) {
|
||||||
|
// cancelFingerAction();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings nightMode) {
|
||||||
|
OsmandApplication app = application;
|
||||||
|
OsmandSettings settings = app.getSettings();
|
||||||
|
if (!settings.SHOW_MAP_MARKERS.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location myLoc;
|
||||||
|
if (useFingerLocation && fingerLocation != null) {
|
||||||
|
myLoc = new Location("");
|
||||||
|
myLoc.setLatitude(fingerLocation.getLatitude());
|
||||||
|
myLoc.setLongitude(fingerLocation.getLongitude());
|
||||||
|
} else {
|
||||||
|
myLoc = app.getLocationProvider().getLastStaleKnownLocation();
|
||||||
|
}
|
||||||
|
MapMarkersHelper markersHelper = app.getMapMarkersHelper();
|
||||||
|
List<MapMarker> activeMapMarkers = markersHelper.getMapMarkers();
|
||||||
|
int displayedWidgets = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get();
|
||||||
|
|
||||||
|
if (route != null && route.points.size() > 0) {
|
||||||
|
planRouteAttrs.updatePaints(app, nightMode, tileBox);
|
||||||
|
new Renderable.StandardTrack(new ArrayList<>(route.points), 17.2).
|
||||||
|
drawSegment(view.getZoom(), defaultAppMode ? planRouteAttrs.paint : planRouteAttrs.paint2, canvas, tileBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.SHOW_LINES_TO_FIRST_MARKERS.get() && myLoc != null) {
|
||||||
|
textAttrs.paint.setTextSize(textSize);
|
||||||
|
textAttrs.paint2.setTextSize(textSize);
|
||||||
|
|
||||||
|
lineAttrs.updatePaints(app, nightMode, tileBox);
|
||||||
|
textAttrs.updatePaints(app, nightMode, tileBox);
|
||||||
|
textAttrs.paint.setStyle(Paint.Style.FILL);
|
||||||
|
|
||||||
|
textPaint.set(textAttrs.paint);
|
||||||
|
|
||||||
|
boolean drawMarkerName = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get() == 1;
|
||||||
|
|
||||||
|
float locX;
|
||||||
|
float locY;
|
||||||
|
if (app.getMapViewTrackingUtilities().isMapLinkedToLocation()
|
||||||
|
&& !MapViewTrackingUtilities.isSmallSpeedForAnimation(myLoc)
|
||||||
|
&& !app.getMapViewTrackingUtilities().isMovingToMyLocation()) {
|
||||||
|
locX = tileBox.getPixXFromLatLon(tileBox.getLatitude(), tileBox.getLongitude());
|
||||||
|
locY = tileBox.getPixYFromLatLon(tileBox.getLatitude(), tileBox.getLongitude());
|
||||||
|
} else {
|
||||||
|
locX = tileBox.getPixXFromLatLon(myLoc.getLatitude(), myLoc.getLongitude());
|
||||||
|
locY = tileBox.getPixYFromLatLon(myLoc.getLatitude(), myLoc.getLongitude());
|
||||||
|
}
|
||||||
|
int[] colors = MapMarker.getColors(application);
|
||||||
|
for (int i = 0; i < activeMapMarkers.size() && i < displayedWidgets; i++) {
|
||||||
|
MapMarker marker = activeMapMarkers.get(i);
|
||||||
|
float markerX = tileBox.getPixXFromLatLon(marker.getLatitude(), marker.getLongitude());
|
||||||
|
float markerY = tileBox.getPixYFromLatLon(marker.getLatitude(), marker.getLongitude());
|
||||||
|
|
||||||
|
linePath.reset();
|
||||||
|
tx.clear();
|
||||||
|
ty.clear();
|
||||||
|
|
||||||
|
tx.add(locX);
|
||||||
|
ty.add(locY);
|
||||||
|
tx.add(markerX);
|
||||||
|
ty.add(markerY);
|
||||||
|
|
||||||
|
GeometryWay.calculatePath(tileBox, tx, ty, linePath);
|
||||||
|
PathMeasure pm = new PathMeasure(linePath, false);
|
||||||
|
float[] pos = new float[2];
|
||||||
|
pm.getPosTan(pm.getLength() / 2, pos, null);
|
||||||
|
|
||||||
|
float dist = (float) MapUtils.getDistance(myLoc.getLatitude(), myLoc.getLongitude(), marker.getLatitude(), marker.getLongitude());
|
||||||
|
String distSt = OsmAndFormatter.getFormattedDistance(dist, view.getApplication());
|
||||||
|
String text = distSt + (drawMarkerName ? " • " + marker.getName(application) : "");
|
||||||
|
text = TextUtils.ellipsize(text, textPaint, pm.getLength(), TextUtils.TruncateAt.END).toString();
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
textAttrs.paint.getTextBounds(text, 0, text.length(), bounds);
|
||||||
|
float hOffset = pm.getLength() / 2 - bounds.width() / 2;
|
||||||
|
lineAttrs.paint.setColor(colors[marker.colorIndex]);
|
||||||
|
|
||||||
|
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||||
|
canvas.drawPath(linePath, lineAttrs.paint);
|
||||||
|
if (locX >= markerX) {
|
||||||
|
canvas.rotate(180, pos[0], pos[1]);
|
||||||
|
canvas.drawTextOnPath(text, linePath, hOffset, bounds.height() + verticalOffset, textAttrs.paint2);
|
||||||
|
canvas.drawTextOnPath(text, linePath, hOffset, bounds.height() + verticalOffset, textAttrs.paint);
|
||||||
|
canvas.rotate(-180, pos[0], pos[1]);
|
||||||
|
} else {
|
||||||
|
canvas.drawTextOnPath(text, linePath, hOffset, -verticalOffset, textAttrs.paint2);
|
||||||
|
canvas.drawTextOnPath(text, linePath, hOffset, -verticalOffset, textAttrs.paint);
|
||||||
|
}
|
||||||
|
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings nightMode) {
|
||||||
|
//widgetsFactory.updateInfo(useFingerLocation ? fingerLocation : null, tileBox.getZoom());
|
||||||
|
OsmandSettings settings = application.getSettings();
|
||||||
|
|
||||||
|
if (tileBox.getZoom() < 3 || !settings.SHOW_MAP_MARKERS.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int displayedWidgets = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get();
|
||||||
|
|
||||||
|
MapMarkersHelper markersHelper = application.getMapMarkersHelper();
|
||||||
|
|
||||||
|
for (MapMarker marker : markersHelper.getMapMarkers()) {
|
||||||
|
if (isLocationVisible(tileBox, marker) && !overlappedByWaypoint(marker)
|
||||||
|
&& !isInMotion(marker) && !isSynced(marker)) {
|
||||||
|
Bitmap bmp = getMapMarkerBitmap(marker.colorIndex);
|
||||||
|
int marginX = bmp.getWidth() / 6;
|
||||||
|
int marginY = bmp.getHeight();
|
||||||
|
int locationX = tileBox.getPixXFromLonNoRot(marker.getLongitude());
|
||||||
|
int locationY = tileBox.getPixYFromLatNoRot(marker.getLatitude());
|
||||||
|
canvas.rotate(-tileBox.getRotate(), locationX, locationY);
|
||||||
|
canvas.drawBitmap(bmp, locationX - marginX, locationY - marginY, bitmapPaint);
|
||||||
|
canvas.rotate(tileBox.getRotate(), locationX, locationY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.SHOW_ARROWS_TO_FIRST_MARKERS.get()) {
|
||||||
|
LatLon loc = tileBox.getCenterLatLon();
|
||||||
|
int i = 0;
|
||||||
|
for (MapMarker marker : markersHelper.getMapMarkers()) {
|
||||||
|
if (!isLocationVisible(tileBox, marker) && !isInMotion(marker)) {
|
||||||
|
canvas.save();
|
||||||
|
net.osmand.Location.distanceBetween(loc.getLatitude(), loc.getLongitude(),
|
||||||
|
marker.getLatitude(), marker.getLongitude(), calculations);
|
||||||
|
float bearing = calculations[1] - 90;
|
||||||
|
float radiusBearing = DIST_TO_SHOW * tileBox.getDensity();
|
||||||
|
final QuadPoint cp = tileBox.getCenterPixelPoint();
|
||||||
|
canvas.rotate(bearing, cp.x, cp.y);
|
||||||
|
canvas.translate(-24 * tileBox.getDensity() + radiusBearing, -22 * tileBox.getDensity());
|
||||||
|
canvas.drawBitmap(arrowShadow, cp.x, cp.y, bitmapPaint);
|
||||||
|
canvas.drawBitmap(arrowToDestination, cp.x, cp.y, getMarkerDestPaint(marker.colorIndex));
|
||||||
|
canvas.drawBitmap(arrowLight, cp.x, cp.y, bitmapPaint);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
if (i > displayedWidgets - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (contextMenuLayer.getMoveableObject() instanceof MapMarker) {
|
||||||
|
// MapMarker objectInMotion = (MapMarker) contextMenuLayer.getMoveableObject();
|
||||||
|
// PointF pf = contextMenuLayer.getMovableCenterPoint(tileBox);
|
||||||
|
// Bitmap bitmap = getMapMarkerBitmap(objectInMotion.colorIndex);
|
||||||
|
// int marginX = bitmap.getWidth() / 6;
|
||||||
|
// int marginY = bitmap.getHeight();
|
||||||
|
// float locationX = pf.x;
|
||||||
|
// float locationY = pf.y;
|
||||||
|
// canvas.rotate(-tileBox.getRotate(), locationX, locationY);
|
||||||
|
// canvas.drawBitmap(bitmap, locationX - marginX, locationY - marginY, bitmapPaint);
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSynced(@NonNull MapMarker marker) {
|
||||||
|
return marker.wptPt != null || marker.favouritePoint != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInMotion(@NonNull MapMarker marker) {
|
||||||
|
return marker.equals(contextMenuLayer.getMoveableObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLocationVisible(RotatedTileBox tb, MapMarker marker) {
|
||||||
|
//noinspection SimplifiableIfStatement
|
||||||
|
if (marker == null || tb == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return containsLatLon(tb, marker.getLatitude(), marker.getLongitude());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsLatLon(RotatedTileBox tb, double lat, double lon) {
|
||||||
|
double widgetHeight = 0;
|
||||||
|
if (widgetsFactory.isTopBarVisible()) {
|
||||||
|
widgetHeight = widgetsFactory.getTopBarHeight();
|
||||||
|
}
|
||||||
|
double tx = tb.getPixXFromLatLon(lat, lon);
|
||||||
|
double ty = tb.getPixYFromLatLon(lat, lon);
|
||||||
|
return tx >= 0 && tx <= tb.getPixWidth() && ty >= widgetHeight && ty <= tb.getPixHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean overlappedByWaypoint(MapMarker marker) {
|
||||||
|
List<TargetPoint> targetPoints = application.getTargetPointsHelper().getAllPoints();
|
||||||
|
for (TargetPoint t : targetPoints) {
|
||||||
|
if (t.point.equals(marker.point)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event, RotatedTileBox tileBox) {
|
||||||
|
if (!longTapDetector.onTouchEvent(event)) {
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
float x = event.getX();
|
||||||
|
float y = event.getY();
|
||||||
|
fingerLocation = tileBox.getLatLonFromPixel(x, y);
|
||||||
|
hasMoved = false;
|
||||||
|
moving = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (!hasMoved) {
|
||||||
|
if (!handler.hasMessages(MAP_REFRESH_MESSAGE)) {
|
||||||
|
Message msg = Message.obtain(handler, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
handler.removeMessages(MAP_REFRESH_MESSAGE);
|
||||||
|
if (moving) {
|
||||||
|
if (!useFingerLocation) {
|
||||||
|
useFingerLocation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
msg.what = MAP_REFRESH_MESSAGE;
|
||||||
|
handler.sendMessageDelayed(msg, USE_FINGER_LOCATION_DELAY);
|
||||||
|
}
|
||||||
|
hasMoved = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
cancelFingerAction();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(event, tileBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelFingerAction() {
|
||||||
|
handler.removeMessages(MAP_REFRESH_MESSAGE);
|
||||||
|
useFingerLocation = false;
|
||||||
|
moving = false;
|
||||||
|
fingerLocation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableSingleTap() {
|
||||||
|
return inPlanRouteMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableLongPressOnMap() {
|
||||||
|
return inPlanRouteMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectClickable(Object o) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean runExclusiveAction(Object o, boolean unknownLocation) {
|
||||||
|
OsmandSettings settings = application.getSettings();
|
||||||
|
if (unknownLocation
|
||||||
|
|| o == null
|
||||||
|
|| !(o instanceof MapMarker)
|
||||||
|
|| !settings.SELECT_MARKER_ON_SINGLE_TAP.get()
|
||||||
|
|| !settings.SHOW_MAP_MARKERS.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final MapMarkersHelper helper = application.getMapMarkersHelper();
|
||||||
|
final MapMarker old = helper.getMapMarkers().get(0);
|
||||||
|
helper.moveMarkerToTop((MapMarker) o);
|
||||||
|
String title = application.getString(R.string.marker_activated, helper.getMapMarkers().get(0).getName(application));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> o, boolean unknownLocation) {
|
||||||
|
if (tileBox.getZoom() < 3 || !application.getSettings().SHOW_MAP_MARKERS.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
amenities.clear();
|
||||||
|
OsmandApplication app = application;
|
||||||
|
int r = getDefaultRadiusPoi(tileBox);
|
||||||
|
boolean selectMarkerOnSingleTap = app.getSettings().SELECT_MARKER_ON_SINGLE_TAP.get();
|
||||||
|
|
||||||
|
for (MapMarker marker : app.getMapMarkersHelper().getMapMarkers()) {
|
||||||
|
if ((!unknownLocation && selectMarkerOnSingleTap) || !isSynced(marker)) {
|
||||||
|
LatLon latLon = marker.point;
|
||||||
|
if (latLon != null) {
|
||||||
|
int x = (int) tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude());
|
||||||
|
int y = (int) tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude());
|
||||||
|
|
||||||
|
if (calculateBelongs((int) point.x, (int) point.y, x, y, r)) {
|
||||||
|
if (!unknownLocation && selectMarkerOnSingleTap) {
|
||||||
|
o.add(marker);
|
||||||
|
} else {
|
||||||
|
if (isMarkerOnFavorite(marker) && app.getSettings().SHOW_FAVORITES.get()
|
||||||
|
|| isMarkerOnWaypoint(marker) && app.getSettings().SHOW_WPT.get()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Amenity mapObj = getMapObjectByMarker(marker);
|
||||||
|
if (mapObj != null) {
|
||||||
|
amenities.add(mapObj);
|
||||||
|
o.add(mapObj);
|
||||||
|
} else {
|
||||||
|
o.add(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMarkerOnWaypoint(@NonNull MapMarker marker) {
|
||||||
|
return marker.point != null && application.getSelectedGpxHelper().getVisibleWayPointByLatLon(marker.point) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMarkerOnFavorite(@NonNull MapMarker marker) {
|
||||||
|
return marker.point != null && application.getFavorites().getVisibleFavByLatLon(marker.point) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Amenity getMapObjectByMarker(@NonNull MapMarker marker) {
|
||||||
|
if (marker.mapObjectName != null && marker.point != null) {
|
||||||
|
String mapObjName = marker.mapObjectName.split("_")[0];
|
||||||
|
return findAmenity(application, -1, Collections.singletonList(mapObjName), marker.point, 15);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) {
|
||||||
|
return Math.abs(objx - ex) <= radius * 1.5 && (ey - objy) <= radius * 1.5 && (objy - ey) <= 2.5 * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LatLon getObjectLocation(Object o) {
|
||||||
|
if (o instanceof MapMarker) {
|
||||||
|
return ((MapMarker) o).point;
|
||||||
|
} else if (o instanceof Amenity && amenities.contains(o)) {
|
||||||
|
return ((Amenity) o).getLocation();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PointDescription getObjectName(Object o) {
|
||||||
|
// if (o instanceof MapMarker) {
|
||||||
|
// return ((MapMarker) o).getPointDescription(view.getContext());
|
||||||
|
// }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder(Object o) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSelectedObject(Object o) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearSelectedObject() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectMovable(Object o) {
|
||||||
|
return o instanceof MapMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyNewObjectPosition(@NonNull Object o, @NonNull LatLon position,
|
||||||
|
@Nullable ApplyMovedObjectCallback callback) {
|
||||||
|
boolean result = false;
|
||||||
|
MapMarker newObject = null;
|
||||||
|
if (o instanceof MapMarker) {
|
||||||
|
MapMarkersHelper markersHelper = application.getMapMarkersHelper();
|
||||||
|
MapMarker marker = (MapMarker) o;
|
||||||
|
|
||||||
|
PointDescription originalDescription = marker.getOriginalPointDescription();
|
||||||
|
if (originalDescription.isLocation()) {
|
||||||
|
originalDescription.setName(PointDescription.getSearchAddressStr(application));
|
||||||
|
}
|
||||||
|
markersHelper.moveMapMarker(marker, position);
|
||||||
|
int index = markersHelper.getMapMarkers().indexOf(marker);
|
||||||
|
if (index != -1) {
|
||||||
|
newObject = markersHelper.getMapMarkers().get(index);
|
||||||
|
}
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onApplyMovedObject(result, newObject == null ? o : newObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.PointDescription;
|
||||||
|
import net.osmand.plus.*;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
|
import net.osmand.plus.mapmarkers.MapMarkersDialogFragment;
|
||||||
|
import net.osmand.plus.views.AnimateDraggingMapThread;
|
||||||
|
import net.osmand.plus.views.DirectionDrawable;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
public class MapMarkersWidgetsMiniFactory {
|
||||||
|
|
||||||
|
public static final int MIN_DIST_OK_VISIBLE = 40; // meters
|
||||||
|
public static final int MIN_DIST_2ND_ROW_SHOW = 150; // meters
|
||||||
|
private static OsmandApplication app;
|
||||||
|
|
||||||
|
private MapMarkersHelper helper;
|
||||||
|
private int screenOrientation;
|
||||||
|
private boolean portraitMode;
|
||||||
|
|
||||||
|
|
||||||
|
private LatLon loc;
|
||||||
|
|
||||||
|
private boolean cachedTopBarVisibility;
|
||||||
|
|
||||||
|
public MapMarkersWidgetsMiniFactory(final OsmandApplication application) {
|
||||||
|
this.app = application;
|
||||||
|
helper = app.getMapMarkersHelper();
|
||||||
|
screenOrientation = app.getUIUtilities().getScreenOrientation();
|
||||||
|
//portraitMode = AndroidUiHelper.isOrientationPortrait(map);
|
||||||
|
|
||||||
|
updateVisibility(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeMarker(int index) {
|
||||||
|
if (helper.getMapMarkers().size() > index) {
|
||||||
|
helper.moveMapMarkerToHistory(helper.getMapMarkers().get(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showMarkerOnMap(int index) {
|
||||||
|
// if (helper.getMapMarkers().size() > index) {
|
||||||
|
// MapMarkersHelper.MapMarker marker = helper.getMapMarkers().get(index);
|
||||||
|
// AnimateDraggingMapThread thread = app.getMapView().getAnimatedDraggingThread();
|
||||||
|
// LatLon pointToNavigate = marker.point;
|
||||||
|
// if (pointToNavigate != null) {
|
||||||
|
// int fZoom = map.getMapView().getZoom() < 15 ? 15 : map.getMapView().getZoom();
|
||||||
|
// thread.startMoving(pointToNavigate.getLatitude(), pointToNavigate.getLongitude(), fZoom, true);
|
||||||
|
// }
|
||||||
|
// //MapMarkerDialogHelper.showMarkerOnMap(map, marker);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean updateVisibility(boolean visible) {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTopBarHeight() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTopBarVisible() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateInfo(LatLon customLocation, int zoom) {
|
||||||
|
if (customLocation != null) {
|
||||||
|
loc = customLocation;
|
||||||
|
} else {
|
||||||
|
Location l = app.getLocationProvider().getLastStaleKnownLocation();
|
||||||
|
if (l != null) {
|
||||||
|
loc = new LatLon(l.getLatitude(), l.getLongitude());
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MapMarkersHelper.MapMarker> markers = helper.getMapMarkers();
|
||||||
|
if (zoom < 3 || markers.size() == 0
|
||||||
|
|| !app.getSettings().MARKERS_DISTANCE_INDICATION_ENABLED.get()
|
||||||
|
|| !app.getSettings().MAP_MARKERS_MODE.get().isToolbar()
|
||||||
|
|| app.getRoutingHelper().isFollowingMode()
|
||||||
|
|| app.getRoutingHelper().isRoutePlanningMode()) {
|
||||||
|
updateVisibility(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float heading = app.getMapViewTrackingUtilities().getHeading();
|
||||||
|
MapMarkersHelper.MapMarker marker = markers.get(0);
|
||||||
|
|
||||||
|
if (markers.size() > 1 && app.getSettings().DISPLAYED_MARKERS_WIDGETS_COUNT.get() == 2) {
|
||||||
|
marker = markers.get(1);
|
||||||
|
if (loc != null && customLocation == null) {
|
||||||
|
for (int i = 1; i < markers.size(); i++) {
|
||||||
|
MapMarkersHelper.MapMarker m = markers.get(i);
|
||||||
|
m.dist = (int) (MapUtils.getDistance(m.getLatitude(), m.getLongitude(),
|
||||||
|
loc.getLatitude(), loc.getLongitude()));
|
||||||
|
if (m.dist < MIN_DIST_2ND_ROW_SHOW && marker.dist > m.dist) {
|
||||||
|
marker = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVisibility(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUI(LatLon loc, Float heading, MapMarkersHelper.MapMarker marker, ImageView arrowImg,
|
||||||
|
TextView distText, ImageButton okButton, TextView addressText,
|
||||||
|
boolean firstLine, boolean customLocation) {
|
||||||
|
float[] mes = new float[2];
|
||||||
|
if (loc != null && marker.point != null) {
|
||||||
|
Location.distanceBetween(marker.getLatitude(), marker.getLongitude(), loc.getLatitude(), loc.getLongitude(), mes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customLocation) {
|
||||||
|
heading = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean newImage = false;
|
||||||
|
DirectionDrawable dd;
|
||||||
|
if (!(arrowImg.getDrawable() instanceof DirectionDrawable)) {
|
||||||
|
newImage = true;
|
||||||
|
dd = new DirectionDrawable(app, arrowImg.getWidth(), arrowImg.getHeight());
|
||||||
|
} else {
|
||||||
|
dd = (DirectionDrawable) arrowImg.getDrawable();
|
||||||
|
}
|
||||||
|
dd.setImage(R.drawable.ic_arrow_marker_diretion, MapMarkersHelper.MapMarker.getColorId(marker.colorIndex));
|
||||||
|
if (heading != null && loc != null) {
|
||||||
|
dd.setAngle(mes[1] - heading + 180 + screenOrientation);
|
||||||
|
}
|
||||||
|
if (newImage) {
|
||||||
|
arrowImg.setImageDrawable(dd);
|
||||||
|
}
|
||||||
|
arrowImg.invalidate();
|
||||||
|
|
||||||
|
int dist = (int) mes[0];
|
||||||
|
String txt;
|
||||||
|
if (loc != null) {
|
||||||
|
txt = OsmAndFormatter.getFormattedDistance(dist, app);
|
||||||
|
} else {
|
||||||
|
txt = "—";
|
||||||
|
}
|
||||||
|
if (txt != null) {
|
||||||
|
distText.setText(txt);
|
||||||
|
}
|
||||||
|
AndroidUiHelper.updateVisibility(okButton, !customLocation && loc != null && dist < MIN_DIST_OK_VISIBLE);
|
||||||
|
|
||||||
|
String descr;
|
||||||
|
PointDescription pd = marker.getPointDescription(app);
|
||||||
|
if (Algorithms.isEmpty(pd.getName())) {
|
||||||
|
descr = pd.getTypeName();
|
||||||
|
} else {
|
||||||
|
descr = pd.getName();
|
||||||
|
}
|
||||||
|
if (!firstLine && !isLandscapeLayout()) {
|
||||||
|
descr = " • " + descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
addressText.setText(descr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextInfoWidget createMapMarkerControl(final MapActivity map, final boolean firstMarker) {
|
||||||
|
return new net.osmand.plus.views.mapwidgets.MapMarkersWidgetsFactory.DistanceToMapMarkerControl(map, firstMarker) {
|
||||||
|
@Override
|
||||||
|
public LatLon getLatLon() {
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void click(OsmandMapTileView view) {
|
||||||
|
showMarkerOnMap(firstMarker ? 0 : 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLandscapeLayout() {
|
||||||
|
return !portraitMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class DistanceToMapMarkerControl extends TextInfoWidget {
|
||||||
|
|
||||||
|
private boolean firstMarker;
|
||||||
|
private final OsmandMapTileView view;
|
||||||
|
private MapActivity map;
|
||||||
|
private MapMarkersHelper helper;
|
||||||
|
private float[] calculations = new float[1];
|
||||||
|
private int cachedMeters;
|
||||||
|
private int cachedMarkerColorIndex = -1;
|
||||||
|
private Boolean cachedNightMode = null;
|
||||||
|
|
||||||
|
public DistanceToMapMarkerControl(MapActivity map, boolean firstMarker) {
|
||||||
|
super(map);
|
||||||
|
this.map = map;
|
||||||
|
this.firstMarker = firstMarker;
|
||||||
|
this.view = map.getMapView();
|
||||||
|
helper = app.getMapMarkersHelper();
|
||||||
|
setText(null, null);
|
||||||
|
setOnClickListener(new View.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
click(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void click(OsmandMapTileView view);
|
||||||
|
|
||||||
|
public abstract LatLon getLatLon();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateInfo(OsmandMapLayer.DrawSettings drawSettings) {
|
||||||
|
MapMarkersHelper.MapMarker marker = getMarker();
|
||||||
|
if (marker == null
|
||||||
|
|| app.getRoutingHelper().isRoutePlanningMode()
|
||||||
|
|| app.getRoutingHelper().isFollowingMode()) {
|
||||||
|
cachedMeters = 0;
|
||||||
|
setText(null, null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean res = false;
|
||||||
|
int d = getDistance();
|
||||||
|
if (isUpdateNeeded() || cachedMeters != d) {
|
||||||
|
cachedMeters = d;
|
||||||
|
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, app);
|
||||||
|
int ls = ds.lastIndexOf(' ');
|
||||||
|
if (ls == -1) {
|
||||||
|
setText(ds, null);
|
||||||
|
} else {
|
||||||
|
setText(ds.substring(0, ls), ds.substring(ls + 1));
|
||||||
|
}
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (marker.colorIndex != -1) {
|
||||||
|
if (marker.colorIndex != cachedMarkerColorIndex
|
||||||
|
|| cachedNightMode == null || cachedNightMode != isNight()) {
|
||||||
|
setImageDrawable(app.getUIUtilities()
|
||||||
|
.getLayeredIcon(isNight() ? R.drawable.widget_marker_night : R.drawable.widget_marker_day,
|
||||||
|
R.drawable.widget_marker_triangle, 0,
|
||||||
|
MapMarkersHelper.MapMarker.getColorId(marker.colorIndex)));
|
||||||
|
cachedMarkerColorIndex = marker.colorIndex;
|
||||||
|
cachedNightMode = isNight();
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMetricSystemDepended() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LatLon getPointToNavigate() {
|
||||||
|
MapMarkersHelper.MapMarker marker = getMarker();
|
||||||
|
if (marker != null) {
|
||||||
|
return marker.point;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapMarkersHelper.MapMarker getMarker() {
|
||||||
|
List<MapMarkersHelper.MapMarker> markers = helper.getMapMarkers();
|
||||||
|
if (firstMarker) {
|
||||||
|
if (markers.size() > 0) {
|
||||||
|
return markers.get(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (markers.size() > 1) {
|
||||||
|
return markers.get(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDistance() {
|
||||||
|
int d = 0;
|
||||||
|
LatLon l = getPointToNavigate();
|
||||||
|
if (l != null) {
|
||||||
|
LatLon loc = getLatLon();
|
||||||
|
if (loc == null) {
|
||||||
|
Location.distanceBetween(view.getLatitude(), view.getLongitude(), l.getLatitude(), l.getLongitude(), calculations);
|
||||||
|
} else {
|
||||||
|
Location.distanceBetween(loc.getLatitude(), loc.getLongitude(), l.getLatitude(), l.getLongitude(), calculations);
|
||||||
|
}
|
||||||
|
d = (int) calculations[0];
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
223
OsmAnd/src/net/osmand/plus/server/map/MapTextMiniLayer.java
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import gnu.trove.set.hash.TIntHashSet;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Align;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import gnu.trove.set.hash.TIntHashSet;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
|
||||||
|
public class MapTextMiniLayer extends OsmandMapLayer {
|
||||||
|
|
||||||
|
private static final int TEXT_WRAP = 15;
|
||||||
|
private static final int TEXT_LINES = 3;
|
||||||
|
private static final int TEXT_SIZE = 13;
|
||||||
|
|
||||||
|
private Map<OsmandMapLayer, Collection<?>> textObjects = new LinkedHashMap<>();
|
||||||
|
private Paint paintTextIcon;
|
||||||
|
private OsmandMapTileView view;
|
||||||
|
|
||||||
|
public interface MapTextProvider<T> {
|
||||||
|
|
||||||
|
LatLon getTextLocation(T o);
|
||||||
|
|
||||||
|
int getTextShift(T o, RotatedTileBox rb);
|
||||||
|
|
||||||
|
String getText(T o);
|
||||||
|
|
||||||
|
boolean isTextVisible();
|
||||||
|
|
||||||
|
boolean isFakeBoldText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putData(OsmandMapLayer ml, Collection<?> objects) {
|
||||||
|
if (objects == null || objects.isEmpty()) {
|
||||||
|
textObjects.remove(ml);
|
||||||
|
} else {
|
||||||
|
if (ml instanceof net.osmand.plus.views.layers.MapTextLayer.MapTextProvider) {
|
||||||
|
textObjects.put(ml, objects);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
TIntHashSet set = new TIntHashSet();
|
||||||
|
for (OsmandMapLayer l : textObjects.keySet()) {
|
||||||
|
net.osmand.plus.views.layers.MapTextLayer.MapTextProvider provider = (net.osmand.plus.views.layers.MapTextLayer.MapTextProvider) l;
|
||||||
|
if (!view.isLayerVisible(l) || !provider.isTextVisible()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTextSize();
|
||||||
|
paintTextIcon.setFakeBoldText(provider.isFakeBoldText());
|
||||||
|
for (Object o : textObjects.get(l)) {
|
||||||
|
LatLon loc = provider.getTextLocation(o);
|
||||||
|
String name = provider.getText(o);
|
||||||
|
if (loc == null || TextUtils.isEmpty(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = (int) tileBox.getPixXFromLatLon(loc.getLatitude(), loc.getLongitude());
|
||||||
|
int y = (int) tileBox.getPixYFromLatLon(loc.getLatitude(), loc.getLongitude());
|
||||||
|
int tx = tileBox.getPixXFromLonNoRot(loc.getLongitude());
|
||||||
|
int ty = tileBox.getPixYFromLatNoRot(loc.getLatitude());
|
||||||
|
|
||||||
|
int lines = 0;
|
||||||
|
while (lines < TEXT_LINES) {
|
||||||
|
if (set.contains(division(tx, ty, 0, lines)) || set.contains(division(tx, ty, -1, lines))
|
||||||
|
|| set.contains(division(tx, ty, +1, lines))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lines++;
|
||||||
|
}
|
||||||
|
if (lines != 0) {
|
||||||
|
int r = provider.getTextShift(o, tileBox);
|
||||||
|
drawWrappedText(canvas, name, paintTextIcon.getTextSize(), x,
|
||||||
|
y + r + 2 + paintTextIcon.getTextSize() / 2, lines);
|
||||||
|
while (lines > 0) {
|
||||||
|
set.add(division(tx, ty, 1, lines - 1));
|
||||||
|
set.add(division(tx, ty, -1, lines - 1));
|
||||||
|
set.add(division(tx, ty, 0, lines - 1));
|
||||||
|
lines--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int division(int x, int y, int sx, int sy) {
|
||||||
|
// make numbers positive
|
||||||
|
return ((((x + 10000) >> 4) + sx) << 16) | (((y + 10000) >> 4) + sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawWrappedText(Canvas cv, String text, float textSize, float x, float y, int lines) {
|
||||||
|
boolean nightMode = view.getApplication().getDaynightHelper().isNightMode();
|
||||||
|
if (text.length() > TEXT_WRAP) {
|
||||||
|
int start = 0;
|
||||||
|
int end = text.length();
|
||||||
|
int lastSpace = -1;
|
||||||
|
int line = 0;
|
||||||
|
int pos = 0;
|
||||||
|
int limit = 0;
|
||||||
|
while (pos < end && (line < lines)) {
|
||||||
|
lastSpace = -1;
|
||||||
|
limit += TEXT_WRAP;
|
||||||
|
while (pos < limit && pos < end) {
|
||||||
|
if (Character.isWhitespace(text.charAt(pos))) {
|
||||||
|
lastSpace = pos;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
if (lastSpace == -1 || (pos == end)) {
|
||||||
|
drawShadowText(cv, text.substring(start, pos), x, y + line * (textSize + 2), nightMode);
|
||||||
|
start = pos;
|
||||||
|
} else {
|
||||||
|
String subtext = text.substring(start, lastSpace);
|
||||||
|
if (line + 1 == lines) {
|
||||||
|
subtext += "..";
|
||||||
|
}
|
||||||
|
drawShadowText(cv, subtext, x, y + line * (textSize + 2), nightMode);
|
||||||
|
|
||||||
|
start = lastSpace + 1;
|
||||||
|
limit += (start - pos) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drawShadowText(cv, text, x, y, nightMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawShadowText(Canvas cv, String text, float centerX, float centerY, boolean nightMode) {
|
||||||
|
Resources r = view.getApplication().getResources();
|
||||||
|
paintTextIcon.setStyle(Paint.Style.STROKE);
|
||||||
|
paintTextIcon.setColor(nightMode
|
||||||
|
? r.getColor(R.color.widgettext_shadow_night)
|
||||||
|
: r.getColor(R.color.widgettext_shadow_day));
|
||||||
|
paintTextIcon.setStrokeWidth(2);
|
||||||
|
cv.drawText(text, centerX, centerY, paintTextIcon);
|
||||||
|
// reset
|
||||||
|
paintTextIcon.setStrokeWidth(2);
|
||||||
|
paintTextIcon.setStyle(Paint.Style.FILL);
|
||||||
|
paintTextIcon.setColor(nightMode
|
||||||
|
? r.getColor(R.color.widgettext_night)
|
||||||
|
: r.getColor(R.color.widgettext_day));
|
||||||
|
cv.drawText(text, centerX, centerY, paintTextIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileView v) {
|
||||||
|
this.view = v;
|
||||||
|
paintTextIcon = new Paint();
|
||||||
|
updateTextSize();
|
||||||
|
paintTextIcon.setTextAlign(Paint.Align.CENTER);
|
||||||
|
paintTextIcon.setAntiAlias(true);
|
||||||
|
Map<OsmandMapLayer, Collection<?>> textObjectsLoc = new TreeMap<>(new Comparator<OsmandMapLayer>() {
|
||||||
|
@Override
|
||||||
|
public int compare(OsmandMapLayer lhs, OsmandMapLayer rhs) {
|
||||||
|
if (view != null) {
|
||||||
|
float z1 = view.getZorder(lhs);
|
||||||
|
float z2 = view.getZorder(rhs);
|
||||||
|
return Float.compare(z1, z2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
textObjectsLoc.putAll(this.textObjects);
|
||||||
|
this.textObjects = textObjectsLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTextSize() {
|
||||||
|
float scale = view.getApplication().getSettings().TEXT_SCALE.get();
|
||||||
|
float textSize = scale * TEXT_SIZE * view.getDensity();
|
||||||
|
if (paintTextIcon.getTextSize() != textSize) {
|
||||||
|
paintTextIcon.setTextSize(textSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
276
OsmAnd/src/net/osmand/plus/server/map/MapTileMiniLayer.java
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.map.ITileSource;
|
||||||
|
import net.osmand.map.TileSourceManager;
|
||||||
|
import net.osmand.map.TileSourceManager.TileSourceTemplate;
|
||||||
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.mapillary.MapillaryPlugin;
|
||||||
|
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
|
||||||
|
import net.osmand.plus.resources.ResourceManager;
|
||||||
|
import net.osmand.plus.views.BaseMapLayer;
|
||||||
|
import net.osmand.plus.views.MapTileAdapter;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.YandexTrafficAdapter;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
public class MapTileMiniLayer extends OsmandMapMiniLayer {
|
||||||
|
|
||||||
|
protected static final int emptyTileDivisor = 16;
|
||||||
|
public static final int OVERZOOM_IN = 2;
|
||||||
|
|
||||||
|
protected final boolean mainMap;
|
||||||
|
protected ITileSource map = null;
|
||||||
|
|
||||||
|
protected Paint paintBitmap;
|
||||||
|
protected RectF bitmapToDraw = new RectF();
|
||||||
|
protected Rect bitmapToZoom = new Rect();
|
||||||
|
|
||||||
|
|
||||||
|
protected ResourceManager resourceManager;
|
||||||
|
protected OsmandSettings settings;
|
||||||
|
private boolean visible = true;
|
||||||
|
private boolean useSampling;
|
||||||
|
|
||||||
|
|
||||||
|
public MapTileMiniLayer(boolean mainMap) {
|
||||||
|
this.mainMap = mainMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileMiniView view) {
|
||||||
|
settings = view.getSettings();
|
||||||
|
resourceManager = view.getApplication().getResourceManager();
|
||||||
|
|
||||||
|
useSampling = Build.VERSION.SDK_INT < 28;
|
||||||
|
|
||||||
|
paintBitmap = new Paint();
|
||||||
|
paintBitmap.setFilterBitmap(true);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlpha(int alpha) {
|
||||||
|
if (paintBitmap != null) {
|
||||||
|
paintBitmap.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapTileAdapter(MapTileAdapter mapTileAdapter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapForMapTileAdapter(ITileSource map, MapTileAdapter mapTileAdapter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(ITileSource map) {
|
||||||
|
MapTileAdapter target = null;
|
||||||
|
if (map instanceof TileSourceTemplate) {
|
||||||
|
if (TileSourceManager.RULE_YANDEX_TRAFFIC.equals(((TileSourceTemplate) map).getRule())) {
|
||||||
|
map = null;
|
||||||
|
target = new YandexTrafficAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
this.map = map;
|
||||||
|
setMapTileAdapter(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapTileAdapter getMapTileAdapter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WrongCall")
|
||||||
|
@Override
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox,
|
||||||
|
DrawSettings drawSettings) {
|
||||||
|
|
||||||
|
drawTileMap(canvas, tileBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawTileMap(Canvas canvas, RotatedTileBox tileBox) {
|
||||||
|
ITileSource map = this.map;
|
||||||
|
if (map == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResourceManager mgr = resourceManager;
|
||||||
|
int nzoom = tileBox.getZoom();
|
||||||
|
final QuadRect tilesRect = tileBox.getTileBounds();
|
||||||
|
|
||||||
|
// recalculate for ellipsoid coordinates
|
||||||
|
float ellipticTileCorrection = 0;
|
||||||
|
if (map.isEllipticYTile()) {
|
||||||
|
ellipticTileCorrection = (float) (MapUtils.getTileEllipsoidNumberY(nzoom, tileBox.getLatitude()) - tileBox.getCenterTileY());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int left = (int) Math.floor(tilesRect.left);
|
||||||
|
int top = (int) Math.floor(tilesRect.top + ellipticTileCorrection);
|
||||||
|
int width = (int) Math.ceil(tilesRect.right - left);
|
||||||
|
int height = (int) Math.ceil(tilesRect.bottom + ellipticTileCorrection - top);
|
||||||
|
|
||||||
|
boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null)
|
||||||
|
&& settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet();
|
||||||
|
int maxLevel = map.getMaximumZoomSupported();
|
||||||
|
int tileSize = map.getTileSize();
|
||||||
|
boolean oneTileShown = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
int leftPlusI = left + i;
|
||||||
|
int topPlusJ = top + j;
|
||||||
|
|
||||||
|
int x1 = tileBox.getPixXFromTileXNoRot(leftPlusI);
|
||||||
|
int x2 = tileBox.getPixXFromTileXNoRot(leftPlusI + 1);
|
||||||
|
|
||||||
|
int y1 = tileBox.getPixYFromTileYNoRot(topPlusJ - ellipticTileCorrection);
|
||||||
|
int y2 = tileBox.getPixYFromTileYNoRot(topPlusJ + 1 - ellipticTileCorrection);
|
||||||
|
bitmapToDraw.set(x1, y1, x2 , y2);
|
||||||
|
|
||||||
|
final int tileX = leftPlusI;
|
||||||
|
final int tileY = topPlusJ;
|
||||||
|
Bitmap bmp = null;
|
||||||
|
String ordImgTile = mgr.calculateTileId(map, tileX, tileY, nzoom);
|
||||||
|
// asking tile image async
|
||||||
|
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, tileX, tileY, nzoom);
|
||||||
|
boolean originalWillBeLoaded = useInternet && nzoom <= maxLevel;
|
||||||
|
if (imgExist || originalWillBeLoaded) {
|
||||||
|
bmp = mgr.getBitmapTilesCache().getTileForMapAsync(ordImgTile, map, tileX, tileY, nzoom, useInternet);
|
||||||
|
}
|
||||||
|
if (bmp == null) {
|
||||||
|
int div = 1;
|
||||||
|
boolean readFromCache = originalWillBeLoaded || imgExist;
|
||||||
|
boolean loadIfExists = !readFromCache;
|
||||||
|
// asking if there is small version of the map (in cache)
|
||||||
|
int allowedScale = Math.min(OVERZOOM_IN + Math.max(0, nzoom - map.getMaximumZoomSupported()), 8);
|
||||||
|
int kzoom = 1;
|
||||||
|
for (; kzoom <= allowedScale; kzoom++) {
|
||||||
|
div *= 2;
|
||||||
|
String imgTileId = mgr.calculateTileId(map, tileX / div, tileY / div, nzoom - kzoom);
|
||||||
|
if (readFromCache) {
|
||||||
|
bmp = mgr.getBitmapTilesCache().get(imgTileId);
|
||||||
|
if (bmp != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (loadIfExists) {
|
||||||
|
if (mgr.tileExistOnFileSystem(imgTileId, map, tileX / div, tileY / div, nzoom - kzoom)
|
||||||
|
|| (useInternet && nzoom - kzoom <= maxLevel)) {
|
||||||
|
bmp = mgr.getBitmapTilesCache().getTileForMapAsync(imgTileId, map, tileX / div, tileY / div, nzoom
|
||||||
|
- kzoom, useInternet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (bmp != null) {
|
||||||
|
if (bmp.getWidth() != tileSize && bmp.getWidth() > 0) {
|
||||||
|
tileSize = bmp.getWidth();
|
||||||
|
}
|
||||||
|
int xZoom = (tileX % div) * tileSize / div;
|
||||||
|
int yZoom = (tileY % div) * tileSize / div;
|
||||||
|
// nice scale
|
||||||
|
boolean useSampling = this.useSampling && kzoom > 3;
|
||||||
|
bitmapToZoom.set(Math.max(xZoom, 0), Math.max(yZoom, 0),
|
||||||
|
Math.min(xZoom + tileSize / div, tileSize),
|
||||||
|
Math.min(yZoom + tileSize / div, tileSize));
|
||||||
|
if (!useSampling) {
|
||||||
|
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
|
||||||
|
} else {
|
||||||
|
int margin = 1;
|
||||||
|
int scaledSize = tileSize / div;
|
||||||
|
float innerMargin = 0.5f;
|
||||||
|
RectF src = new RectF(0, 0, scaledSize, scaledSize);
|
||||||
|
if (bitmapToZoom.left >= margin) {
|
||||||
|
bitmapToZoom.left -= margin;
|
||||||
|
src.left = innerMargin;
|
||||||
|
src.right += margin;
|
||||||
|
}
|
||||||
|
if (bitmapToZoom.top >= margin) {
|
||||||
|
bitmapToZoom.top -= margin;
|
||||||
|
src.top = innerMargin;
|
||||||
|
src.bottom += margin;
|
||||||
|
}
|
||||||
|
if (bitmapToZoom.right + margin <= tileSize) {
|
||||||
|
bitmapToZoom.right += margin;
|
||||||
|
src.right += margin - innerMargin;
|
||||||
|
}
|
||||||
|
if (bitmapToZoom.bottom + margin <= tileSize) {
|
||||||
|
bitmapToZoom.bottom += margin;
|
||||||
|
src.bottom += margin - innerMargin;
|
||||||
|
}
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
RectF dest = new RectF(0, 0, tileSize, tileSize);
|
||||||
|
m.setRectToRect(src, dest, Matrix.ScaleToFit.FILL);
|
||||||
|
Bitmap sampled = Bitmap.createBitmap(bmp,
|
||||||
|
bitmapToZoom.left, bitmapToZoom.top,
|
||||||
|
bitmapToZoom.width(), bitmapToZoom.height(), m, true);
|
||||||
|
bitmapToZoom.set(0, 0, tileSize, tileSize);
|
||||||
|
// very expensive that's why put in the cache
|
||||||
|
mgr.getBitmapTilesCache().put(ordImgTile, sampled);
|
||||||
|
canvas.drawBitmap(sampled, bitmapToZoom, bitmapToDraw, paintBitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bitmapToZoom.set(0, 0, tileSize, tileSize);
|
||||||
|
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
|
||||||
|
}
|
||||||
|
if (bmp != null) {
|
||||||
|
oneTileShown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getMaximumShownMapZoom() {
|
||||||
|
return map == null ? 20 : map.getMaximumZoomSupported() + OVERZOOM_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinimumShownMapZoom() {
|
||||||
|
return map == null ? 1 : map.getMinimumZoomSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
setMapTileAdapter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITileSource getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
233
OsmAnd/src/net/osmand/plus/server/map/MapVectorMiniLayer.java
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.graphics.*;
|
||||||
|
import net.osmand.core.android.MapRendererView;
|
||||||
|
import net.osmand.core.jni.MapLayerConfiguration;
|
||||||
|
import net.osmand.core.jni.PointI;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.QuadPointDouble;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.render.MapRenderRepositories;
|
||||||
|
import net.osmand.plus.resources.ResourceManager;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.views.*;
|
||||||
|
import net.osmand.plus.views.corenative.NativeCoreContext;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import net.osmand.core.android.MapRendererView;
|
||||||
|
import net.osmand.core.android.TileSourceProxyProvider;
|
||||||
|
import net.osmand.core.jni.MapLayerConfiguration;
|
||||||
|
import net.osmand.core.jni.PointI;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.QuadPointDouble;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.map.ITileSource;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.resources.ResourceManager;
|
||||||
|
import net.osmand.plus.views.BaseMapLayer;
|
||||||
|
import net.osmand.plus.views.MapTileLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.corenative.NativeCoreContext;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
|
||||||
|
public class MapVectorMiniLayer extends OsmandMapMiniLayer {
|
||||||
|
|
||||||
|
public static final int DEFAULT_MAX_ZOOM = 21;
|
||||||
|
public static final int DEFAULT_MIN_ZOOM = 1;
|
||||||
|
private int alpha = 255;
|
||||||
|
protected int warningToSwitchMapShown = 0;
|
||||||
|
|
||||||
|
public int getAlpha() {
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OsmandMapTileMiniView view;
|
||||||
|
private ResourceManager resourceManager;
|
||||||
|
private Paint paintImg;
|
||||||
|
|
||||||
|
private RectF destImage = new RectF();
|
||||||
|
private final MapTileMiniLayer tileLayer;
|
||||||
|
private boolean visible = false;
|
||||||
|
private boolean oldRender = false;
|
||||||
|
private String cachedUnderlay;
|
||||||
|
private Integer cachedMapTransparency;
|
||||||
|
private String cachedOverlay;
|
||||||
|
private Integer cachedOverlayTransparency;
|
||||||
|
|
||||||
|
public MapVectorMiniLayer(MapTileMiniLayer tileLayer, boolean oldRender) {
|
||||||
|
this.tileLayer = tileLayer;
|
||||||
|
this.oldRender = oldRender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileMiniView view) {
|
||||||
|
this.view = view;
|
||||||
|
//resourceManager = view.getApplication().getResourceManager();
|
||||||
|
resourceManager = new ResourceManager(view.getApplication());
|
||||||
|
paintImg = new Paint();
|
||||||
|
paintImg.setFilterBitmap(true);
|
||||||
|
paintImg.setAlpha(getAlpha());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVectorDataVisible() {
|
||||||
|
return visible && view.getZoom() >= view.getSettings().LEVEL_TO_SWITCH_VECTOR_RASTER.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
if (!visible) {
|
||||||
|
resourceManager.getRenderer().clearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) {
|
||||||
|
// if (!visible) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (!isVectorDataVisible() && tileLayer != null) {
|
||||||
|
// tileLayer.drawTileMap(canvas, tilesRect);
|
||||||
|
// resourceManager.getRenderer().interruptLoadingMap();
|
||||||
|
// } else {
|
||||||
|
final MapRendererView mapRenderer = view.getMapRenderer();
|
||||||
|
if (mapRenderer != null && !oldRender) {
|
||||||
|
NativeCoreContext.getMapRendererContext().setNightMode(drawSettings.isNightMode());
|
||||||
|
OsmandSettings st = view.getApplication().getSettings();
|
||||||
|
/* TODO: Commented to avoid crash (looks like IMapTiledDataProvider.Request parameter does not pass correctly or cannot be resolved while calling obtainImage method)
|
||||||
|
if (!Algorithms.objectEquals(st.MAP_UNDERLAY.get(), cachedUnderlay)) {
|
||||||
|
cachedUnderlay = st.MAP_UNDERLAY.get();
|
||||||
|
ITileSource tileSource = st.getTileSourceByName(cachedUnderlay, false);
|
||||||
|
if (tileSource != null) {
|
||||||
|
TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource);
|
||||||
|
mapRenderer.setMapLayerProvider(-1, prov.instantiateProxy(true));
|
||||||
|
prov.swigReleaseOwnership();
|
||||||
|
// mapRenderer.setMapLayerProvider(-1,
|
||||||
|
// net.osmand.core.jni.OnlineTileSources.getBuiltIn().createProviderFor("Mapnik (OsmAnd)"));
|
||||||
|
} else {
|
||||||
|
mapRenderer.resetMapLayerProvider(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (!Algorithms.objectEquals(st.MAP_TRANSPARENCY.get(), cachedMapTransparency)) {
|
||||||
|
cachedMapTransparency = st.MAP_TRANSPARENCY.get();
|
||||||
|
MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration();
|
||||||
|
mapLayerConfiguration.setOpacityFactor(((float) cachedMapTransparency) / 255.0f);
|
||||||
|
mapRenderer.setMapLayerConfiguration(0, mapLayerConfiguration);
|
||||||
|
}
|
||||||
|
/* TODO: Commented to avoid crash (looks like IMapTiledDataProvider.Request parameter does not pass correctly or cannot be resolved while calling obtainImage method)
|
||||||
|
if (!Algorithms.objectEquals(st.MAP_OVERLAY.get(), cachedOverlay)) {
|
||||||
|
cachedOverlay = st.MAP_OVERLAY.get();
|
||||||
|
ITileSource tileSource = st.getTileSourceByName(cachedOverlay, false);
|
||||||
|
if (tileSource != null) {
|
||||||
|
TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource);
|
||||||
|
mapRenderer.setMapLayerProvider(1, prov.instantiateProxy(true));
|
||||||
|
prov.swigReleaseOwnership();
|
||||||
|
// mapRenderer.setMapLayerProvider(1,
|
||||||
|
// net.osmand.core.jni.OnlineTileSources.getBuiltIn().createProviderFor("Mapnik (OsmAnd)"));
|
||||||
|
} else {
|
||||||
|
mapRenderer.resetMapLayerProvider(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Algorithms.objectEquals(st.MAP_OVERLAY_TRANSPARENCY.get(), cachedOverlayTransparency)) {
|
||||||
|
cachedOverlayTransparency = st.MAP_OVERLAY_TRANSPARENCY.get();
|
||||||
|
MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration();
|
||||||
|
mapLayerConfiguration.setOpacityFactor(((float) cachedOverlayTransparency) / 255.0f);
|
||||||
|
mapRenderer.setMapLayerConfiguration(1, mapLayerConfiguration);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// opengl renderer
|
||||||
|
LatLon ll = tilesRect.getLatLonFromPixel(tilesRect.getPixWidth() / 2, tilesRect.getPixHeight() / 2);
|
||||||
|
mapRenderer.setTarget(new PointI(MapUtils.get31TileNumberX(ll.getLongitude()), MapUtils.get31TileNumberY(ll
|
||||||
|
.getLatitude())));
|
||||||
|
mapRenderer.setAzimuth(-tilesRect.getRotate());
|
||||||
|
mapRenderer.setZoom((float) (tilesRect.getZoom() + tilesRect.getZoomAnimation() + tilesRect
|
||||||
|
.getZoomFloatPart()));
|
||||||
|
float zoomMagnifier = st.MAP_DENSITY.get();
|
||||||
|
mapRenderer.setVisualZoomShift(zoomMagnifier - 1.0f);
|
||||||
|
} else {
|
||||||
|
//if (!view.isZooming()) {
|
||||||
|
final OsmandMapLayer.DrawSettings drawSettings1 =
|
||||||
|
new OsmandMapLayer.DrawSettings(drawSettings.isNightMode(), true);
|
||||||
|
if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings1)) {
|
||||||
|
// pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 *
|
||||||
|
// view.getHeight() / 2);
|
||||||
|
final RotatedTileBox copy = tilesRect.copy();
|
||||||
|
copy.increasePixelDimensions(copy.getPixWidth() / 3, copy.getPixHeight() / 4);
|
||||||
|
resourceManager.updateRendererMap(copy, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapRenderRepositories renderer = resourceManager.getRenderer();
|
||||||
|
|
||||||
|
RotatedTileBox currentTileBlock = tilesRect;
|
||||||
|
resourceManager.getRenderer().loadMap(currentTileBlock, resourceManager.getMapTileDownloader());
|
||||||
|
drawRenderedMap(canvas, renderer.getBitmap(), renderer.getBitmapLocation(), tilesRect);
|
||||||
|
drawRenderedMap(canvas, renderer.getPrevBitmap(), renderer.getPrevBmpLocation(), tilesRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean drawRenderedMap(Canvas canvas, Bitmap bmp, RotatedTileBox bmpLoc, RotatedTileBox currentViewport) {
|
||||||
|
boolean shown = false;
|
||||||
|
if (bmp != null && bmpLoc != null) {
|
||||||
|
float rot = -bmpLoc.getRotate();
|
||||||
|
canvas.rotate(rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
|
||||||
|
final RotatedTileBox calc = currentViewport.copy();
|
||||||
|
calc.setRotate(bmpLoc.getRotate());
|
||||||
|
QuadPointDouble lt = bmpLoc.getLeftTopTile(bmpLoc.getZoom());
|
||||||
|
QuadPointDouble rb = bmpLoc.getRightBottomTile(bmpLoc.getZoom());
|
||||||
|
final float x1 = calc.getPixXFromTile(lt.x, lt.y, bmpLoc.getZoom());
|
||||||
|
final float x2 = calc.getPixXFromTile(rb.x, rb.y, bmpLoc.getZoom());
|
||||||
|
final float y1 = calc.getPixYFromTile(lt.x, lt.y, bmpLoc.getZoom());
|
||||||
|
final float y2 = calc.getPixYFromTile(rb.x, rb.y, bmpLoc.getZoom());
|
||||||
|
|
||||||
|
// LatLon lt = bmpLoc.getLeftTopLatLon();
|
||||||
|
// LatLon rb = bmpLoc.getRightBottomLatLon();
|
||||||
|
// final float x1 = calc.getPixXFromLatLon(lt.getLatitude(), lt.getLongitude());
|
||||||
|
// final float x2 = calc.getPixXFromLatLon(rb.getLatitude(), rb.getLongitude());
|
||||||
|
// final float y1 = calc.getPixYFromLatLon(lt.getLatitude(), lt.getLongitude());
|
||||||
|
// final float y2 = calc.getPixYFromLatLon(rb.getLatitude(), rb.getLongitude());
|
||||||
|
destImage.set(0, 0, 512, 512);
|
||||||
|
if (!bmp.isRecycled()) {
|
||||||
|
canvas.drawBitmap(bmp, null, destImage, paintImg);
|
||||||
|
shown = true;
|
||||||
|
}
|
||||||
|
canvas.rotate(-rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
|
||||||
|
}
|
||||||
|
return shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTap(PointF point, RotatedTileBox tileBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
OsmAnd/src/net/osmand/plus/server/map/MyCustomLayer.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
|
||||||
|
public class MyCustomLayer extends OsmandMapMiniLayer{
|
||||||
|
|
||||||
|
protected Paint paintBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileMiniView view) {
|
||||||
|
|
||||||
|
paintBitmap = new Paint();
|
||||||
|
paintBitmap.setFilterBitmap(true);
|
||||||
|
paintBitmap.setColor(Color.BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
//canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,40,paintBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
482
OsmAnd/src/net/osmand/plus/server/map/OsmandMapMiniLayer.java
Normal file
|
@ -0,0 +1,482 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.*;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import net.osmand.binary.BinaryMapIndexReader;
|
||||||
|
import net.osmand.data.*;
|
||||||
|
import net.osmand.osm.PoiCategory;
|
||||||
|
import net.osmand.plus.ContextMenuAdapter;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.render.OsmandRenderer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.render.RenderingRuleSearchRequest;
|
||||||
|
import net.osmand.render.RenderingRulesStorage;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class OsmandMapMiniLayer {
|
||||||
|
|
||||||
|
protected List<LatLon> fullObjectsLatLon;
|
||||||
|
protected List<LatLon> smallObjectsLatLon;
|
||||||
|
|
||||||
|
public enum MapGestureType {
|
||||||
|
DOUBLE_TAP_ZOOM_IN,
|
||||||
|
DOUBLE_TAP_ZOOM_CHANGE,
|
||||||
|
TWO_POINTERS_ZOOM_OUT
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMapGestureAllowed(MapGestureType type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void initLayer(OsmandMapTileMiniView view);
|
||||||
|
|
||||||
|
public abstract void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings);
|
||||||
|
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void destroyLayer();
|
||||||
|
|
||||||
|
public void onRetainNonConfigurationInstance(Map<String, Object> map) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populateObjectContextMenu(LatLon latLon, Object o, ContextMenuAdapter adapter, MapActivity mapActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onSingleTap(PointF point, RotatedTileBox tileBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent event, RotatedTileBox tileBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public <Params> void executeTaskInBackground(AsyncTask<Params, ?, ?> task, Params... params) {
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresentInFullObjects(LatLon latLon) {
|
||||||
|
if (fullObjectsLatLon == null) {
|
||||||
|
return true;
|
||||||
|
} else if (latLon != null) {
|
||||||
|
return fullObjectsLatLon.contains(latLon);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresentInSmallObjects(LatLon latLon) {
|
||||||
|
if (smallObjectsLatLon != null && latLon != null) {
|
||||||
|
return smallObjectsLatLon.contains(latLon);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns whether canvas should be rotated as
|
||||||
|
* map rotated before {@link #onDraw(android.graphics.Canvas, net.osmand.data.RotatedTileBox, DrawSettings)}.
|
||||||
|
* If the layer draws simply layer over screen (not over map)
|
||||||
|
* it should return true.
|
||||||
|
*/
|
||||||
|
public abstract boolean drawInScreenPixels();
|
||||||
|
|
||||||
|
public static class DrawSettings {
|
||||||
|
private final boolean nightMode;
|
||||||
|
private final boolean updateVectorRendering;
|
||||||
|
|
||||||
|
public DrawSettings(boolean nightMode) {
|
||||||
|
this(nightMode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawSettings(boolean nightMode, boolean updateVectorRendering) {
|
||||||
|
this.nightMode = nightMode;
|
||||||
|
this.updateVectorRendering = updateVectorRendering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpdateVectorRendering() {
|
||||||
|
return updateVectorRendering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNightMode() {
|
||||||
|
return nightMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static QuadTree<QuadRect> initBoundIntersections(RotatedTileBox tileBox) {
|
||||||
|
QuadRect bounds = new QuadRect(0, 0, tileBox.getPixWidth(), tileBox.getPixHeight());
|
||||||
|
bounds.inset(-bounds.width() / 4, -bounds.height() / 4);
|
||||||
|
return new QuadTree<>(bounds, 4, 0.6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean intersects(QuadTree<QuadRect> boundIntersections, float x, float y, float width, float height) {
|
||||||
|
List<QuadRect> result = new ArrayList<>();
|
||||||
|
QuadRect visibleRect = calculateRect(x, y, width, height);
|
||||||
|
boundIntersections.queryInBox(new QuadRect(visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom), result);
|
||||||
|
for (QuadRect r : result) {
|
||||||
|
if (QuadRect.intersects(r, visibleRect)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boundIntersections.insert(visibleRect,
|
||||||
|
new QuadRect(visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuadRect getCorrectedQuadRect(QuadRect latlonRect) {
|
||||||
|
double topLatitude = latlonRect.top;
|
||||||
|
double leftLongitude = latlonRect.left;
|
||||||
|
double bottomLatitude = latlonRect.bottom;
|
||||||
|
double rightLongitude = latlonRect.right;
|
||||||
|
// double lat = 0;
|
||||||
|
// double lon = 0;
|
||||||
|
// this is buggy lat/lon should be 0 but in that case
|
||||||
|
// it needs to be fixed in case there is no route points in the view bbox
|
||||||
|
double lat = topLatitude - bottomLatitude + 0.1;
|
||||||
|
double lon = rightLongitude - leftLongitude + 0.1;
|
||||||
|
return new QuadRect(leftLongitude - lon, topLatitude + lat, rightLongitude + lon, bottomLatitude - lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuadRect calculateRect(float x, float y, float width, float height) {
|
||||||
|
QuadRect rf;
|
||||||
|
double left = x - width / 2.0d;
|
||||||
|
double top = y - height / 2.0d;
|
||||||
|
double right = left + width;
|
||||||
|
double bottom = top + height;
|
||||||
|
rf = new QuadRect(left, top, right, bottom);
|
||||||
|
return rf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Amenity findAmenity(OsmandApplication app, long id, List<String> names, LatLon latLon, int radius) {
|
||||||
|
QuadRect rect = MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), radius);
|
||||||
|
List<Amenity> amenities = app.getResourceManager().searchAmenities(
|
||||||
|
new BinaryMapIndexReader.SearchPoiTypeFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(PoiCategory type, String subcategory) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, rect.top, rect.left, rect.bottom, rect.right, -1, null);
|
||||||
|
|
||||||
|
Amenity res = null;
|
||||||
|
for (Amenity amenity : amenities) {
|
||||||
|
Long amenityId = amenity.getId() >> 1;
|
||||||
|
if (amenityId == id && !amenity.isClosed()) {
|
||||||
|
res = amenity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res == null && names != null && names.size() > 0) {
|
||||||
|
for (Amenity amenity : amenities) {
|
||||||
|
for (String name : names) {
|
||||||
|
if (name.equals(amenity.getName()) && !amenity.isClosed()) {
|
||||||
|
res = amenity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDefaultRadiusPoi(RotatedTileBox tb) {
|
||||||
|
int r;
|
||||||
|
final double zoom = tb.getZoom();
|
||||||
|
if (zoom <= 15) {
|
||||||
|
r = 10;
|
||||||
|
} else if (zoom <= 16) {
|
||||||
|
r = 14;
|
||||||
|
} else if (zoom <= 17) {
|
||||||
|
r = 16;
|
||||||
|
} else {
|
||||||
|
r = 18;
|
||||||
|
}
|
||||||
|
return (int) (r * tb.getDensity());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getIconSize(Context ctx) {
|
||||||
|
return ctx.getResources().getDimensionPixelSize(R.dimen.favorites_icon_outline_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rect getIconDestinationRect(float x, float y, int width, int height, float scale) {
|
||||||
|
int scaledWidth = width;
|
||||||
|
int scaledHeight = height;
|
||||||
|
if (scale != 1.0f) {
|
||||||
|
scaledWidth = (int) (width * scale);
|
||||||
|
scaledHeight = (int) (height * scale);
|
||||||
|
}
|
||||||
|
Rect rect = new Rect(0, 0, scaledWidth, scaledHeight);
|
||||||
|
rect.offset((int) x - scaledWidth / 2, (int) y - scaledHeight / 2);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScaledTouchRadius(OsmandApplication app, int radiusPoi) {
|
||||||
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
|
if (textScale < 1.0f) {
|
||||||
|
textScale = 1.0f;
|
||||||
|
}
|
||||||
|
return (int) textScale * radiusPoi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapButtonIcon(ImageView imageView, Drawable icon) {
|
||||||
|
int btnSizePx = imageView.getLayoutParams().height;
|
||||||
|
int iconSizePx = imageView.getContext().getResources().getDimensionPixelSize(R.dimen.map_widget_icon);
|
||||||
|
int iconPadding = (btnSizePx - iconSizePx) / 2;
|
||||||
|
imageView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding);
|
||||||
|
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||||
|
imageView.setImageDrawable(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class MapLayerData<T> {
|
||||||
|
public int ZOOM_THRESHOLD = 1;
|
||||||
|
public RotatedTileBox queriedBox;
|
||||||
|
protected T results;
|
||||||
|
protected Task currentTask;
|
||||||
|
protected Task pendingTask;
|
||||||
|
|
||||||
|
public RotatedTileBox getQueriedBox() {
|
||||||
|
return queriedBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResults() {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean queriedBoxContains(final RotatedTileBox queriedData, final RotatedTileBox newBox) {
|
||||||
|
return queriedData != null && queriedData.containsTileBox(newBox) && Math.abs(queriedData.getZoom() - newBox.getZoom()) <= ZOOM_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void queryNewData(RotatedTileBox tileBox) {
|
||||||
|
if (!queriedBoxContains(queriedBox, tileBox)) {
|
||||||
|
Task ct = currentTask;
|
||||||
|
if (ct == null || !queriedBoxContains(ct.getDataBox(), tileBox)) {
|
||||||
|
RotatedTileBox original = tileBox.copy();
|
||||||
|
RotatedTileBox extended = original.copy();
|
||||||
|
extended.increasePixelDimensions(tileBox.getPixWidth() / 2, tileBox.getPixHeight() / 2);
|
||||||
|
Task task = new Task(original, extended);
|
||||||
|
if (currentTask == null) {
|
||||||
|
executeTaskInBackground(task);
|
||||||
|
} else {
|
||||||
|
pendingTask = task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void layerOnPreExecute() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void layerOnPostExecute() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterrupted() {
|
||||||
|
return pendingTask != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T calculateResult(RotatedTileBox tileBox);
|
||||||
|
|
||||||
|
public class Task extends AsyncTask<Object, Object, T> {
|
||||||
|
private RotatedTileBox dataBox;
|
||||||
|
private RotatedTileBox requestedBox;
|
||||||
|
|
||||||
|
public Task(RotatedTileBox requestedBox, RotatedTileBox dataBox) {
|
||||||
|
this.requestedBox = requestedBox;
|
||||||
|
this.dataBox = dataBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RotatedTileBox getOriginalBox() {
|
||||||
|
return requestedBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RotatedTileBox getDataBox() {
|
||||||
|
return dataBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected T doInBackground(Object... params) {
|
||||||
|
if (queriedBoxContains(queriedBox, dataBox)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return calculateResult(dataBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
currentTask = this;
|
||||||
|
layerOnPreExecute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(T result) {
|
||||||
|
if (result != null) {
|
||||||
|
queriedBox = dataBox;
|
||||||
|
results = result;
|
||||||
|
}
|
||||||
|
currentTask = null;
|
||||||
|
if (pendingTask != null) {
|
||||||
|
executeTaskInBackground(pendingTask);
|
||||||
|
pendingTask = null;
|
||||||
|
} else {
|
||||||
|
layerOnPostExecute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCache() {
|
||||||
|
results = null;
|
||||||
|
queriedBox = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RenderingLineAttributes {
|
||||||
|
protected int cachedHash;
|
||||||
|
public Paint paint;
|
||||||
|
public Paint customColorPaint;
|
||||||
|
public int customColor = 0;
|
||||||
|
public int defaultWidth = 0;
|
||||||
|
public int defaultColor = 0;
|
||||||
|
public boolean isPaint2;
|
||||||
|
public Paint paint2;
|
||||||
|
public int defaultWidth2 = 0;
|
||||||
|
public boolean isPaint3;
|
||||||
|
public Paint paint3;
|
||||||
|
public int defaultWidth3 = 0;
|
||||||
|
public Paint shadowPaint;
|
||||||
|
public boolean isShadowPaint;
|
||||||
|
public int defaultShadowWidthExtent = 2;
|
||||||
|
public Paint paint_1;
|
||||||
|
public boolean isPaint_1;
|
||||||
|
public int defaultWidth_1 = 0;
|
||||||
|
private String renderingAttribute;
|
||||||
|
|
||||||
|
public RenderingLineAttributes(String renderingAttribute) {
|
||||||
|
this.renderingAttribute = renderingAttribute;
|
||||||
|
paint = initPaint();
|
||||||
|
customColorPaint = new Paint(paint);
|
||||||
|
paint2 = initPaint();
|
||||||
|
paint3 = initPaint();
|
||||||
|
paint_1 = initPaint();
|
||||||
|
shadowPaint = initPaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Paint initPaint() {
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setStyle(Paint.Style.STROKE);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||||
|
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||||
|
return paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean updatePaints(OsmandApplication app, DrawSettings settings, RotatedTileBox tileBox) {
|
||||||
|
OsmandRenderer renderer = app.getResourceManager().getRenderer().getRenderer();
|
||||||
|
RenderingRulesStorage rrs = app.getRendererRegistry().getCurrentSelectedRenderer();
|
||||||
|
final boolean isNight = settings != null && settings.isNightMode();
|
||||||
|
int hsh = calculateHash(rrs, isNight, tileBox.getDensity());
|
||||||
|
if (hsh != cachedHash) {
|
||||||
|
cachedHash = hsh;
|
||||||
|
if (rrs != null) {
|
||||||
|
RenderingRuleSearchRequest req = new RenderingRuleSearchRequest(rrs);
|
||||||
|
req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, isNight);
|
||||||
|
if (req.searchRenderingAttribute(renderingAttribute)) {
|
||||||
|
OsmandRenderer.RenderingContext rc = new OsmandRenderer.RenderingContext(app);
|
||||||
|
rc.setDensityValue((float) tileBox.getDensity());
|
||||||
|
// cachedColor = req.getIntPropertyValue(rrs.PROPS.R_COLOR);
|
||||||
|
renderer.updatePaint(req, paint, 0, false, rc);
|
||||||
|
isPaint2 = renderer.updatePaint(req, paint2, 1, false, rc);
|
||||||
|
if (paint2.getStrokeWidth() == 0 && defaultWidth2 != 0) {
|
||||||
|
paint2.setStrokeWidth(defaultWidth2);
|
||||||
|
}
|
||||||
|
isPaint3 = renderer.updatePaint(req, paint3, 2, false, rc);
|
||||||
|
if (paint3.getStrokeWidth() == 0 && defaultWidth3 != 0) {
|
||||||
|
paint3.setStrokeWidth(defaultWidth3);
|
||||||
|
}
|
||||||
|
isPaint_1 = renderer.updatePaint(req, paint_1, -1, false, rc);
|
||||||
|
if (paint_1.getStrokeWidth() == 0 && defaultWidth_1 != 0) {
|
||||||
|
paint_1.setStrokeWidth(defaultWidth_1);
|
||||||
|
}
|
||||||
|
isShadowPaint = req.isSpecified(rrs.PROPS.R_SHADOW_RADIUS);
|
||||||
|
if (isShadowPaint) {
|
||||||
|
ColorFilter cf = new PorterDuffColorFilter(
|
||||||
|
req.getIntPropertyValue(rrs.PROPS.R_SHADOW_COLOR), PorterDuff.Mode.SRC_IN);
|
||||||
|
shadowPaint.setColorFilter(cf);
|
||||||
|
shadowPaint.setStrokeWidth(paint.getStrokeWidth() + defaultShadowWidthExtent
|
||||||
|
* rc.getComplexValue(req, rrs.PROPS.R_SHADOW_RADIUS));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("Rendering attribute route is not found !");
|
||||||
|
}
|
||||||
|
updateDefaultColor(paint, defaultColor);
|
||||||
|
if (paint.getStrokeWidth() == 0 && defaultWidth != 0) {
|
||||||
|
paint.setStrokeWidth(defaultWidth);
|
||||||
|
}
|
||||||
|
customColorPaint = new Paint(paint);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateDefaultColor(Paint paint, int defaultColor) {
|
||||||
|
if ((paint.getColor() == 0 || paint.getColor() == Color.BLACK) && defaultColor != 0) {
|
||||||
|
paint.setColor(defaultColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateHash(Object... o) {
|
||||||
|
return Arrays.hashCode(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPath(Canvas canvas, Path path) {
|
||||||
|
if (isPaint_1) {
|
||||||
|
canvas.drawPath(path, paint_1);
|
||||||
|
}
|
||||||
|
if (isShadowPaint) {
|
||||||
|
canvas.drawPath(path, shadowPaint);
|
||||||
|
}
|
||||||
|
if (customColor != 0) {
|
||||||
|
customColorPaint.setColor(customColor);
|
||||||
|
canvas.drawPath(path, customColorPaint);
|
||||||
|
} else {
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
if (isPaint2) {
|
||||||
|
canvas.drawPath(path, paint2);
|
||||||
|
}
|
||||||
|
if (isPaint3) {
|
||||||
|
canvas.drawPath(path, paint3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1314
OsmAnd/src/net/osmand/plus/server/map/OsmandMapTileMiniView.java
Normal file
471
OsmAnd/src/net/osmand/plus/server/map/POIMapLayerMini.java
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
package net.osmand.plus.server.map;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.util.Linkify;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.ResultMatcher;
|
||||||
|
import net.osmand.ValueHolder;
|
||||||
|
import net.osmand.data.*;
|
||||||
|
import net.osmand.osm.PoiType;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.base.PointImageDrawable;
|
||||||
|
import net.osmand.plus.helpers.WaypointHelper;
|
||||||
|
import net.osmand.plus.poi.PoiUIFilter;
|
||||||
|
import net.osmand.plus.render.RenderingIcons;
|
||||||
|
import net.osmand.plus.routing.IRouteInformationListener;
|
||||||
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.layers.ContextMenuLayer;
|
||||||
|
import net.osmand.plus.views.layers.MapTextLayer;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static net.osmand.AndroidUtils.dpToPx;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.util.Linkify;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.ResultMatcher;
|
||||||
|
import net.osmand.ValueHolder;
|
||||||
|
import net.osmand.data.Amenity;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.PointDescription;
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
|
import net.osmand.data.QuadTree;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.osm.PoiType;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.OsmandPlugin;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.base.PointImageDrawable;
|
||||||
|
import net.osmand.plus.helpers.WaypointHelper;
|
||||||
|
import net.osmand.plus.poi.PoiUIFilter;
|
||||||
|
import net.osmand.plus.render.RenderingIcons;
|
||||||
|
import net.osmand.plus.routing.IRouteInformationListener;
|
||||||
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer;
|
||||||
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
|
import net.osmand.plus.views.layers.MapTextLayer.MapTextProvider;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import static net.osmand.AndroidUtils.dpToPx;
|
||||||
|
|
||||||
|
public class POIMapLayerMini extends OsmandMapMiniLayer implements ContextMenuLayer.IContextMenuProvider,
|
||||||
|
MapTextLayer.MapTextProvider<Amenity>, IRouteInformationListener {
|
||||||
|
private static final int startZoom = 9;
|
||||||
|
|
||||||
|
public static final org.apache.commons.logging.Log log = PlatformUtil.getLog(net.osmand.plus.views.layers.POIMapLayer.class);
|
||||||
|
|
||||||
|
private OsmandMapTileMiniView view;
|
||||||
|
|
||||||
|
private RoutingHelper routingHelper;
|
||||||
|
private Set<PoiUIFilter> filters = new TreeSet<>();
|
||||||
|
private MapTextLayer mapTextLayer;
|
||||||
|
|
||||||
|
/// cache for displayed POI
|
||||||
|
// Work with cache (for map copied from AmenityIndexRepositoryOdb)
|
||||||
|
private MapLayerData<List<Amenity>> data;
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
|
||||||
|
public POIMapLayerMini(final OsmandApplication app) {
|
||||||
|
routingHelper = app.getRoutingHelper();
|
||||||
|
routingHelper.addListener(this);
|
||||||
|
this.app = app;
|
||||||
|
data = new OsmandMapMiniLayer.MapLayerData<List<Amenity>>() {
|
||||||
|
|
||||||
|
Set<PoiUIFilter> calculatedFilters;
|
||||||
|
|
||||||
|
{
|
||||||
|
ZOOM_THRESHOLD = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInterrupted() {
|
||||||
|
return super.isInterrupted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layerOnPreExecute() {
|
||||||
|
calculatedFilters = new TreeSet<>(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layerOnPostExecute() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Amenity> calculateResult(RotatedTileBox tileBox) {
|
||||||
|
QuadRect latLonBounds = tileBox.getLatLonBounds();
|
||||||
|
if (calculatedFilters.isEmpty() || latLonBounds == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
int z = (int) Math.floor(tileBox.getZoom() + Math.log(view.getSettings().MAP_DENSITY.get()) / Math.log(2));
|
||||||
|
|
||||||
|
List<Amenity> res = new ArrayList<>();
|
||||||
|
PoiUIFilter.combineStandardPoiFilters(calculatedFilters, app);
|
||||||
|
for (PoiUIFilter filter : calculatedFilters) {
|
||||||
|
res.addAll(filter.searchAmenities(latLonBounds.top, latLonBounds.left,
|
||||||
|
latLonBounds.bottom, latLonBounds.right, z, new ResultMatcher<Amenity>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean publish(Amenity object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return isInterrupted();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(res, new Comparator<Amenity>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Amenity lhs, Amenity rhs) {
|
||||||
|
return lhs.getId() < rhs.getId() ? -1 : (lhs.getId().longValue() == rhs.getId().longValue() ? 0 : 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getAmenityFromPoint(RotatedTileBox tb, PointF point, List<? super Amenity> am) {
|
||||||
|
List<Amenity> objects = data.getResults();
|
||||||
|
if (objects != null) {
|
||||||
|
int ex = (int) point.x;
|
||||||
|
int ey = (int) point.y;
|
||||||
|
int compare = getScaledTouchRadius(view.getApplication(), getRadiusPoi(tb));
|
||||||
|
int radius = compare * 3 / 2;
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
|
Amenity n = objects.get(i);
|
||||||
|
int x = (int) tb.getPixXFromLatLon(n.getLocation().getLatitude(), n.getLocation().getLongitude());
|
||||||
|
int y = (int) tb.getPixYFromLatLon(n.getLocation().getLatitude(), n.getLocation().getLongitude());
|
||||||
|
if (Math.abs(x - ex) <= compare && Math.abs(y - ey) <= compare) {
|
||||||
|
compare = radius;
|
||||||
|
am.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
// that's really rare case, but is much efficient than introduce synchronized block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initLayer(OsmandMapTileMiniView view) {
|
||||||
|
this.view = view;
|
||||||
|
//mapTextLayer = view.getLayerByClass(MapTextLayer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRadiusPoi(RotatedTileBox tb) {
|
||||||
|
int r;
|
||||||
|
final double zoom = tb.getZoom();
|
||||||
|
if (zoom < startZoom) {
|
||||||
|
r = 0;
|
||||||
|
} else if (zoom <= 15) {
|
||||||
|
r = 10;
|
||||||
|
} else if (zoom <= 16) {
|
||||||
|
r = 14;
|
||||||
|
} else if (zoom <= 17) {
|
||||||
|
r = 16;
|
||||||
|
} else {
|
||||||
|
r = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) (r * view.getScaleCoefficient());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
Set<PoiUIFilter> selectedPoiFilters = app.getPoiFilters().getSelectedPoiFilters();
|
||||||
|
if (this.filters != selectedPoiFilters) {
|
||||||
|
this.filters = selectedPoiFilters;
|
||||||
|
data.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Amenity> objects = Collections.emptyList();
|
||||||
|
List<Amenity> fullObjects = new ArrayList<>();
|
||||||
|
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
||||||
|
List<LatLon> smallObjectsLatLon = new ArrayList<>();
|
||||||
|
//if (!filters.isEmpty()) {
|
||||||
|
if (tileBox.getZoom() >= startZoom) {
|
||||||
|
data.queryNewData(tileBox);
|
||||||
|
objects = data.getResults();
|
||||||
|
if (objects != null) {
|
||||||
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
|
float iconSize = getIconSize(app) * 1.5f * textScale;
|
||||||
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
|
WaypointHelper wph = app.getWaypointHelper();
|
||||||
|
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(app,
|
||||||
|
ContextCompat.getColor(app, R.color.osmand_orange), true);
|
||||||
|
pointImageDrawable.setAlpha(0.8f);
|
||||||
|
for (Amenity o : objects) {
|
||||||
|
float x = tileBox.getPixXFromLatLon(o.getLocation().getLatitude(), o.getLocation()
|
||||||
|
.getLongitude());
|
||||||
|
float y = tileBox.getPixYFromLatLon(o.getLocation().getLatitude(), o.getLocation()
|
||||||
|
.getLongitude());
|
||||||
|
|
||||||
|
if (tileBox.containsPoint(x, y, iconSize)) {
|
||||||
|
if (intersects(boundIntersections, x, y, iconSize, iconSize) ||
|
||||||
|
(app.getSettings().SHOW_NEARBY_POI.get() && wph.isRouteCalculated() && !wph.isAmenityNoPassed(o))) {
|
||||||
|
pointImageDrawable.drawSmallPoint(canvas, x, y, textScale);
|
||||||
|
smallObjectsLatLon.add(new LatLon(o.getLocation().getLatitude(),
|
||||||
|
o.getLocation().getLongitude()));
|
||||||
|
} else {
|
||||||
|
fullObjects.add(o);
|
||||||
|
fullObjectsLatLon.add(new LatLon(o.getLocation().getLatitude(),
|
||||||
|
o.getLocation().getLongitude()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Amenity o : fullObjects) {
|
||||||
|
int x = (int) tileBox.getPixXFromLatLon(o.getLocation().getLatitude(), o.getLocation()
|
||||||
|
.getLongitude());
|
||||||
|
int y = (int) tileBox.getPixYFromLatLon(o.getLocation().getLatitude(), o.getLocation()
|
||||||
|
.getLongitude());
|
||||||
|
if (tileBox.containsPoint(x, y, iconSize)) {
|
||||||
|
String id = null;
|
||||||
|
PoiType st = o.getType().getPoiTypeByKeyName(o.getSubType());
|
||||||
|
if (st != null) {
|
||||||
|
if (RenderingIcons.containsSmallIcon(st.getIconKeyName())) {
|
||||||
|
id = st.getIconKeyName();
|
||||||
|
} else if (RenderingIcons.containsSmallIcon(st.getOsmTag() + "_" + st.getOsmValue())) {
|
||||||
|
id = st.getOsmTag() + "_" + st.getOsmValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id != null) {
|
||||||
|
pointImageDrawable = PointImageDrawable.getOrCreate(app,
|
||||||
|
ContextCompat.getColor(app, R.color.osmand_orange), true,
|
||||||
|
RenderingIcons.getResId(id));
|
||||||
|
pointImageDrawable.setAlpha(0.8f);
|
||||||
|
pointImageDrawable.drawPoint(canvas, x, y, textScale, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.fullObjectsLatLon = fullObjectsLatLon;
|
||||||
|
this.smallObjectsLatLon = smallObjectsLatLon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
//mapTextLayer.putData(this, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyLayer() {
|
||||||
|
routingHelper.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean drawInScreenPixels() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showDescriptionDialog(Context ctx, OsmandApplication app, String text, String title) {
|
||||||
|
showText(ctx, app, text, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getResIdFromAttribute(final Context ctx, final int attr) {
|
||||||
|
if (attr == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
final TypedValue typedvalueattr = new TypedValue();
|
||||||
|
ctx.getTheme().resolveAttribute(attr, typedvalueattr, true);
|
||||||
|
return typedvalueattr.resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showText(final Context ctx, final OsmandApplication app, final String text, String title) {
|
||||||
|
final Dialog dialog = new Dialog(ctx,
|
||||||
|
app.getSettings().isLightContent() ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
|
||||||
|
|
||||||
|
LinearLayout ll = new LinearLayout(ctx);
|
||||||
|
ll.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
final Toolbar topBar = new Toolbar(ctx);
|
||||||
|
topBar.setClickable(true);
|
||||||
|
Drawable icBack = app.getUIUtilities().getIcon(AndroidUtils.getNavigationIconResId(ctx));
|
||||||
|
topBar.setNavigationIcon(icBack);
|
||||||
|
topBar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
|
||||||
|
topBar.setTitle(title);
|
||||||
|
topBar.setBackgroundColor(ContextCompat.getColor(ctx, getResIdFromAttribute(ctx, R.attr.pstsTabBackground)));
|
||||||
|
topBar.setTitleTextColor(ContextCompat.getColor(ctx, getResIdFromAttribute(ctx, R.attr.pstsTextColor)));
|
||||||
|
topBar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(final View v) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final TextView textView = new TextView(ctx);
|
||||||
|
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
int textMargin = dpToPx(app, 10f);
|
||||||
|
boolean light = app.getSettings().isLightContent();
|
||||||
|
textView.setLayoutParams(llTextParams);
|
||||||
|
textView.setPadding(textMargin, textMargin, textMargin, textMargin);
|
||||||
|
textView.setTextSize(16);
|
||||||
|
textView.setTextColor(ContextCompat.getColor(app, light ? R.color.text_color_primary_light : R.color.text_color_primary_dark));
|
||||||
|
textView.setAutoLinkMask(Linkify.ALL);
|
||||||
|
textView.setLinksClickable(true);
|
||||||
|
textView.setText(text);
|
||||||
|
|
||||||
|
ScrollView scrollView = new ScrollView(ctx);
|
||||||
|
ll.addView(topBar);
|
||||||
|
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
|
||||||
|
lp.weight = 1;
|
||||||
|
ll.addView(scrollView, lp);
|
||||||
|
scrollView.addView(textView);
|
||||||
|
|
||||||
|
dialog.setContentView(ll);
|
||||||
|
dialog.setCancelable(true);
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PointDescription getObjectName(Object o) {
|
||||||
|
if (o instanceof Amenity) {
|
||||||
|
Amenity amenity = (Amenity) o;
|
||||||
|
String preferredLang = app.getSettings().MAP_PREFERRED_LOCALE.get();
|
||||||
|
boolean transliterateNames = app.getSettings().MAP_TRANSLITERATE_NAMES.get();
|
||||||
|
|
||||||
|
if (amenity.getType().isWiki()) {
|
||||||
|
if (Algorithms.isEmpty(preferredLang)) {
|
||||||
|
preferredLang = app.getLanguage();
|
||||||
|
}
|
||||||
|
preferredLang = OsmandPlugin.onGetMapObjectsLocale(amenity, preferredLang);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PointDescription(PointDescription.POINT_TYPE_POI,
|
||||||
|
amenity.getName(preferredLang, transliterateNames));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableSingleTap() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableLongPressOnMap() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> objects, boolean unknownLocation) {
|
||||||
|
if (tileBox.getZoom() >= startZoom) {
|
||||||
|
getAmenityFromPoint(tileBox, point, objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LatLon getObjectLocation(Object o) {
|
||||||
|
if (o instanceof Amenity) {
|
||||||
|
return ((Amenity) o).getLocation();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectClickable(Object o) {
|
||||||
|
return o instanceof Amenity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean runExclusiveAction(Object o, boolean unknownLocation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LatLon getTextLocation(Amenity o) {
|
||||||
|
return o.getLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTextShift(Amenity amenity, RotatedTileBox rb) {
|
||||||
|
int radiusPoi = getRadiusPoi(rb);
|
||||||
|
if (isPresentInFullObjects(amenity.getLocation())) {
|
||||||
|
radiusPoi += (getIconSize(app) - app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_size_small)) / 2;
|
||||||
|
}
|
||||||
|
return radiusPoi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText(Amenity o) {
|
||||||
|
return o.getName(view.getSettings().MAP_PREFERRED_LOCALE.get(),
|
||||||
|
view.getSettings().MAP_TRANSLITERATE_NAMES.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTextVisible() {
|
||||||
|
return app.getSettings().SHOW_POI_LABEL.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFakeBoldText() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void newRouteIsCalculated(boolean newRoute, ValueHolder<Boolean> showToast) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void routeWasCancelled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void routeWasFinished() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
protected OsmandSettings settings = null;
|
protected OsmandSettings settings = null;
|
||||||
private CanvasColors canvasColors = null;
|
private CanvasColors canvasColors = null;
|
||||||
private Boolean nightMode = null;
|
private Boolean nightMode = null;
|
||||||
|
public Bitmap currentCanvas = null;
|
||||||
|
|
||||||
private class CanvasColors {
|
private class CanvasColors {
|
||||||
int colorDay = MAP_DEFAULT_COLOR;
|
int colorDay = MAP_DEFAULT_COLOR;
|
||||||
|
@ -104,7 +105,6 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
|
|
||||||
protected static final int emptyTileDivisor = 16;
|
protected static final int emptyTileDivisor = 16;
|
||||||
|
|
||||||
|
|
||||||
public interface OnTrackBallListener {
|
public interface OnTrackBallListener {
|
||||||
public boolean onTrackBallEvent(MotionEvent e);
|
public boolean onTrackBallEvent(MotionEvent e);
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,10 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
public void onDrawOverMap();
|
public void onDrawOverMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IMapImageDrawListener {
|
||||||
|
public void onDraw(RotatedTileBox viewport,Bitmap bmp);
|
||||||
|
}
|
||||||
|
|
||||||
protected static final Log LOG = PlatformUtil.getLog(OsmandMapTileView.class);
|
protected static final Log LOG = PlatformUtil.getLog(OsmandMapTileView.class);
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,6 +148,8 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
|
|
||||||
private OnTrackBallListener trackBallDelegate;
|
private OnTrackBallListener trackBallDelegate;
|
||||||
|
|
||||||
|
private IMapImageDrawListener iMapImageDrawListener;
|
||||||
|
|
||||||
private AccessibilityActionsProvider accessibilityActions;
|
private AccessibilityActionsProvider accessibilityActions;
|
||||||
|
|
||||||
private List<OsmandMapLayer> layers = new ArrayList<>();
|
private List<OsmandMapLayer> layers = new ArrayList<>();
|
||||||
|
@ -366,6 +372,14 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
return wasZoomInMultiTouch;
|
return wasZoomInMultiTouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMapImageDrawListener getMapImageDrawListener() {
|
||||||
|
return iMapImageDrawListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapImageDrawListener(IMapImageDrawListener iMapImageDrawListener) {
|
||||||
|
this.iMapImageDrawListener = iMapImageDrawListener;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean mapGestureAllowed(OsmandMapLayer.MapGestureType type) {
|
public boolean mapGestureAllowed(OsmandMapLayer.MapGestureType type) {
|
||||||
for (OsmandMapLayer layer : layers) {
|
for (OsmandMapLayer layer : layers) {
|
||||||
if (!layer.isMapGestureAllowed(type)) {
|
if (!layer.isMapGestureAllowed(type)) {
|
||||||
|
@ -517,8 +531,8 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
|
|
||||||
public void restoreMapRatio() {
|
public void restoreMapRatio() {
|
||||||
RotatedTileBox box = currentViewport.copy();
|
RotatedTileBox box = currentViewport.copy();
|
||||||
float rx = (float)box.getCenterPixelX() / box.getPixWidth();
|
float rx = (float) box.getCenterPixelX() / box.getPixWidth();
|
||||||
float ry = (float)box.getCenterPixelY() / box.getPixHeight();
|
float ry = (float) box.getCenterPixelY() / box.getPixHeight();
|
||||||
if (mapPosition == OsmandSettings.BOTTOM_CONSTANT) {
|
if (mapPosition == OsmandSettings.BOTTOM_CONSTANT) {
|
||||||
ry -= 0.35;
|
ry -= 0.35;
|
||||||
}
|
}
|
||||||
|
@ -574,12 +588,13 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
if (!bufferBitmap.isRecycled()) {
|
if (!bufferBitmap.isRecycled()) {
|
||||||
RectF rct = new RectF(x1, y1, x2, y2);
|
RectF rct = new RectF(x1, y1, x2, y2);
|
||||||
canvas.drawBitmap(bufferBitmap, null, rct, paintImg);
|
canvas.drawBitmap(bufferBitmap, null, rct, paintImg);
|
||||||
|
currentCanvas = bufferBitmap;
|
||||||
}
|
}
|
||||||
canvas.rotate(-rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
|
canvas.rotate(-rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshBaseMapInternal(RotatedTileBox tileBox, DrawSettings drawSettings) {
|
public void refreshBaseMapInternal(RotatedTileBox tileBox, DrawSettings drawSettings) {
|
||||||
if (tileBox.getPixHeight() == 0 || tileBox.getPixWidth() == 0) {
|
if (tileBox.getPixHeight() == 0 || tileBox.getPixWidth() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -614,9 +629,12 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
}
|
}
|
||||||
long end = SystemClock.elapsedRealtime();
|
long end = SystemClock.elapsedRealtime();
|
||||||
additional.calculateFPS(start, end);
|
additional.calculateFPS(start, end);
|
||||||
|
if (iMapImageDrawListener != null){
|
||||||
|
iMapImageDrawListener.onDraw(tileBox,bufferBitmap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshMapInternal(DrawSettings drawSettings) {
|
public void refreshMapInternal(DrawSettings drawSettings) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -821,7 +839,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
|
|
||||||
// this method could be called in non UI thread
|
// this method could be called in non UI thread
|
||||||
public void refreshMap(final boolean updateVectorRendering) {
|
public void refreshMap(final boolean updateVectorRendering) {
|
||||||
if (view != null && view.isShown()) {
|
if (view != null) {
|
||||||
boolean nightMode = application.getDaynightHelper().isNightMode();
|
boolean nightMode = application.getDaynightHelper().isNightMode();
|
||||||
Boolean currentNightMode = this.nightMode;
|
Boolean currentNightMode = this.nightMode;
|
||||||
boolean forceUpdateVectorDrawing = currentNightMode != null && currentNightMode != nightMode;
|
boolean forceUpdateVectorDrawing = currentNightMode != null && currentNightMode != nightMode;
|
||||||
|
@ -869,6 +887,20 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
|
||||||
return currentViewport;
|
return currentViewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCurrentRotatedTileBox(net.osmand.data.RotatedTileBox tileBox) {
|
||||||
|
float rx = (float) tileBox.getCenterPixelX() / tileBox.getPixWidth();
|
||||||
|
float ry = (float) tileBox.getCenterPixelY() / tileBox.getPixHeight();
|
||||||
|
if (mapPosition == OsmandSettings.BOTTOM_CONSTANT) {
|
||||||
|
ry -= 0.35;
|
||||||
|
}
|
||||||
|
tileBox.setCenterLocation(rx, ry);
|
||||||
|
LatLon screenCenter = tileBox.getLatLonFromPixel(tileBox.getPixWidth() / 2f, tileBox.getPixHeight() / 2f);
|
||||||
|
mapRatioX = 0;
|
||||||
|
mapRatioY = 0;
|
||||||
|
setLatLon(screenCenter.getLatitude(), screenCenter.getLongitude());
|
||||||
|
currentViewport = tileBox;
|
||||||
|
}
|
||||||
|
|
||||||
public float getDensity() {
|
public float getDensity() {
|
||||||
return currentViewport.getDensity();
|
return currentViewport.getDensity();
|
||||||
}
|
}
|
||||||
|
|