mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-05 11:53:53 +00:00
add moving variant of full-canvas, to support auto-zoom on raceboard;
This commit is contained in:
1 parent
419daa7a8e
commit
89426cb773
6 files changed
+111
-16
No files matched your search
+6
-2
@@ -268,6 +268,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
*/
|
||||
private LatLngBounds currentMapBounds;
|
||||
|
||||
private int currentZoomLevel;
|
||||
|
||||
private WindStreamletsRaceboardOverlay streamletOverlay;
|
||||
private final boolean showViewStreamlets;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
@@ -382,10 +384,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
infoOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
}
|
||||
if (streamletOverlay != null) {
|
||||
streamletOverlay.onBoundsChanged();
|
||||
int newZoomLevel = map.getZoom();
|
||||
if ((streamletOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
|
||||
streamletOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
|
||||
}
|
||||
currentMapBounds = map.getBounds();
|
||||
currentZoomLevel = newZoomLevel;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@ import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.simulator.StreamletParameters;
|
||||
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
|
||||
import com.sap.sailing.gwt.ui.simulator.racemap.MovingCanvasOverlay;
|
||||
import com.sap.sailing.gwt.ui.simulator.streamlets.Swarm;
|
||||
import com.sap.sailing.gwt.ui.simulator.streamlets.VectorField;
|
||||
import com.sap.sailing.gwt.ui.simulator.streamlets.WindInfoForRaceVectorField;
|
||||
@@ -38,7 +38,7 @@ import com.sap.sse.gwt.client.player.Timer;
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class WindStreamletsRaceboardOverlay extends FullCanvasOverlay {
|
||||
public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay {
|
||||
public static final String LODA_WIND_STREAMLET_DATA_CATEGORY = "loadWindStreamletData";
|
||||
private static final int animationIntervalMillis = 40;
|
||||
private static final long RESOLUTION_IN_MILLIS = 5000;
|
||||
@@ -220,9 +220,9 @@ public class WindStreamletsRaceboardOverlay extends FullCanvasOverlay {
|
||||
protected void drawCenterChanged() {
|
||||
}
|
||||
|
||||
public void onBoundsChanged() {
|
||||
public void onBoundsChanged(boolean zoomChanged) {
|
||||
if (swarm != null) {
|
||||
swarm.onBoundsChanged();
|
||||
swarm.onBoundsChanged(zoomChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -477,7 +477,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
|
||||
public void execute() {
|
||||
if (windStreamletsCanvasOverlay.getSwarm() != null) {
|
||||
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged();
|
||||
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+10
-2
@@ -13,6 +13,7 @@ import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
import com.sap.sailing.gwt.ui.simulator.streamlets.Vector;
|
||||
|
||||
/**
|
||||
* This class extends @CanvasOverlayV3 to provide the functionality that the canvas always covers the
|
||||
@@ -25,10 +26,12 @@ import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
|
||||
public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements RequiresResize {
|
||||
|
||||
/** the x coordinate where the canvas is placed */
|
||||
private double widgetPosLeft = 0;
|
||||
protected double widgetPosLeft = 0;
|
||||
|
||||
/** the y coordinate where the canvas element is placed */
|
||||
private double widgetPosTop = 0;
|
||||
protected double widgetPosTop = 0;
|
||||
|
||||
protected Vector diffPx;
|
||||
|
||||
public String pointColor = "Red";
|
||||
public String textColor = "Black";
|
||||
@@ -43,6 +46,7 @@ public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements Requi
|
||||
drawCenterChanged();
|
||||
};
|
||||
});
|
||||
diffPx = new Vector(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,4 +272,8 @@ public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements Requi
|
||||
public void setWidgetPosTop(double widgetPosTop) {
|
||||
this.widgetPosTop = widgetPosTop;
|
||||
}
|
||||
|
||||
public Vector getDiffPx() {
|
||||
return diffPx;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.sap.sailing.gwt.ui.simulator.racemap;
|
||||
|
||||
import com.google.gwt.canvas.dom.client.Context2d;
|
||||
import com.google.gwt.canvas.dom.client.ImageData;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.Point;
|
||||
import com.sap.sailing.gwt.ui.simulator.streamlets.Vector;
|
||||
|
||||
/**
|
||||
* This class extends @FullCanvasOverlay to provide the functionality that the canvas covers the
|
||||
* full viewable area of the map and moves previously drawn content according to drag and zoom
|
||||
*
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public abstract class MovingCanvasOverlay extends FullCanvasOverlay {
|
||||
|
||||
private LatLng ne;
|
||||
private LatLng sw;
|
||||
|
||||
public MovingCanvasOverlay(MapWidget map, int zIndex) {
|
||||
super(map, zIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCanvasSettings() {
|
||||
int canvasWidth = getMap().getDiv().getClientWidth();
|
||||
int canvasHeight = getMap().getDiv().getClientHeight();
|
||||
|
||||
Context2d ctxt = canvas.getContext2d();
|
||||
ImageData canvasContent = ctxt.getImageData(0, 0, canvas.getElement().getClientWidth(), canvas.getElement().getClientHeight());
|
||||
canvas.setWidth(String.valueOf(canvasWidth));
|
||||
canvas.setHeight(String.valueOf(canvasHeight));
|
||||
canvas.setCoordinateSpaceWidth(canvasWidth);
|
||||
canvas.setCoordinateSpaceHeight(canvasHeight);
|
||||
|
||||
Point oldSWpx = mapProjection.fromLatLngToDivPixel(sw);
|
||||
Point oldNEpx = mapProjection.fromLatLngToDivPixel(ne);
|
||||
|
||||
sw = getMap().getBounds().getSouthWest();
|
||||
ne = getMap().getBounds().getNorthEast();
|
||||
Point swPx = mapProjection.fromLatLngToDivPixel(sw);
|
||||
Point nePx = mapProjection.fromLatLngToDivPixel(ne);
|
||||
widgetPosLeft = Math.min(swPx.getX(), nePx.getX());
|
||||
widgetPosTop = Math.min(swPx.getY(), nePx.getY());
|
||||
|
||||
double oldLeftpx;
|
||||
double oldToppx;
|
||||
if (oldSWpx == null) {
|
||||
oldLeftpx = widgetPosLeft;
|
||||
oldToppx = widgetPosTop;
|
||||
} else {
|
||||
oldLeftpx = Math.min(oldSWpx.getX(), oldNEpx.getX());
|
||||
oldToppx = Math.min(oldSWpx.getY(), oldNEpx.getY());
|
||||
}
|
||||
|
||||
diffPx = new Vector(oldLeftpx - widgetPosLeft, oldToppx - widgetPosTop);
|
||||
|
||||
ctxt = canvas.getContext2d();
|
||||
ctxt.putImageData(canvasContent, diffPx.x, diffPx.y);
|
||||
|
||||
setCanvasPosition(getWidgetPosLeft(), getWidgetPosTop());
|
||||
}
|
||||
|
||||
}
|
||||
+24
-7
@@ -24,6 +24,9 @@ public class Swarm implements TimeListener {
|
||||
private Mercator projection;
|
||||
private final VectorField field;
|
||||
|
||||
private boolean zoomChanged = false;
|
||||
private Vector diffPx;
|
||||
|
||||
/**
|
||||
* The number of particles to show. After {@link #updateBounds()} has been run, this also reflects the size of the
|
||||
* {@link #particles} array. Note that since elements in {@link #particles} can be <code>null</code>, this number
|
||||
@@ -59,6 +62,7 @@ public class Swarm implements TimeListener {
|
||||
this.parameters = streamletPars;
|
||||
timePoint = timer.getTime();
|
||||
cosineOfAverageLatitude = 1.0; // default to equator
|
||||
diffPx = new Vector(0, 0);
|
||||
}
|
||||
|
||||
public void start(int animationIntervalMillis) {
|
||||
@@ -125,8 +129,11 @@ public class Swarm implements TimeListener {
|
||||
return newParticles;
|
||||
}
|
||||
|
||||
public void onBoundsChanged() {
|
||||
projection.clearCanvas();
|
||||
public void onBoundsChanged(boolean zoomChanged) {
|
||||
this.zoomChanged |= zoomChanged;
|
||||
if (this.zoomChanged) {
|
||||
projection.clearCanvas();
|
||||
}
|
||||
swarmPause = 5;
|
||||
}
|
||||
|
||||
@@ -141,8 +148,7 @@ public class Swarm implements TimeListener {
|
||||
Vector boundsNEpx = this.projection.latlng2pixel(visibleBoundsOfField.getNorthEast());
|
||||
double boundsWidthpx = Math.abs(boundsNEpx.x - boundsSWpx.x);
|
||||
double boundsHeightpx = Math.abs(boundsSWpx.y - boundsNEpx.y);
|
||||
this.nParticles = (int) Math.round(Math.sqrt(boundsWidthpx * boundsHeightpx) * this.field.getParticleFactor()
|
||||
* this.parameters.swarmScale);
|
||||
this.nParticles = (int)Math.round(Math.sqrt(boundsWidthpx * boundsHeightpx) * this.field.getParticleFactor() * this.parameters.swarmScale);
|
||||
cosineOfAverageLatitude = Math.cos((visibleBoundsOfField.getSouthWest().getLatRad()+visibleBoundsOfField.getNorthEast().getLatRad())/2);
|
||||
};
|
||||
|
||||
@@ -155,13 +161,18 @@ public class Swarm implements TimeListener {
|
||||
swarmPause--;
|
||||
} else if (swarmPause == 1) {
|
||||
fullcanvas.setCanvasSettings();
|
||||
diffPx = fullcanvas.getDiffPx();
|
||||
projection.calibrate();
|
||||
updateBounds();
|
||||
particles = createParticles();
|
||||
if (zoomChanged) {
|
||||
particles = createParticles();
|
||||
zoomChanged = false;
|
||||
}
|
||||
swarmPause = 0;
|
||||
}
|
||||
if ((!swarmOffScreen) && (swarmPause == 0)) {
|
||||
execute();
|
||||
execute(diffPx);
|
||||
diffPx = new Vector(0, 0);
|
||||
}
|
||||
Date time1 = new Date();
|
||||
if (swarmContinue) {
|
||||
@@ -203,7 +214,7 @@ public class Swarm implements TimeListener {
|
||||
* Moves each particle by its vector {@link Particle#v} multiplied by the speed which is 0.01 times the
|
||||
* {@link VectorField#getMotionScale(int)} at the map's current zoom level.
|
||||
*/
|
||||
private boolean execute() {
|
||||
private boolean execute(Vector diffPx) {
|
||||
double speed = 0.01 * field.getMotionScale(map.getZoom());
|
||||
for (int idx = 0; idx < particles.length; idx++) {
|
||||
Particle particle = particles[idx];
|
||||
@@ -212,6 +223,12 @@ public class Swarm implements TimeListener {
|
||||
// update its currentPosition, currentPixelCoordinate and previousPixelCoordinate fields;
|
||||
// also, its particle.v field is updated based on its new position from the vector field
|
||||
particle.previousPixelCoordinate = particle.currentPixelCoordinate;
|
||||
if (diffPx.x != 0) {
|
||||
particle.previousPixelCoordinate.x += diffPx.x;
|
||||
}
|
||||
if (diffPx.y != 0) {
|
||||
particle.previousPixelCoordinate.y += diffPx.y;
|
||||
}
|
||||
double latDeg = particle.currentPosition.getLatDeg() + speed * particle.v.y;
|
||||
double lngDeg = particle.currentPosition.getLngDeg() + speed * particle.v.x / cosineOfAverageLatitude;
|
||||
particle.currentPosition = new DegreePosition(latDeg, lngDeg);
|
||||
|
||||
Reference in new issue
Block a user