Back to project page geoar-app.
The source code is released under:
Apache License
If you think the Android project geoar-app listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/** * Copyright 2012 52North Initiative for Geospatial Open Source Software GmbH */* w ww.jav a 2 s . c o m*/ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.n52.geoar.map.view; import java.util.ArrayList; import java.util.List; import org.mapsforge.android.maps.MapView; import org.mapsforge.android.maps.Projection; import org.mapsforge.core.GeoPoint; import org.n52.geoar.R; import org.n52.geoar.alg.proj.MercatorRect; import org.n52.geoar.exception.UnsupportedGeometryType; import org.n52.geoar.map.view.overlay.DataSourcesOverlay; import org.n52.geoar.map.view.overlay.OverlayType; import org.n52.geoar.map.view.overlay.PointOverlayType; import org.n52.geoar.map.view.overlay.PolylineOverlayType; import org.n52.geoar.newdata.DataCache.Cancelable; import org.n52.geoar.newdata.DataCache.DataSourceErrorType; import org.n52.geoar.newdata.DataCache.GetDataBoundsCallback; import org.n52.geoar.newdata.DataSourceInstanceHolder; import org.n52.geoar.newdata.DataSourceInstanceHolder.DataSourceSettingsChangedListener; import org.n52.geoar.newdata.SpatialEntity2; import org.n52.geoar.newdata.Visualization.MapVisualization.ItemVisualization; import org.n52.geoar.view.InfoView; import org.n52.geoar.view.geoar.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import android.graphics.Point; import android.os.Handler; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Polygon; /** * @author Holger Hopmann * @author Arne de Wall * */ public class DataSourceOverlayHandler implements DataSourceSettingsChangedListener { /** * An instance of this class describes a measurement request order which * will be performed in the future, just to make sure that the user will * stop navigating through the map. It ensures that it wont alter this * overlays data if it got canceled before * */ private class UpdateHolder implements Runnable { private boolean canceled; private MercatorRect bounds; // protected MapView mapView; private Cancelable requestHolder; private GetDataBoundsCallback callback = new GetDataBoundsCallback() { @Override public void onProgressUpdate(int progress, int maxProgress) { InfoView.setProgressTitle(R.string.requesting_data, UpdateHolder.this); // TODO InfoView.setProgress(progress, maxProgress, UpdateHolder.this); // if (infoHandler != null) { // String stepTitle = ""; // switch(step){ // case InfoView.STEP_CLUSTERING: // stepTitle = "Clustering"; // break; // case InfoView.STEP_INTERPOLATION: // stepTitle = "Interpolation"; // break; // case MeasurementManager.STEP_REQUEST: // stepTitle = "Messungsabfrage"; // break; // // } // infoHandler.setProgressTitle(stepTitle, UpdateHolder.this); // infoHandler.setProgress(progress, maxProgress, // UpdateHolder.this); // } } @Override public void onAbort(MercatorRect bounds, DataSourceErrorType reason) { canceled = true; InfoView.clearProgress(UpdateHolder.this); if (reason == DataSourceErrorType.CONNECTION) { InfoView.setStatus(R.string.connection_error, 5000, UpdateHolder.this); } else if (reason == DataSourceErrorType.UNKNOWN) { InfoView.setStatus(R.string.unknown_error, 5000, UpdateHolder.this); } } @Override public void onReceiveDataUpdate(MercatorRect bounds, List<? extends SpatialEntity2<? extends Geometry>> data) { if (!canceled) { synchronized (updateLock) { List<OverlayType<? extends Geometry>> overlayItems = new ArrayList<OverlayType<? extends Geometry>>(); List<ItemVisualization> visualizations = dataSourceInstance .getParent().getVisualizations() .getCheckedItems(ItemVisualization.class); for (SpatialEntity2<? extends Geometry> entity : data) { Geometry geometry = entity.getGeometry(); for (ItemVisualization visualization : visualizations) { OverlayType<? extends Geometry> overlayType; if (geometry instanceof LineString) { overlayItems.add(new PolylineOverlayType( (LineString) entity.getGeometry(), visualization.getTitle(entity), visualization .getDescription(entity), entity, visualization, dataSourceInstance)); } else if (geometry instanceof com.vividsolutions.jts.geom.Point) { overlayItems .add(new PointOverlayType( (com.vividsolutions.jts.geom.Point) (entity .getGeometry()), visualization .getTitle(entity), visualization .getDescription(entity), visualization .getDrawableForEntity(entity), entity, visualization, dataSourceInstance)); } else if (geometry instanceof Polygon){ } else { // FIXME handle this gracefully try { throw new UnsupportedGeometryType(geometry.getClass().toString()); } catch (UnsupportedGeometryType e) { e.printStackTrace(); } } } } overlay.setOverlayItems(overlayItems, dataSourceInstance); // data received, now this object represents // the current data currentUpdate = UpdateHolder.this; nextUpdate = null; } } } }; private UpdateHolder(MercatorRect bounds) { this.bounds = bounds; } public void cancel() { synchronized (updateLock) { if (requestHolder != null) { requestHolder.cancel(); } canceled = true; } } @Override public void run() { synchronized (updateLock) { if (!canceled) { if (bounds.zoom >= dataSourceInstance.getParent() .getMinZoomLevel()) { // Just runs if zoom is in range requestHolder = dataSourceInstance.getDataCache() .getDataByBBox(bounds, callback, false); } else { InfoView.setStatus(R.string.not_zoomed_in, 5000, this); } } } } } private UpdateHolder currentUpdate; private UpdateHolder nextUpdate; private Handler updateHandler = new Handler(); private Object updateLock = new Object(); private DataSourcesOverlay overlay; private DataSourceInstanceHolder dataSourceInstance; private static final Logger LOG = LoggerFactory .getLogger(DataSourceOverlayHandler.class); public DataSourceOverlayHandler(DataSourcesOverlay overlay, DataSourceInstanceHolder dataSource) { this.overlay = overlay; this.dataSourceInstance = dataSource; dataSource.addOnSettingsChangedListener(this); } public DataSourceInstanceHolder getDataSource() { return dataSourceInstance; } public void clear() { synchronized (updateLock) { LOG.info(dataSourceInstance.getName() + " clearing map overlay"); cancel(); overlay.clear(dataSourceInstance); } } public void cancel() { synchronized (updateLock) { if (nextUpdate != null) { updateHandler.removeCallbacks(nextUpdate); nextUpdate.cancel(); nextUpdate = null; LOG.info(dataSourceInstance.getName() + " map overlay canceled"); } } } /** * Updates the interpolation data of this overlay. Computes the current * bounds and compares them to the existing interpolation data. Data will be * requested in future if needed * * @param mapView * @param force * request data without verification */ public void updateOverlay(MapView mapView, boolean force) { byte zoom = mapView.getMapPosition().getZoomLevel(); zoom = (byte) Math.min(zoom, dataSourceInstance.getParent() .getMaxZoomLevel()); Projection proj = mapView.getProjection(); GeoPoint gPoint = (GeoPoint) proj.fromPixels(0, 0); if (gPoint == null) return; // mapview not yet displayed Point point = proj.toPoint(gPoint, null, zoom); // int x = (int) MercatorProj.transformLonToPixelX( // gPoint.getLongitudeE6() / 1E6f, zoom); // int y = (int) MercatorProj.transformLatToPixelY( // gPoint.getLatitudeE6() / 1E6f, zoom); synchronized (updateLock) { MercatorRect newBounds = new MercatorRect(point.x, point.y, point.x + mapView.getWidth(), point.y + mapView.getHeight(), zoom); int updateDelay = -1; if (currentUpdate == null || !currentUpdate.bounds.contains(newBounds)) { // no data or data outside viewport updateDelay = 1000; } if (currentUpdate != null && currentUpdate.bounds.contains(newBounds) && zoom != currentUpdate.bounds.zoom) { // data inside viewport, but different zoom updateDelay = 5000; } if (updateDelay >= 0 || force) { // Queue next update newBounds.expand(Settings.BUFFER_MAPINTERPOLATION, Settings.BUFFER_MAPINTERPOLATION); if (nextUpdate != null) { nextUpdate.cancel(); updateHandler.removeCallbacks(nextUpdate); } nextUpdate = new UpdateHolder(newBounds); updateHandler.postDelayed(nextUpdate, Math.max(0, updateDelay)); LOG.debug("Overlay Update in " + updateDelay / 1000 + " s"); } } } public void destroy() { clear(); dataSourceInstance.removeOnSettingsChangedListener(this); } @Override public void onDataSourceSettingsChanged() { if (nextUpdate != null) { // There is already an update pending return; } if (currentUpdate != null) { // repeat last update with new settings updateHandler.removeCallbacks(currentUpdate); updateHandler.post(currentUpdate); } } }