kopia lustrzana https://github.com/sh123/codec2_talkie
216 wiersze
8.4 KiB
Java
216 wiersze
8.4 KiB
Java
package com.radio.codec2talkie.maps;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Matrix;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
|
import androidx.lifecycle.LiveData;
|
|
import androidx.lifecycle.ViewModelProvider;
|
|
import androidx.lifecycle.ViewModelStoreOwner;
|
|
|
|
import com.radio.codec2talkie.R;
|
|
import com.radio.codec2talkie.protocol.aprs.tools.AprsSymbolTable;
|
|
import com.radio.codec2talkie.protocol.position.Position;
|
|
import com.radio.codec2talkie.storage.position.PositionItemViewModel;
|
|
import com.radio.codec2talkie.storage.station.StationItem;
|
|
import com.radio.codec2talkie.storage.station.StationItemViewModel;
|
|
import com.radio.codec2talkie.tools.DateTools;
|
|
import com.radio.codec2talkie.tools.UnitTools;
|
|
|
|
import org.osmdroid.util.GeoPoint;
|
|
import org.osmdroid.views.MapView;
|
|
import org.osmdroid.views.overlay.Marker;
|
|
import org.osmdroid.views.overlay.Polygon;
|
|
import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
|
|
public class MapStations {
|
|
private static final String TAG = MapTrack.class.getSimpleName();
|
|
|
|
private final Context _context;
|
|
|
|
private final AprsSymbolTable _aprsSymbolTable;
|
|
|
|
private final PositionItemViewModel _positionItemViewModel;
|
|
private final ViewModelStoreOwner _owner;
|
|
private final MapView _mapView;
|
|
|
|
private final MarkerInfoWindow _infoWindow;
|
|
|
|
private LiveData<List<StationItem>> _stationItemLiveData;
|
|
private final StationItemViewModel _stationItemViewModel;
|
|
|
|
private final HashMap<String, Marker> _objectOverlayItems = new HashMap<>();
|
|
private final HashMap<String, Polygon> _objectOverlayRangeCircles = new HashMap<>();
|
|
|
|
private boolean _showCircles = false;
|
|
private boolean _showMoving = false;
|
|
|
|
private final MapTrack _activeTrack;
|
|
|
|
public MapStations(Context context, MapView mapView, ViewModelStoreOwner owner) {
|
|
_context = context;
|
|
_owner = owner;
|
|
_mapView = mapView;
|
|
_positionItemViewModel = new ViewModelProvider(_owner).get(PositionItemViewModel.class);
|
|
|
|
_aprsSymbolTable = AprsSymbolTable.getInstance(context);
|
|
_infoWindow = new MarkerInfoWindow(R.layout.bonuspack_bubble, _mapView);
|
|
_activeTrack = new MapTrack(_context, _mapView, _owner);
|
|
|
|
_stationItemViewModel = new ViewModelProvider(_owner).get(StationItemViewModel.class);
|
|
loadStations(_showMoving);
|
|
}
|
|
|
|
private void loadStations(boolean movingOnly) {
|
|
if (_stationItemLiveData != null)
|
|
_stationItemLiveData.removeObservers((LifecycleOwner) _owner);
|
|
removePositionMarkers();
|
|
_stationItemLiveData = _stationItemViewModel.getAllStationItems(movingOnly);
|
|
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
|
|
_stationItemLiveData.observe((LifecycleOwner) _owner, allStations -> {
|
|
Log.i(TAG, "add stations " + allStations.size());
|
|
for (StationItem station : allStations) {
|
|
//Log.i(TAG, "new position " + station.getSrcCallsign() + ">" +
|
|
// station.getDstCallsign() + " " + station.getLatitude() + " " + station.getLongitude());
|
|
// do not add items without coordinate
|
|
if (station.getMaidenHead() == null) continue;
|
|
if (addStationPositionIcon(station)) {
|
|
addRangeCircle(station);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void removePositionMarkers() {
|
|
for (Marker marker : _objectOverlayItems.values()) {
|
|
marker.remove(_mapView);
|
|
}
|
|
_objectOverlayItems.clear();
|
|
for (Polygon circle : _objectOverlayRangeCircles.values()) {
|
|
_mapView.getOverlays().remove(circle);
|
|
}
|
|
_objectOverlayRangeCircles.clear();
|
|
}
|
|
|
|
public void showMovingStations(boolean isMoving) {
|
|
_showMoving = isMoving;
|
|
loadStations(_showMoving);
|
|
}
|
|
|
|
public void showRangeCircles(boolean isVisible) {
|
|
_showCircles = isVisible;
|
|
for (Polygon polygon : _objectOverlayRangeCircles.values()) {
|
|
polygon.setVisible(isVisible);
|
|
}
|
|
}
|
|
|
|
private void addRangeCircle(StationItem group) {
|
|
if (group.getRangeMiles() == 0) return;
|
|
String callsign = group.getSrcCallsign();
|
|
Polygon polygon = null;
|
|
|
|
if (_objectOverlayRangeCircles.containsKey(callsign)) {
|
|
polygon = _objectOverlayRangeCircles.get(callsign);
|
|
assert polygon != null;
|
|
}
|
|
|
|
if (polygon == null) {
|
|
polygon = new Polygon();
|
|
polygon.setVisible(_showCircles);
|
|
|
|
Paint p = polygon.getOutlinePaint();
|
|
p.setStrokeWidth(1);
|
|
|
|
_mapView.getOverlayManager().add(0, polygon);
|
|
_objectOverlayRangeCircles.put(callsign, polygon);
|
|
}
|
|
ArrayList<GeoPoint> circlePoints = new ArrayList<>();
|
|
for (float f = 0; f < 360; f += 6) {
|
|
circlePoints.add(new GeoPoint(group.getLatitude(), group.getLongitude()).destinationPoint(1000 * UnitTools.milesToKilometers(group.getRangeMiles()), f));
|
|
}
|
|
polygon.setPoints(circlePoints);
|
|
}
|
|
|
|
private boolean addStationPositionIcon(StationItem group) {
|
|
String callsign = group.getSrcCallsign();
|
|
Marker marker = null;
|
|
|
|
String newTitle = DateTools.epochToIso8601(group.getTimestampEpoch()) + " " + callsign;
|
|
String newSnippet = getStatus(group);
|
|
|
|
// find old marker
|
|
if (_objectOverlayItems.containsKey(callsign)) {
|
|
marker = _objectOverlayItems.get(callsign);
|
|
assert marker != null;
|
|
|
|
// skip if unchanged
|
|
GeoPoint oldPosition = marker.getPosition();
|
|
if (oldPosition.getLatitude() == group.getLatitude() &&
|
|
oldPosition.getLongitude() == group.getLongitude() &&
|
|
marker.getTitle().equals(newTitle) &&
|
|
marker.getSnippet().equals(newSnippet)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// create new marker
|
|
if (marker == null) {
|
|
Bitmap bitmapInfoIcon = _aprsSymbolTable.bitmapFromSymbol(group.getSymbolCode(), true);
|
|
if (bitmapInfoIcon == null) return false;
|
|
|
|
// add marker
|
|
BitmapDrawable drawableText = group.drawLabelWithIcon(_context, 12);
|
|
BitmapDrawable drawableInfoIcon = new BitmapDrawable(_context.getResources(), bitmapInfoIcon);
|
|
marker = new Marker(_mapView);
|
|
marker.setId(callsign);
|
|
if (drawableText == null)
|
|
Log.e(TAG, "Cannot load icon for " + callsign);
|
|
else
|
|
marker.setIcon(drawableText);
|
|
marker.setImage(drawableInfoIcon);
|
|
marker.setOnMarkerClickListener((monitoredStationMarker, mapView) -> {
|
|
GeoPoint markerPoint = monitoredStationMarker.getPosition();
|
|
_infoWindow.open(monitoredStationMarker, new GeoPoint(markerPoint.getLatitude(), markerPoint.getLongitude()), 0, -64);
|
|
_activeTrack.drawForStationMarker(monitoredStationMarker);
|
|
return false;
|
|
});
|
|
_mapView.getOverlays().add(marker);
|
|
_objectOverlayItems.put(callsign, marker);
|
|
}
|
|
|
|
marker.setPosition(new GeoPoint(group.getLatitude(), group.getLongitude()));
|
|
marker.setTitle(newTitle);
|
|
marker.setSnippet(newSnippet);
|
|
|
|
return true;
|
|
}
|
|
|
|
private String getStatus(StationItem station) {
|
|
double range = UnitTools.milesToKilometers(station.getRangeMiles());
|
|
return String.format(Locale.US, "%s %s<br>%s %f %f<br>%03d° %03dkm/h %04dm %.2fkm<br>%s %s",
|
|
station.getDstCallsign(),
|
|
station.getDigipath(),
|
|
station.getMaidenHead(), station.getLatitude(), station.getLongitude(),
|
|
(int)station.getBearingDegrees(),
|
|
UnitTools.metersPerSecondToKilometersPerHour((int)station.getSpeedMetersPerSecond()),
|
|
(int)station.getAltitudeMeters(),
|
|
range == 0 ? UnitTools.milesToKilometers(Position.DEFAULT_RANGE_MILES): range,
|
|
station.getStatus(),
|
|
station.getComment());
|
|
}
|
|
}
|