Added mapillary sequence browser for non webgl view
This commit is contained in:
parent
42e15d2670
commit
d2d967a40a
6 changed files with 349 additions and 95 deletions
47
OsmAnd/res/layout/mapillary_static_image_view.xml
Normal file
47
OsmAnd/res/layout/mapillary_static_image_view.xml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:background="@android:color/transparent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/leftArrowButton"
|
||||||
|
android:layout_width="44dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_arrow_back"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/rightArrowButton"
|
||||||
|
android:layout_width="44dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_arrow_forward"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -1,7 +1,5 @@
|
||||||
package net.osmand.plus.mapillary;
|
package net.osmand.plus.mapillary;
|
||||||
|
|
||||||
import net.osmand.util.Algorithms;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class MapillaryImage {
|
public class MapillaryImage {
|
||||||
|
@ -41,10 +39,10 @@ public class MapillaryImage {
|
||||||
public boolean setData(Map userData) {
|
public boolean setData(Map userData) {
|
||||||
boolean res = true;
|
boolean res = true;
|
||||||
try {
|
try {
|
||||||
this.ca = (Double) userData.get("ca");
|
this.ca = ((Number) userData.get("ca")).doubleValue();
|
||||||
this.capturedAt = (Long) userData.get("captured_at");
|
this.capturedAt = ((Number) userData.get("captured_at")).longValue();
|
||||||
this.key = (String) userData.get("key");
|
this.key = (String) userData.get("key");
|
||||||
this.pano = ((Long) userData.get("pano")) == 1;
|
this.pano = ((Number) userData.get("pano")).intValue() == 1;
|
||||||
this.sKey = (String) userData.get("skey");
|
this.sKey = (String) userData.get("skey");
|
||||||
this.userKey = (String) userData.get("userkey");
|
this.userKey = (String) userData.get("userkey");
|
||||||
|
|
||||||
|
@ -78,7 +76,7 @@ public class MapillaryImage {
|
||||||
return pano;
|
return pano;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getsKey() {
|
public String getSKey() {
|
||||||
return sKey;
|
return sKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
|
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class MapillaryImageCard extends ImageCard {
|
public class MapillaryImageCard extends ImageCard {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.view.Gravity;
|
import android.support.v4.util.Pair;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -16,24 +16,48 @@ import android.webkit.ConsoleMessage;
|
||||||
import android.webkit.JavascriptInterface;
|
import android.webkit.JavascriptInterface;
|
||||||
import android.webkit.WebChromeClient;
|
import android.webkit.WebChromeClient;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import com.vividsolutions.jts.geom.Geometry;
|
||||||
|
import com.vividsolutions.jts.geom.Point;
|
||||||
|
|
||||||
import net.osmand.AndroidNetworkUtils;
|
import net.osmand.AndroidNetworkUtils;
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.data.GeometryTile;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.QuadPointDouble;
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.map.ITileSource;
|
||||||
|
import net.osmand.map.TileSourceManager;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.mapcontextmenu.MenuBuilder;
|
import net.osmand.plus.mapcontextmenu.MenuBuilder;
|
||||||
import net.osmand.plus.mapcontextmenu.builders.cards.dialogs.ContextMenuCardDialog;
|
import net.osmand.plus.mapcontextmenu.builders.cards.dialogs.ContextMenuCardDialog;
|
||||||
import net.osmand.plus.mapcontextmenu.builders.cards.dialogs.ContextMenuCardDialogFragment;
|
import net.osmand.plus.mapcontextmenu.builders.cards.dialogs.ContextMenuCardDialogFragment;
|
||||||
|
import net.osmand.plus.resources.ResourceManager;
|
||||||
import net.osmand.plus.views.OsmandMapTileView;
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static net.osmand.plus.mapillary.MapillaryVectorLayer.EXTENT;
|
||||||
|
import static net.osmand.plus.mapillary.MapillaryVectorLayer.TILE_ZOOM;
|
||||||
|
|
||||||
public class MapillaryImageDialog extends ContextMenuCardDialog {
|
public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
|
|
||||||
private static final String KEY_MAPILLARY_DIALOG_IMAGE_KEY = "key_mapillary_dialog_image_key";
|
private static final String KEY_MAPILLARY_DIALOG_IMAGE_KEY = "key_mapillary_dialog_image_key";
|
||||||
|
private static final String KEY_MAPILLARY_DIALOG_IMAGE_SKEY = "key_mapillary_dialog_image_skey";
|
||||||
private static final String KEY_MAPILLARY_DIALOG_IMAGE_URL = "key_mapillary_dialog_image_url";
|
private static final String KEY_MAPILLARY_DIALOG_IMAGE_URL = "key_mapillary_dialog_image_url";
|
||||||
private static final String KEY_MAPILLARY_DIALOG_VIEWER_URL = "key_mapillary_dialog_viewer_url";
|
private static final String KEY_MAPILLARY_DIALOG_VIEWER_URL = "key_mapillary_dialog_viewer_url";
|
||||||
private static final String KEY_MAPILLARY_DIALOG_LATLON = "key_mapillary_dialog_latlon";
|
private static final String KEY_MAPILLARY_DIALOG_LATLON = "key_mapillary_dialog_latlon";
|
||||||
|
@ -47,22 +71,31 @@ public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
private static final String WEBGL_ERROR_MESSAGE = "Error creating WebGL context";
|
private static final String WEBGL_ERROR_MESSAGE = "Error creating WebGL context";
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
|
private String sKey;
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
private String viewerUrl;
|
private String viewerUrl;
|
||||||
private LatLon latLon;
|
private LatLon latLon;
|
||||||
private double ca = Double.NaN;
|
private double ca = Double.NaN;
|
||||||
|
|
||||||
|
private View staticImageView;
|
||||||
|
private List<Pair<QuadPointDouble, GeometryTile>> tiles = new ArrayList<>();
|
||||||
|
private double fetchedTileLat = Double.NaN;
|
||||||
|
private double fetchedTileLon = Double.NaN;
|
||||||
|
private List<MapillaryImage> sequenceImages = new ArrayList<>();
|
||||||
|
private AtomicInteger downloadRequestNumber = new AtomicInteger();
|
||||||
|
|
||||||
public MapillaryImageDialog(@NonNull MapActivity mapActivity, @NonNull Bundle bundle) {
|
public MapillaryImageDialog(@NonNull MapActivity mapActivity, @NonNull Bundle bundle) {
|
||||||
super(mapActivity, CardDialogType.MAPILLARY);
|
super(mapActivity, CardDialogType.MAPILLARY);
|
||||||
restoreFields(bundle);
|
restoreFields(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapillaryImageDialog(MapActivity mapActivity, String key, String imageUrl, String viewerUrl, LatLon latLon, double ca,
|
public MapillaryImageDialog(MapActivity mapActivity, String key, String sKey, String imageUrl,
|
||||||
String title, String description) {
|
String viewerUrl, LatLon latLon, double ca, String title, String description) {
|
||||||
super(mapActivity, CardDialogType.MAPILLARY);
|
super(mapActivity, CardDialogType.MAPILLARY);
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
this.sKey = sKey;
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
this.viewerUrl = viewerUrl;
|
this.viewerUrl = viewerUrl;
|
||||||
this.latLon = latLon;
|
this.latLon = latLon;
|
||||||
|
@ -88,6 +121,7 @@ public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
public void saveMenu(Bundle bundle) {
|
public void saveMenu(Bundle bundle) {
|
||||||
super.saveMenu(bundle);
|
super.saveMenu(bundle);
|
||||||
bundle.putSerializable(KEY_MAPILLARY_DIALOG_IMAGE_KEY, key);
|
bundle.putSerializable(KEY_MAPILLARY_DIALOG_IMAGE_KEY, key);
|
||||||
|
bundle.putSerializable(KEY_MAPILLARY_DIALOG_IMAGE_SKEY, sKey);
|
||||||
bundle.putSerializable(KEY_MAPILLARY_DIALOG_IMAGE_URL, imageUrl);
|
bundle.putSerializable(KEY_MAPILLARY_DIALOG_IMAGE_URL, imageUrl);
|
||||||
bundle.putSerializable(KEY_MAPILLARY_DIALOG_VIEWER_URL, viewerUrl);
|
bundle.putSerializable(KEY_MAPILLARY_DIALOG_VIEWER_URL, viewerUrl);
|
||||||
bundle.putSerializable(KEY_MAPILLARY_DIALOG_LATLON, latLon);
|
bundle.putSerializable(KEY_MAPILLARY_DIALOG_LATLON, latLon);
|
||||||
|
@ -98,6 +132,7 @@ public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
protected void restoreFields(Bundle bundle) {
|
protected void restoreFields(Bundle bundle) {
|
||||||
super.restoreFields(bundle);
|
super.restoreFields(bundle);
|
||||||
this.key = bundle.getString(KEY_MAPILLARY_DIALOG_IMAGE_KEY);
|
this.key = bundle.getString(KEY_MAPILLARY_DIALOG_IMAGE_KEY);
|
||||||
|
this.sKey = bundle.getString(KEY_MAPILLARY_DIALOG_IMAGE_SKEY);
|
||||||
this.imageUrl = bundle.getString(KEY_MAPILLARY_DIALOG_IMAGE_URL);
|
this.imageUrl = bundle.getString(KEY_MAPILLARY_DIALOG_IMAGE_URL);
|
||||||
this.viewerUrl = bundle.getString(KEY_MAPILLARY_DIALOG_VIEWER_URL);
|
this.viewerUrl = bundle.getString(KEY_MAPILLARY_DIALOG_VIEWER_URL);
|
||||||
Object latLonObj = bundle.getSerializable(KEY_MAPILLARY_DIALOG_LATLON);
|
Object latLonObj = bundle.getSerializable(KEY_MAPILLARY_DIALOG_LATLON);
|
||||||
|
@ -218,46 +253,221 @@ public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
private View getStaticImageView() {
|
private View getStaticImageView() {
|
||||||
LinearLayout ll = new LinearLayout(getMapActivity());
|
View view = getMapActivity().getLayoutInflater().inflate(R.layout.mapillary_static_image_view, null);
|
||||||
ll.setClickable(true);
|
view.setClickable(true);
|
||||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||||
isPortrait() ? ViewGroup.LayoutParams.MATCH_PARENT : AndroidUtils.dpToPx(getMapActivity(), 360f),
|
isPortrait() ? ViewGroup.LayoutParams.MATCH_PARENT : AndroidUtils.dpToPx(getMapActivity(), 360f),
|
||||||
isPortrait() ? AndroidUtils.dpToPx(getMapActivity(), 270f) : ViewGroup.LayoutParams.MATCH_PARENT);
|
isPortrait() ? AndroidUtils.dpToPx(getMapActivity(), 270f) : ViewGroup.LayoutParams.MATCH_PARENT);
|
||||||
ll.setGravity(Gravity.CENTER);
|
view.setLayoutParams(lp);
|
||||||
ll.setLayoutParams(lp);
|
|
||||||
|
|
||||||
ProgressBar progressBar = new ProgressBar(getMapActivity());
|
view.findViewById(R.id.leftArrowButton).setOnClickListener(new View.OnClickListener() {
|
||||||
progressBar.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
@Override
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
public void onClick(View v) {
|
||||||
ll.addView(progressBar);
|
clickLeftArrowButton(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
view.findViewById(R.id.rightArrowButton).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
clickRightArrowButton(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ImageView imageView = new ImageView(getMapActivity());
|
staticImageView = view;
|
||||||
imageView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
||||||
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
|
||||||
ll.addView(imageView);
|
|
||||||
|
|
||||||
if (!Algorithms.isEmpty(imageUrl)) {
|
if (!Algorithms.isEmpty(imageUrl)) {
|
||||||
MenuBuilder.execute(new DownloadImageTask(progressBar, imageView));
|
MenuBuilder.execute(new DownloadImageTask(staticImageView, downloadRequestNumber.incrementAndGet(), downloadRequestNumber));
|
||||||
|
fetchSequence();
|
||||||
}
|
}
|
||||||
return ll;
|
updateArrowButtons();
|
||||||
|
return staticImageView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchSequence() {
|
||||||
|
if (Algorithms.isEmpty(sKey)) {
|
||||||
|
acquireSequenceKey();
|
||||||
|
}
|
||||||
|
if (!Algorithms.isEmpty(sKey)) {
|
||||||
|
acquireSequenceImages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acquireSequenceKey() {
|
||||||
|
fetchTiles();
|
||||||
|
for (Pair<QuadPointDouble, GeometryTile> pt : tiles) {
|
||||||
|
GeometryTile tile = pt.second;
|
||||||
|
for (Geometry g : tile.getData()) {
|
||||||
|
if (g instanceof Point && !g.isEmpty() && g.getUserData() != null && g.getUserData() instanceof HashMap) {
|
||||||
|
HashMap userData = (HashMap) g.getUserData();
|
||||||
|
String key = (String) userData.get("key");
|
||||||
|
if (this.key.equals(key)) {
|
||||||
|
sKey = (String) userData.get("skey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acquireSequenceImages() {
|
||||||
|
fetchTiles();
|
||||||
|
List<MapillaryImage> sequenceImages = new ArrayList<>();
|
||||||
|
if (!Algorithms.isEmpty(sKey)) {
|
||||||
|
double px, py;
|
||||||
|
for (Pair<QuadPointDouble, GeometryTile> pt : tiles) {
|
||||||
|
QuadPointDouble point = pt.first;
|
||||||
|
GeometryTile tile = pt.second;
|
||||||
|
for (Geometry g : tile.getData()) {
|
||||||
|
if (g instanceof Point && !g.isEmpty() && g.getUserData() != null && g.getUserData() instanceof HashMap) {
|
||||||
|
HashMap userData = (HashMap) g.getUserData();
|
||||||
|
String sKey = (String) userData.get("skey");
|
||||||
|
if (this.sKey.equals(sKey)) {
|
||||||
|
Point p = (Point) g;
|
||||||
|
px = p.getCoordinate().x / EXTENT;
|
||||||
|
py = p.getCoordinate().y / EXTENT;
|
||||||
|
MapillaryImage image = new MapillaryImage(
|
||||||
|
MapUtils.getLatitudeFromTile(TILE_ZOOM, point.y + py),
|
||||||
|
MapUtils.getLongitudeFromTile(TILE_ZOOM, point.x + px));
|
||||||
|
if (image.setData(userData)) {
|
||||||
|
sequenceImages.add(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(sequenceImages, new Comparator<MapillaryImage>() {
|
||||||
|
@Override
|
||||||
|
public int compare(MapillaryImage img1, MapillaryImage img2) {
|
||||||
|
return img1.getCapturedAt() < img2.getCapturedAt() ?
|
||||||
|
-1 : (img1.getCapturedAt() == img2.getCapturedAt() ? 0 : 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.sequenceImages = sequenceImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateArrowButtons() {
|
||||||
|
if (staticImageView != null) {
|
||||||
|
boolean showLeftButton = false;
|
||||||
|
boolean showRightButton = false;
|
||||||
|
if (sequenceImages.size() > 1 && !Algorithms.isEmpty(key)) {
|
||||||
|
showLeftButton = !sequenceImages.get(0).getKey().equals(key);
|
||||||
|
showRightButton = !sequenceImages.get(sequenceImages.size() - 1).getKey().equals(key);
|
||||||
|
}
|
||||||
|
staticImageView.findViewById(R.id.leftArrowButton)
|
||||||
|
.setVisibility(showLeftButton ? View.VISIBLE : View.GONE);
|
||||||
|
staticImageView.findViewById(R.id.rightArrowButton)
|
||||||
|
.setVisibility(showRightButton ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getImageIndex(String key) {
|
||||||
|
for (int i = 0; i < sequenceImages.size(); i++) {
|
||||||
|
if (sequenceImages.get(i).getKey().equals(key)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickLeftArrowButton(View v) {
|
||||||
|
fetchSequence();
|
||||||
|
if (sequenceImages != null) {
|
||||||
|
int index = getImageIndex(key);
|
||||||
|
if (index != -1 && index > 0) {
|
||||||
|
setImage(sequenceImages.get(index - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateArrowButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickRightArrowButton(View v) {
|
||||||
|
fetchSequence();
|
||||||
|
if (sequenceImages != null) {
|
||||||
|
int index = getImageIndex(key);
|
||||||
|
if (index != -1 && index < sequenceImages.size() - 1) {
|
||||||
|
setImage(sequenceImages.get(index + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateArrowButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setImage(MapillaryImage image) {
|
||||||
|
this.latLon = new LatLon(image.getLatitude(), image.getLongitude());
|
||||||
|
this.ca = image.getCa();
|
||||||
|
this.key = image.getKey();
|
||||||
|
this.imageUrl = MAPILLARY_HIRES_IMAGE_URL_TEMPLATE + image.getKey();
|
||||||
|
this.viewerUrl = MAPILLARY_VIEWER_URL_TEMPLATE + image.getKey();
|
||||||
|
MenuBuilder.execute(new DownloadImageTask(staticImageView, downloadRequestNumber.incrementAndGet(), downloadRequestNumber));
|
||||||
|
setImageLocation(latLon, ca, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetchTiles() {
|
||||||
|
RotatedTileBox tileBox = getMapActivity().getMapView().getCurrentRotatedTileBox().copy();
|
||||||
|
if (fetchedTileLat == tileBox.getLatitude() && fetchedTileLon == tileBox.getLongitude()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ITileSource map = TileSourceManager.getMapillaryVectorSource();
|
||||||
|
int nzoom = tileBox.getZoom();
|
||||||
|
if (nzoom < map.getMinimumZoomSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResourceManager mgr = getMapActivity().getMyApplication().getResourceManager();
|
||||||
|
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);
|
||||||
|
int dzoom = nzoom - TILE_ZOOM;
|
||||||
|
int div = (int) Math.pow(2.0, dzoom);
|
||||||
|
|
||||||
|
Map<String, Pair<QuadPointDouble, GeometryTile>> tiles = new HashMap<>();
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
for (int j = 0; j < height; j++) {
|
||||||
|
int tileX = (left + i) / div;
|
||||||
|
int tileY = (top + j) / div;
|
||||||
|
String tileId = mgr.calculateTileId(map, tileX, tileY, TILE_ZOOM);
|
||||||
|
Pair<QuadPointDouble, GeometryTile> p = tiles.get(tileId);
|
||||||
|
if (p == null) {
|
||||||
|
GeometryTile tile = null;
|
||||||
|
// asking tile image async
|
||||||
|
boolean imgExist = mgr.tileExistOnFileSystem(tileId, map, tileX, tileY, TILE_ZOOM);
|
||||||
|
if (imgExist) {
|
||||||
|
tile = mgr.getGeometryTilesCache().getTileForMapAsync(tileId, map, tileX, tileY, TILE_ZOOM, false);
|
||||||
|
}
|
||||||
|
if (tile != null) {
|
||||||
|
tiles.put(tileId, new Pair<>(new QuadPointDouble(tileX, tileY), tile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchedTileLat = tileBox.getLatitude();
|
||||||
|
fetchedTileLon = tileBox.getLongitude();
|
||||||
|
this.tiles = new ArrayList<>(tiles.values());
|
||||||
|
}
|
||||||
|
|
||||||
public static MapillaryImageDialog show(MapActivity mapActivity, String key, String imageUrl,
|
public static MapillaryImageDialog show(MapActivity mapActivity, String key, String imageUrl,
|
||||||
String viewerUrl, LatLon latLon, double ca,
|
String viewerUrl, LatLon latLon, double ca,
|
||||||
String title, String description) {
|
String title, String description) {
|
||||||
MapillaryImageDialog dialog = new MapillaryImageDialog(mapActivity, key, imageUrl, viewerUrl,
|
MapillaryImageDialog dialog = new MapillaryImageDialog(mapActivity, key, null, imageUrl,
|
||||||
latLon, ca, title, description);
|
viewerUrl, latLon, ca, title, description);
|
||||||
ContextMenuCardDialogFragment.showInstance(dialog);
|
ContextMenuCardDialogFragment.showInstance(dialog);
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MapillaryImageDialog show(MapActivity mapActivity, double latitude, double longitude,
|
public static MapillaryImageDialog show(MapActivity mapActivity, double latitude, double longitude,
|
||||||
String key, double ca, String title, String description) {
|
String key, String sKey, double ca, String title, String description) {
|
||||||
String imageUrl = MAPILLARY_HIRES_IMAGE_URL_TEMPLATE + key;
|
String imageUrl = MAPILLARY_HIRES_IMAGE_URL_TEMPLATE + key;
|
||||||
String viewerUrl = MAPILLARY_VIEWER_URL_TEMPLATE + key;
|
String viewerUrl = MAPILLARY_VIEWER_URL_TEMPLATE + key;
|
||||||
LatLon latLon = new LatLon(latitude, longitude);
|
LatLon latLon = new LatLon(latitude, longitude);
|
||||||
MapillaryImageDialog dialog = new MapillaryImageDialog(mapActivity, key, imageUrl, viewerUrl,
|
MapillaryImageDialog dialog = new MapillaryImageDialog(mapActivity, key, sKey, imageUrl, viewerUrl,
|
||||||
latLon, ca, title, description);
|
latLon, ca, title, description);
|
||||||
ContextMenuCardDialogFragment.showInstance(dialog);
|
ContextMenuCardDialogFragment.showInstance(dialog);
|
||||||
return dialog;
|
return dialog;
|
||||||
|
@ -265,30 +475,57 @@ public class MapillaryImageDialog extends ContextMenuCardDialog {
|
||||||
|
|
||||||
private class DownloadImageTask extends AsyncTask<Void, Void, Bitmap> {
|
private class DownloadImageTask extends AsyncTask<Void, Void, Bitmap> {
|
||||||
|
|
||||||
|
private int request;
|
||||||
|
private AtomicInteger downloadRequestNumber;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private ImageView imageView;
|
private ImageView imageView;
|
||||||
|
|
||||||
public DownloadImageTask(ProgressBar progressBar, ImageView imageView) {
|
public DownloadImageTask(View staticImageView, int request, AtomicInteger downloadRequestNumber) {
|
||||||
|
if (staticImageView != null) {
|
||||||
|
this.request = request;
|
||||||
|
this.downloadRequestNumber = downloadRequestNumber;
|
||||||
|
ProgressBar progressBar = (ProgressBar) staticImageView.findViewById(R.id.progressBar);
|
||||||
|
ImageView imageView = (ImageView) staticImageView.findViewById(R.id.imageView);
|
||||||
this.progressBar = progressBar;
|
this.progressBar = progressBar;
|
||||||
this.imageView = imageView;
|
this.imageView = imageView;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
|
if (progressBar != null) {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Bitmap doInBackground(Void... params) {
|
protected Bitmap doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
if (isValidRequest()) {
|
||||||
return AndroidNetworkUtils.downloadImage(getMapActivity().getMyApplication(), imageUrl);
|
return AndroidNetworkUtils.downloadImage(getMapActivity().getMyApplication(), imageUrl);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Bitmap bitmap) {
|
protected void onPostExecute(Bitmap bitmap) {
|
||||||
|
if (isValidRequest()) {
|
||||||
|
if (progressBar != null) {
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
if (bitmap != null) {
|
}
|
||||||
|
if (bitmap != null && imageView != null) {
|
||||||
imageView.setImageDrawable(new BitmapDrawable(getMapActivity().getResources(), bitmap));
|
imageView.setImageDrawable(new BitmapDrawable(getMapActivity().getResources(), bitmap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isValidRequest() {
|
||||||
|
return request == downloadRequestNumber.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ public class MapillaryMenuController extends MenuController {
|
||||||
public boolean setActive(boolean active) {
|
public boolean setActive(boolean active) {
|
||||||
if (image != null && getMenuType() == MenuType.STANDARD) {
|
if (image != null && getMenuType() == MenuType.STANDARD) {
|
||||||
MapillaryImageDialog.show(getMapActivity(), image.getLatitude(), image.getLongitude(),
|
MapillaryImageDialog.show(getMapActivity(), image.getLatitude(), image.getLongitude(),
|
||||||
image.getKey(), image.getCa(), getMapActivity().getMyApplication().getString(R.string.mapillary), null);
|
image.getKey(), image.getSKey(), image.getCa(), getMapActivity().getMyApplication().getString(R.string.mapillary), null);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return super.setActive(active);
|
return super.setActive(active);
|
||||||
|
|
|
@ -28,10 +28,8 @@ import net.osmand.plus.resources.ResourceManager;
|
||||||
import net.osmand.plus.views.ContextMenuLayer.IContextMenuProvider;
|
import net.osmand.plus.views.ContextMenuLayer.IContextMenuProvider;
|
||||||
import net.osmand.plus.views.MapTileLayer;
|
import net.osmand.plus.views.MapTileLayer;
|
||||||
import net.osmand.plus.views.OsmandMapTileView;
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.util.Algorithms;
|
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -39,8 +37,8 @@ import java.util.Map.Entry;
|
||||||
|
|
||||||
class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, IContextMenuProvider {
|
class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, IContextMenuProvider {
|
||||||
|
|
||||||
private static final int TILE_ZOOM = 14;
|
public static final int TILE_ZOOM = 14;
|
||||||
private static final double EXTENT = 4096.0;
|
public static final double EXTENT = 4096.0;
|
||||||
|
|
||||||
private LatLon selectedImageLocation;
|
private LatLon selectedImageLocation;
|
||||||
private Float selectedImageCameraAngle;
|
private Float selectedImageCameraAngle;
|
||||||
|
@ -70,7 +68,7 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
|
|
||||||
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location);
|
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location);
|
||||||
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location_view_angle);
|
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location_view_angle);
|
||||||
point = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_note_small);
|
point = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_photo_dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,6 +121,8 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
int top = (int) Math.floor(tilesRect.top + ellipticTileCorrection);
|
int top = (int) Math.floor(tilesRect.top + ellipticTileCorrection);
|
||||||
int width = (int) Math.ceil(tilesRect.right - left);
|
int width = (int) Math.ceil(tilesRect.right - left);
|
||||||
int height = (int) Math.ceil(tilesRect.bottom + ellipticTileCorrection - top);
|
int height = (int) Math.ceil(tilesRect.bottom + ellipticTileCorrection - top);
|
||||||
|
int dzoom = nzoom - TILE_ZOOM;
|
||||||
|
int div = (int) Math.pow(2.0, dzoom);
|
||||||
|
|
||||||
boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null) &&
|
boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null) &&
|
||||||
settings.USE_INTERNET_TO_DOWNLOAD_TILES.get() && settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet();
|
settings.USE_INTERNET_TO_DOWNLOAD_TILES.get() && settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet();
|
||||||
|
@ -131,23 +131,9 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
Map<QuadPointDouble, Map> visiblePoints = new HashMap<>();
|
Map<QuadPointDouble, Map> visiblePoints = new HashMap<>();
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
for (int j = 0; j < height; j++) {
|
for (int j = 0; j < height; j++) {
|
||||||
int leftPlusI = left + i;
|
int tileX = (left + i) / div;
|
||||||
int topPlusJ = top + j;
|
int tileY = (top + j) / div;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
int tileX = leftPlusI;
|
|
||||||
int tileY = topPlusJ;
|
|
||||||
|
|
||||||
int dzoom = nzoom - TILE_ZOOM;
|
|
||||||
int div = (int) Math.pow(2.0, dzoom);
|
|
||||||
tileX /= div;
|
|
||||||
tileY /= div;
|
|
||||||
String tileId = mgr.calculateTileId(map, tileX, tileY, TILE_ZOOM);
|
String tileId = mgr.calculateTileId(map, tileX, tileY, TILE_ZOOM);
|
||||||
GeometryTile tile = tiles.get(tileId);
|
GeometryTile tile = tiles.get(tileId);
|
||||||
if (tile == null) {
|
if (tile == null) {
|
||||||
|
@ -173,22 +159,6 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
|
|
||||||
protected void drawPoints(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY,
|
protected void drawPoints(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY,
|
||||||
GeometryTile tile, Map<QuadPointDouble, Map> visiblePoints) {
|
GeometryTile tile, Map<QuadPointDouble, Map> visiblePoints) {
|
||||||
Map<String, List<Point>> seqMap = new HashMap<>();
|
|
||||||
for (Geometry g : tile.getData()) {
|
|
||||||
if (g instanceof Point && !g.isEmpty() && g.getUserData() != null && g.getUserData() instanceof HashMap) {
|
|
||||||
HashMap userData = (HashMap) g.getUserData();
|
|
||||||
String seq = (String) userData.get("skey");
|
|
||||||
if (!Algorithms.isEmpty(seq)) {
|
|
||||||
List<Point> pointList = seqMap.get(seq);
|
|
||||||
if (pointList == null) {
|
|
||||||
pointList = new ArrayList<>();
|
|
||||||
seqMap.put(seq, pointList);
|
|
||||||
}
|
|
||||||
pointList.add((Point) g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dzoom = tileBox.getZoom() - TILE_ZOOM;
|
int dzoom = tileBox.getZoom() - TILE_ZOOM;
|
||||||
int mult = (int) Math.pow(2.0, dzoom);
|
int mult = (int) Math.pow(2.0, dzoom);
|
||||||
QuadRect tileBounds = tileBox.getTileBounds();
|
QuadRect tileBounds = tileBox.getTileBounds();
|
||||||
|
@ -198,14 +168,11 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
float ph = point.getHeight();
|
float ph = point.getHeight();
|
||||||
float pwd = pw / 2;
|
float pwd = pw / 2;
|
||||||
float phd = ph / 2;
|
float phd = ph / 2;
|
||||||
//float lx = -1000f;
|
|
||||||
//float ly = -1000f;
|
|
||||||
//float pwm = pw * 2;
|
|
||||||
//float phm = ph * 2;
|
|
||||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||||
for (List<Point> points : seqMap.values()) {
|
|
||||||
for (int i = 0; i < points.size(); i++) {
|
for (Geometry g : tile.getData()) {
|
||||||
Point p = points.get(i);
|
if (g instanceof Point && !g.isEmpty() && g.getUserData() != null && g.getUserData() instanceof HashMap) {
|
||||||
|
Point p = (Point) g;
|
||||||
px = p.getCoordinate().x / EXTENT;
|
px = p.getCoordinate().x / EXTENT;
|
||||||
py = p.getCoordinate().y / EXTENT;
|
py = p.getCoordinate().y / EXTENT;
|
||||||
tx = (tileX + px) * mult;
|
tx = (tileX + px) * mult;
|
||||||
|
@ -213,14 +180,8 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
if (tileBounds.contains(tx, ty, tx, ty)) {
|
if (tileBounds.contains(tx, ty, tx, ty)) {
|
||||||
x = tileBox.getPixXFromTile(tileX + px, tileY + py, TILE_ZOOM);
|
x = tileBox.getPixXFromTile(tileX + px, tileY + py, TILE_ZOOM);
|
||||||
y = tileBox.getPixYFromTile(tileX + px, tileY + py, TILE_ZOOM);
|
y = tileBox.getPixYFromTile(tileX + px, tileY + py, TILE_ZOOM);
|
||||||
//QuadRect rNow = calculateRect(x, y, pwm, phm);
|
|
||||||
//QuadRect rLast = calculateRect(lx, ly, pw, ph);
|
|
||||||
//if (!QuadRect.intersects(rLast, rNow) || i == points.size() - 1) {
|
|
||||||
canvas.drawBitmap(point, x - pwd, y - phd, paintPoint);
|
canvas.drawBitmap(point, x - pwd, y - phd, paintPoint);
|
||||||
visiblePoints.put(new QuadPointDouble(tileX + px, tileY + py), (Map) p.getUserData());
|
visiblePoints.put(new QuadPointDouble(tileX + px, tileY + py), (Map) p.getUserData());
|
||||||
//lx = x;
|
|
||||||
//ly = y;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,24 +303,34 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, ICont
|
||||||
private void getImagesFromPoint(RotatedTileBox tb, PointF point, List<? super MapillaryImage> images) {
|
private void getImagesFromPoint(RotatedTileBox tb, PointF point, List<? super MapillaryImage> images) {
|
||||||
Map<QuadPointDouble, Map> points = this.visiblePoints;
|
Map<QuadPointDouble, Map> points = this.visiblePoints;
|
||||||
if (points != null) {
|
if (points != null) {
|
||||||
int ex = (int) point.x;
|
float ex = point.x;
|
||||||
int ey = (int) point.y;
|
float ey = point.y;
|
||||||
final int rp = getRadius(tb);
|
final int rp = getRadius(tb);
|
||||||
int radius = rp * 3 / 2;
|
int radius = rp * 3 / 2;
|
||||||
float x, y;
|
float x, y;
|
||||||
|
double minSqDist = Double.NaN;
|
||||||
|
double sqDist;
|
||||||
|
MapillaryImage img = null;
|
||||||
for (Entry<QuadPointDouble, Map> entry : points.entrySet()) {
|
for (Entry<QuadPointDouble, Map> entry : points.entrySet()) {
|
||||||
x = tb.getPixXFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
|
x = tb.getPixXFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
|
||||||
y = tb.getPixYFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
|
y = tb.getPixYFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
|
||||||
if (Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius) {
|
if (Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius) {
|
||||||
MapillaryImage img = new MapillaryImage(MapUtils.getLatitudeFromTile(TILE_ZOOM, entry.getKey().y),
|
sqDist = (x - ex) * (x - ex) + (y - ey) * (y - ey);
|
||||||
|
if (img == null || minSqDist > sqDist) {
|
||||||
|
minSqDist = sqDist;
|
||||||
|
img = new MapillaryImage(MapUtils.getLatitudeFromTile(TILE_ZOOM, entry.getKey().y),
|
||||||
MapUtils.getLongitudeFromTile(TILE_ZOOM, entry.getKey().x));
|
MapUtils.getLongitudeFromTile(TILE_ZOOM, entry.getKey().x));
|
||||||
if (img.setData(entry.getValue())) {
|
if (!img.setData(entry.getValue())) {
|
||||||
|
img = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (img != null) {
|
||||||
images.add(img);
|
images.add(img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRadius(RotatedTileBox tb) {
|
public int getRadius(RotatedTileBox tb) {
|
||||||
int r;
|
int r;
|
||||||
|
|
Loading…
Reference in a new issue