GWT streamlets in simulator;

This commit is contained in:
Christopher Ronnewinkel (D036654) committed 2014-05-03 00:20:45 +02:00
1 parent 15af984a94
commit c83196f73d
10 files changed
+806 -70

No files matched your search

@@ -0,0 +1,12 @@
package com.sap.sailing.gwt.ui.simulator;
public class Index {
public long x;
public long y;
public Index(long x, long y) {
this.x = x;
this.y = y;
}
}
@@ -0,0 +1,20 @@
package com.sap.sailing.gwt.ui.simulator;
public class Neighbors {
public int xBot;
public int xTop;
public double xMod;
public int yBot;
public int yTop;
public double yMod;
public Neighbors(int xTop, int yTop, int xBot, int yBot, double xMod, double yMod) {
this.xTop = xTop;
this.yTop = yTop;
this.xBot = xBot;
this.yBot = yBot;
this.xMod = xMod;
this.yMod = yMod;
}
}
@@ -4,19 +4,22 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.maps.client.base.LatLng;
public class RectField {
public class RectField implements VectorField {
Vector[][] field;
private Vector[][] field;
public double x0;
public double x1;
public double y0;
public double y1;
public double visX0;
//public double visX0;
public double visX1;
public double visY0;
public double visY1;
public GeoPos visSW;
public GeoPos visNE;
private int w;
private int h;
@@ -30,11 +33,9 @@ public class RectField {
this.y0 = y0;
this.y1 = y1;
this.visX0 = 0;
this.visY0 = 0;
this.visX1 = 0;
this.visY1 = 0;
this.visSW = new GeoPos(0.0, 0.0);
this.visNE = new GeoPos(0.0, 0.0);
this.field = field;
this.w = field.length;
this.h = field[0].length;
@@ -83,26 +84,35 @@ public class RectField {
return result;
}
public void setStep(int step) {
}
public void nextStep() {
}
public void prevStep() {
}
public GeoPos getRandomPosition() {
double rndY = Math.random();
double rndX = Math.random();
GeoPos result = new GeoPos();
result.lat = rndY * this.visY0 + (1 - rndY) * this.visY1;
result.lng = rndX * this.visX0 + (1 - rndX) * this.visX1;
result.lat = rndY * this.visSW.lat + (1 - rndY) * this.visNE.lat;
result.lng = rndX * this.visSW.lng + (1 - rndX) * this.visNE.lng;
return result;
}
public boolean inBounds(double x, double y) {
return x >= this.x0 && x < this.x1 && y >= this.y0 && y < this.y1;
public boolean inBounds(GeoPos p) {
return p.lng >= this.x0 && p.lng < this.x1 && p.lat >= this.y0 && p.lat < this.y1;
}
public Vector interpolate(double a, double b) {
int na = (int)Math.floor(a);
int nb = (int)Math.floor(b);
int ma = (int)Math.ceil(a);
int mb = (int)Math.ceil(b);
double fa = a - na;
double fb = b - nb;
public Vector interpolate(GeoPos p) {
int na = (int)Math.floor(p.lng);
int nb = (int)Math.floor(p.lat);
int ma = (int)Math.ceil(p.lng);
int mb = (int)Math.ceil(p.lat);
double fa = p.lng - na;
double fb = p.lat - nb;
Vector result = new Vector();
result.x = this.field[na][nb].x * (1 - fa) * (1 - fb) + this.field[ma][nb].x * fa * (1 - fb) + this.field[na][mb].x * (1 - fa) * fb + this.field[ma][mb].x * fa * fb;
@@ -113,12 +123,13 @@ public class RectField {
public Vector getVector(GeoPos p) {
double a = (this.w - 1 - 1e-6) * (p.lng - this.x0) / (this.x1 - this.x0);
double b = (this.h - 1 - 1e-6) * (p.lat - this.y0) / (this.y1 - this.y0);
if ((a < 0)||(a > (this.w-1))||(b < 0)||(b > (this.h-1))) {
GeoPos q = new GeoPos();
q.lng = (this.w - 1 - 1e-6) * (p.lng - this.x0) / (this.x1 - this.x0);
q.lat = (this.h - 1 - 1e-6) * (p.lat - this.y0) / (this.y1 - this.y0);
if ((q.lng < 0)||(q.lng > (this.w-1))||(q.lat < 0)||(q.lat > (this.h-1))) {
return null;
} else {
return this.interpolate(a, b);
return this.interpolate(q);
}
}
@@ -153,4 +164,23 @@ public class RectField {
return 1.0;
}
public GeoPos getFieldNE() {
return new GeoPos(Math.max(this.y0, this.y1), Math.max(this.x0, this.x1));
}
public GeoPos getFieldSW() {
return new GeoPos(Math.min(this.y0, this.y1), Math.min(this.x0, this.x1));
}
public void setVisNE(GeoPos visNE) {
this.visNE = visNE;
}
public void setVisSW(GeoPos visSW) {
this.visSW = visSW;
}
public double getParticleFactor() {
return this.particleFactor;
}
}
@@ -0,0 +1,297 @@
package com.sap.sailing.gwt.ui.simulator;
import java.util.List;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
import com.sap.sailing.gwt.ui.shared.WindFieldGenParamsDTO;
public class SimulatorField implements VectorField {
private boolean swarmDebug = false;
private GeoPos rcStart;
private GeoPos rcEnd;
private int resY;
private int resX;
private int borderY;
private int borderX;
private double bdXi;
private double bdPhi;
private GeoPos bdA;
private GeoPos bdB;
private GeoPos bdC;
private double xScale;
private double x0;
private double x1;
private double y0;
private double y1;
public GeoPos visSW;
public GeoPos visNE;
private double maxLength;
private double particleFactor;
private double lngScale;
private GeoPos nvY;
private GeoPos nvX;
private GeoPos gvX;
private double[][][] data;
private int step;
public SimulatorField(WindFieldDTO windData, WindFieldGenParamsDTO windParams) {
this.step = 0;
String parseString = windData.windDataJSON.substring(18, windData.windDataJSON.length()-1) + "}";
JSONObject baseData = JSONParser.parseLenient(parseString).isObject();
this.rcStart = new GeoPos();
this.rcStart.lat = baseData.get("rcStart").isObject().get("lat").isNumber().doubleValue();
this.rcStart.lng = baseData.get("rcStart").isObject().get("lng").isNumber().doubleValue();
this.rcEnd = new GeoPos();
this.rcEnd.lat = baseData.get("rcEnd").isObject().get("lat").isNumber().doubleValue();
this.rcEnd.lng = baseData.get("rcEnd").isObject().get("lng").isNumber().doubleValue();
this.resY = (int)baseData.get("resY").isNumber().doubleValue();
this.resX = (int)baseData.get("resX").isNumber().doubleValue();
this.borderY = (int)baseData.get("borderY").isNumber().doubleValue();
this.borderX = (int)baseData.get("borderX").isNumber().doubleValue();
this.bdXi = (this.borderY + 0.5) / (this.resY - 1);
this.bdPhi = 1.0 + 2*this.bdXi;
this.bdA = new GeoPos(this.rcEnd.lat+(this.rcEnd.lat-this.rcStart.lat)*this.bdXi, this.rcEnd.lng+(this.rcEnd.lng-this.rcStart.lng)*this.bdXi);
this.bdB = new GeoPos((this.rcStart.lat-this.rcEnd.lat)*this.bdPhi, (this.rcStart.lng-this.rcEnd.lng)*this.bdPhi);
this.xScale = baseData.get("xScale").isNumber().doubleValue();
this.x0 = baseData.get("boundsSW").isObject().get("lng").isNumber().doubleValue();
this.x1 = baseData.get("boundsNE").isObject().get("lng").isNumber().doubleValue();
this.y0 = baseData.get("boundsSW").isObject().get("lat").isNumber().doubleValue();
this.y1 = baseData.get("boundsNE").isObject().get("lat").isNumber().doubleValue();
this.visSW = new GeoPos(0.0, 0.0);
this.visNE = new GeoPos(0.0, 0.0);
List<SimulatorWindDTO> gridData = windData.getMatrix();
int p = 0;
int imax = windParams.getyRes() + 2*windParams.getBorderY();
int jmax = windParams.getxRes() + 2*windParams.getBorderX();
int steps = gridData.size() / (imax * jmax);
this.data = new double[steps][imax][2*jmax];
double maxWindSpeed = 0;
for(int s=0; s<steps; s++) {
for(int i=0; i<imax; i++) {
for(int j=0; j<jmax; j++) {
SimulatorWindDTO wind = gridData.get(p);
p++;
if (wind.trueWindSpeedInKnots > maxWindSpeed) {
maxWindSpeed = wind.trueWindSpeedInKnots;
}
this.data[s][i][2*j+1] = wind.trueWindSpeedInKnots*Math.cos(wind.trueWindBearingDeg*Math.PI/180.0);
this.data[s][i][2*j] = wind.trueWindSpeedInKnots*Math.sin(wind.trueWindBearingDeg*Math.PI/180.0);
}
}
}
this.maxLength = maxWindSpeed;
this.particleFactor = 2.0;
double latAvg = (this.rcEnd.lat + this.rcStart.lat) / 2.;
this.lngScale = Math.cos(latAvg * Math.PI / 180.0);
double difLat = this.rcEnd.lat - this.rcStart.lat;
double difLng = (this.rcEnd.lng - this.rcStart.lng) * this.lngScale;
double difLen = Math.sqrt(difLat*difLat + difLng*difLng);
this.nvY = new GeoPos(difLat/difLen/difLen*(this.resY-1), difLng/difLen/difLen*(this.resY-1));
double nrmLat = -difLng/difLen;
double nrmLng = difLat/difLen;
this.nvX = new GeoPos( nrmLat/this.xScale/difLen*(this.resX-1), nrmLng/this.xScale/difLen*(this.resX-1) );
this.gvX = new GeoPos( nrmLat*this.xScale*difLen, nrmLng/this.lngScale*this.xScale*difLen );
this.bdC = new GeoPos( this.gvX.lat*(this.resX+2*this.borderX-1)/(this.resX-1), this.gvX.lng*(this.resX+2*this.borderX-1)/(this.resX-1) );
}
public static native void console(String msg) /*-{
console.log(msg);
}-*/;
public GeoPos getRandomPosition() {
double rndY = Math.random();
double rndX = Math.random() - 0.5;
GeoPos result = new GeoPos();
result.lat = this.bdA.lat + rndY * this.bdB.lat + rndX * this.bdC.lat;
result.lng = this.bdA.lng + rndY * this.bdB.lng + rndX * this.bdC.lng;
if (swarmDebug&&(!this.inBounds(result))) {
console("random-position: out of bounds");
}
return result;
}
public boolean inBounds(GeoPos p) {
Index idx = this.getIndex(p);
boolean inBool = (idx.x >= 0) && (idx.x < (this.resX+2*this.borderX)) && (idx.y >= 0) && (idx.y < (this.resY+2*this.borderY));
return inBool;
}
public Vector interpolate(GeoPos p) {
Neighbors idx = this.getNeighbors(p);
if (swarmDebug&&((idx.xTop >= (this.resX+2*this.borderX))||(idx.yTop >= (this.resY+2*this.borderY)))) {
console("interpolate: out of range: " + idx.xTop + " " + idx.yTop);
}
//System.out.println("neighbors:"+idx.xBot+","+idx.xTop+","+idx.yBot+","+idx.yTop);
double avgX = this.data[this.step][idx.yBot][2*idx.xBot] * (1 - idx.yMod) * (1 - idx.xMod) + this.data[this.step][idx.yTop][2*idx.xBot] * idx.yMod * (1 - idx.xMod)
+ this.data[this.step][idx.yBot][2*idx.xTop] * (1 - idx.yMod) * idx.xMod + this.data[this.step][idx.yTop][2*idx.xTop] * idx.yMod * idx.xMod;
double avgY = this.data[this.step][idx.yBot][2*idx.xBot+1] * (1 - idx.yMod) * (1 - idx.xMod) + this.data[this.step][idx.yTop][2*idx.xBot+1] * idx.yMod * (1 - idx.xMod)
+ this.data[this.step][idx.yBot][2*idx.xTop+1] * (1 - idx.yMod) * idx.xMod + this.data[this.step][idx.yTop][2*idx.xTop+1] * idx.yMod * idx.xMod;
return new Vector(avgX / this.lngScale, avgY);
}
public void setStep(int step) {
if (step < 0) {
this.step = 0;
} else if (step >= this.data.length) {
this.step = this.data.length-1;
} else {
this.step = step;
}
}
public void nextStep() {
if (this.step < (this.data.length-1)) {
this.step++;
}
}
public void prevStep() {
if (this.step > 0) {
this.step--;
}
}
public Vector getVector(GeoPos p) {
return this.interpolate(p);
}
public Index getIndex(GeoPos p) {
// calculate grid indexes
GeoPos posR = new GeoPos( p.lat - this.rcStart.lat, (p.lng - this.rcStart.lng) * this.lngScale );
// closest grid point
long yIdx = Math.round( posR.lat * this.nvY.lat + posR.lng * this.nvY.lng ) + this.borderY;
long xIdx = Math.round( posR.lat * this.nvX.lat + posR.lng * this.nvX.lng + (this.resX - 1) / 2. ) + this.borderX;
return new Index( xIdx, yIdx );
}
public Neighbors getNeighbors(GeoPos p) {
// calculate grid indexes
GeoPos posR = new GeoPos( p.lat - this.rcStart.lat, (p.lng - this.rcStart.lng) * this.lngScale );
// surrounding grid points
double yFlt = posR.lat * this.nvY.lat + posR.lng * this.nvY.lng + this.borderY;
double xFlt = posR.lat * this.nvX.lat + posR.lng * this.nvX.lng + (this.resX - 1) / 2. + this.borderX;
double yBot = Math.floor( yFlt );
double xBot = Math.floor( xFlt );
double yTop = Math.ceil( yFlt );
double xTop = Math.ceil( xFlt );
double yMod = yFlt - yBot;
double xMod = xFlt - xBot;
if (xBot < 0) {
xBot = 0;
}
if (yBot < 0) {
yBot = 0;
}
if (xTop >= (this.resX+2*this.borderX)) {
xTop = this.resX+2*this.borderX-1;
}
if (yTop >= (this.resY+2*this.borderY)) {
yTop = this.resY+2*this.borderY-1;
}
//System.out.println("neighbors:"+xFlt+","+xBot+","+xTop+","+yFlt+","+yBot+","+yTop);
return new Neighbors((int)xTop, (int)yTop, (int)xBot, (int)yBot, xMod, yMod );
}
public double getMaxLength() {
return maxLength;
}
public double motionScale(int zoomLevel) {
return 0.08 * Math.pow(1.6, Math.min(1.0, 6.0 - zoomLevel));
}
public double particleWeight(GeoPos p, Vector v) {
return v.length() / this.maxLength + 0.1;
}
public String[] getColors() {
String[] colors = new String[256];
double alpha = 0.7;
int greyValue = 255;
for (int i = 0; i < 256; i++) {
colors[i] = "rgba(" + (greyValue) + "," + (greyValue) + "," + (greyValue) + "," + (alpha*i/255.0) + ")";
//this.colors[i] = 'hsla(' + 360*(0.55+0.9*(0.5-i/255)) + ',' + (100) + '% ,' + (50) + '%,' + (i/255) + ')';
}
return colors;
}
public double lineWidth(int alpha) {
return 1.0;
}
public GeoPos getFieldNE() {
return new GeoPos(Math.max(this.y0, this.y1), Math.max(this.x0, this.x1));
}
public GeoPos getFieldSW() {
return new GeoPos(Math.min(this.y0, this.y1), Math.min(this.x0, this.x1));
}
public void setVisNE(GeoPos visNE) {
this.visNE = visNE;
}
public void setVisSW(GeoPos visSW) {
this.visSW = visSW;
}
public double getParticleFactor() {
return this.particleFactor;
}
}
@@ -463,14 +463,16 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
add(map, 0, 0);
map.setSize("100%", "100%");
if (parent.particles > 0) {
if (windParams.isShowStreamlets2()) {
map.addBoundsChangeHandler(new BoundsChangeMapHandler() {
@Override
public void onEvent(BoundsChangeMapEvent event) {
// improve browser performance by deferred scheduling of redraws
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
public void execute() {
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged();
if (windStreamletsCanvasOverlay.getSwarm() != null) {
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged();
}
}
});
}
@@ -7,6 +7,7 @@ import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.GWT;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.user.client.Timer;
import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
public class Swarm {
@@ -18,7 +19,7 @@ public class Swarm {
private Timer loopTimer;
private String[] color;
private Mercator projection;
private RectField field;
private VectorField field;
private int nParticles;
private Particle[] particles;
private boolean swarmOffScreen = false;
@@ -33,19 +34,27 @@ public class Swarm {
this.map = map;
}
public void start(int animationDuration) {
public void start(int animationDuration, WindFieldDTO windField) {
projection = new Mercator(fullcanvas, map);
if (field == null) {
if (windField == null) {
SimulatorJSBundle bundle = GWT.create(SimulatorJSBundle.class);
String jsonStr = bundle.windStreamletsDataJS().getText();
field = RectField.read(jsonStr.substring(19, jsonStr.length()-1), false);
map.setZoom(5);
map.panTo(field.getCenter());
map.panTo(((RectField)field).getCenter());
projection.calibrate();
} else {
field = new SimulatorField(((WindStreamletsCanvasOverlay)fullcanvas).windFieldDTO, ((WindStreamletsCanvasOverlay)fullcanvas).windParams);
fullcanvas.setCanvasSettings();
projection.calibrate();
}
this.updateBounds();
@@ -53,7 +62,13 @@ public class Swarm {
color = field.getColors();
Context2d ctxt = canvas.getContext2d();
ctxt.setFillStyle("white");
ctxt.setFillStyle("red");
/*Vector p = this.projection.latlng2pixel(this.field.getFieldNE());
ctxt.fillRect(p.x,p.y,5.0,5.0);
p = this.projection.latlng2pixel(this.field.getFieldSW());
ctxt.fillRect(p.x,p.y,5.0,5.0);*/
particles = this.createParticles();
@@ -115,8 +130,8 @@ public class Swarm {
GeoPos mapNE = new GeoPos(map.getBounds().getNorthEast());
GeoPos mapSW = new GeoPos(map.getBounds().getSouthWest());
GeoPos fieldNE = new GeoPos(Math.max(this.field.y0, this.field.y1), Math.max(this.field.x0, this.field.x1));
GeoPos fieldSW = new GeoPos(Math.min(this.field.y0, this.field.y1), Math.min(this.field.x0, this.field.x1));
GeoPos fieldNE = this.field.getFieldNE();
GeoPos fieldSW = this.field.getFieldSW();
Vector visibleNE = this.isVisible(fieldNE);
Vector visibleSW = this.isVisible(fieldSW);
@@ -157,10 +172,8 @@ public class Swarm {
}
this.field.visX0 = this.boundsSW.lng;
this.field.visY0 = this.boundsSW.lat;
this.field.visX1 = this.boundsNE.lng;
this.field.visY1 = this.boundsNE.lat;
this.field.setVisSW(this.boundsSW);
this.field.setVisNE(this.boundsNE);
Vector boundsSWpx = this.projection.latlng2pixel(this.boundsSW);
Vector boundsNEpx = this.projection.latlng2pixel(this.boundsNE);
@@ -168,7 +181,7 @@ public class Swarm {
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.particleFactor);
this.nParticles = (int)Math.round(Math.sqrt(boundsWidthpx * boundsHeightpx) * this.field.getParticleFactor());
//console("#particles: "+this.nParticles + " at " + (boundsWidthpx) +"x" + (boundsHeightpx) + "px (" + (boundsWidthpx * boundsHeightpx) + " pixels)");
};
@@ -245,14 +258,16 @@ public class Swarm {
for(int idx=0; idx<particles.length; idx++) {
Particle particle = particles[idx];
if ((particle.age > 0) && (this.field.inBounds(particle.pos.lng, particle.pos.lat))) {
if ((particle.age > 0) && (particle.v != null)) {
particle.pos.lat = particle.pos.lat + speed*particle.v.y;
particle.pos.lng = particle.pos.lng + speed*particle.v.x;
double s = particle.v.length() / field.getMaxLength();
particle.alpha = (int)Math.min(255, 90 + Math.round(350 * s));
particle.age--;
if (particle.age > 0) {
if ((particle.age > 0) && (this.field.inBounds(particle.pos))) {
particle.v = field.getVector(particle.pos);
} else {
particle.v = null;
}
} else {
particles[idx] = this.createParticle();
@@ -263,5 +278,9 @@ public class Swarm {
return true;
}
public VectorField getField() {
return field;
}
}
@@ -5,6 +5,14 @@ public class Vector {
public double x;
public double y;
public Vector() {
}
public Vector(double x, double y) {
this.x = x;
this.y = y;
}
public double length() {
return Math.sqrt(x*x + y*y);
}
@@ -0,0 +1,40 @@
package com.sap.sailing.gwt.ui.simulator;
public interface VectorField {
public GeoPos getRandomPosition();
public boolean inBounds(GeoPos p);
public Vector interpolate(GeoPos p);
public Vector getVector(GeoPos p);
public double getMaxLength();
public double motionScale(int zoomLevel);
public double particleWeight(GeoPos p, Vector v);
public String[] getColors();
public double lineWidth(int alpha);
public GeoPos getFieldNE();
public GeoPos getFieldSW();
public void setVisNE(GeoPos visNE);
public void setVisSW(GeoPos visSW);
public double getParticleFactor();
public void setStep(int step);
public void nextStep();
public void prevStep();
}
@@ -52,11 +52,6 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
getCanvas().getElement().setId("swarm-display");
/*if (!this.isSwarmDataExt()) {
// random test windfield
JavaScriptObject swarmData = this.getJSONRandomWindData();
this.setSwarmData(swarmData);
}*/
}
public JavaScriptObject getJSONRandomWindData() {
@@ -143,24 +138,41 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
$wnd.swarmCanvasProjection = instance;
}-*/;
public native void startStreamlets() /*-{
if ($wnd.swarmAnimator) {
$wnd.swarmUpdData = true;
$wnd.updateStreamlets($wnd.swarmUpdData);
} else {
$wnd.initStreamlets($wnd.swarmMap);
// public native void startStreamlets() /*-{
// if ($wnd.swarmAnimator) {
// $wnd.swarmUpdData = true;
// $wnd.updateStreamlets($wnd.swarmUpdData);
// } else {
// $wnd.initStreamlets($wnd.swarmMap);
// }
// }-*/;
public void startStreamlets() {
if (swarm == null) {
this.swarm = new Swarm(this,map);
}
}-*/;
this.swarm.start(40, windFieldDTO);
}
// public native void setStreamletsStep(int step) /*-{
// $wnd.swarmField.setStep(step);
// }-*/;
public native void setStreamletsStep(int step) /*-{
$wnd.swarmField.setStep(step);
}-*/;
public void setStreamletsStep(int step) {
this.swarm.getField().setStep(step);
}
public native void stopStreamlets() /*-{
if ($wnd.stopStreamlets) {
$wnd.stopStreamlets();
};
}-*/;
// public native void stopStreamlets() /*-{
// if ($wnd.stopStreamlets) {
// $wnd.stopStreamlets();
// };
// }-*/;
public void stopStreamlets() {
if (swarm != null) {
this.swarm.stop();
}
}
public void extendWindDataJSON() {
@@ -207,14 +219,6 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
public void setWindField(final WindFieldDTO windFieldDTO) {
this.windFieldDTO = windFieldDTO;
this.extendWindDataJSON();
this.setWindDataJSON(this.windFieldDTO.windDataJSON);
//this.getJSNIWind(this);
this.setMapInstance(this.simulatorMap.getMap().getJso());
this.setCanvasProjectionInstance(this.simulatorMap.getRegattaAreaCanvasOverlay().getMapProjection());
}
@Override
@@ -263,7 +267,7 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
if (mapProjection != null) {
if ((nParticles > 0)&&(swarm == null)) {
this.swarm = new Swarm(this,map);
this.swarm.start(40);
this.swarm.start(40, null);
}
if (windFieldDTO != null) {
// drawing is done by external JavaScript for Streamlets
@@ -276,7 +280,7 @@ public class WindStreamletsCanvasOverlay extends FullCanvasOverlay implements Ti
}
private void clear() {
this.stopStreamlets();
this.stopStreamlets();
}
@Override
@@ -0,0 +1,304 @@
package com.sap.sailing.gwt.ui.simulator;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.maps.client.base.LatLng;
import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
import com.sap.sailing.gwt.ui.shared.WindFieldGenParamsDTO;
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
import com.sap.sse.gwt.client.player.Timer;
/**
* A google map overlay based on a HTML5 canvas for drawing a wind field. The overlay covers the whole map and displays
* the wind objects inside it.
*
* @author Nidhi Sawhney(D054070)
*
*/
public class WindStreamletsCanvasOverlayJS extends FullCanvasOverlay implements TimeListenerWithStoppingCriteria {
/** The wind field that is to be displayed in the overlay */
protected WindFieldDTO windFieldDTO;
protected WindFieldGenParamsDTO windParams = null;
protected SimulatorMap simulatorMap;
private boolean visible = false;
private Timer timer;
private int nParticles;
private Swarm swarm;
private static Logger logger = Logger.getLogger(WindStreamletsCanvasOverlayJS.class.getName());
public WindStreamletsCanvasOverlayJS(SimulatorMap simulatorMap, int zIndex, final Timer timer, final WindFieldGenParamsDTO windParams) {
super(simulatorMap.getMap(), zIndex);
this.simulatorMap = simulatorMap;
this.timer = timer;
this.windParams = windParams;
this.nParticles = this.simulatorMap.getMainPanel().particles;
windFieldDTO = null;
getCanvas().getElement().setId("swarm-display");
/*if (!this.isSwarmDataExt()) {
// random test windfield
JavaScriptObject swarmData = this.getJSONRandomWindData();
this.setSwarmData(swarmData);
}*/
}
public JavaScriptObject getJSONRandomWindData() {
JSONObject jsonWindData = new JSONObject();
jsonWindData.put("timestamp", new JSONString("11:55 am on March 18, 2014"));
LatLng boundsSW = LatLng.newInstance(53.854617, 8.159124);
LatLng boundsNE = LatLng.newInstance(55.263922, 11.413824);
jsonWindData.put("x0", new JSONNumber(boundsSW.getLongitude()));
jsonWindData.put("y0", new JSONNumber(boundsSW.getLatitude()));
jsonWindData.put("x1", new JSONNumber(boundsNE.getLongitude()));
jsonWindData.put("y1", new JSONNumber(boundsNE.getLatitude()));
int maxSteps = 1;
int gridWidth = 100;
int gridHeight = 100;
jsonWindData.put("gridWidth", new JSONNumber(gridWidth));
jsonWindData.put("gridHeight", new JSONNumber(gridHeight));
JSONArray windField = new JSONArray();
for(int stp=0; stp < maxSteps; stp++) {
JSONArray vectorField = new JSONArray();
for(int idx=0; idx < (gridWidth*gridHeight*2); idx++) {
vectorField.set(idx, new JSONNumber((Math.random()-0.5)*10.0+3.0));
//windField.set(idx, new JSONNumber(10.0));
}
windField.set(stp, vectorField);
}
jsonWindData.put("field", windField);
return jsonWindData.getJavaScriptObject();
}
public native boolean isSwarmDataExt() /*-{
if ($wnd.swarmDataExt) {
return true;
} else {
return false;
}
}-*/;
public native String getSwarmData() /*-{
return JSON.stringify($wnd.swarmData);
}-*/;
public native void setSwarmData(JavaScriptObject swarmData) /*-{
$wnd.swarmData = swarmData;
}-*/;
private native void getJSNIWind(WindStreamletsCanvasOverlayJS wsc) /*-{
$wnd.getWindfromSimulator = function(idx) {
return wsc.@com.sap.sailing.gwt.ui.simulator.WindStreamletsCanvasOverlay::getWind(I)(idx);
};
}-*/;
private native JavaScriptObject getWindInst(double x, double y) /*-{
return {x:x, y:y};
}-*/;
public JavaScriptObject getWind(int idx){
SimulatorWindDTO wind = this.windFieldDTO.getMatrix().get(idx);
double y = wind.trueWindSpeedInKnots*Math.cos(wind.trueWindBearingDeg*Math.PI/180.0);
double x = wind.trueWindSpeedInKnots*Math.sin(wind.trueWindBearingDeg*Math.PI/180.0);
return getWindInst(x,y);
}
public native void setWindDataJSON(String jsonField) /*-{
eval(jsonField);
}-*/;
public WindStreamletsCanvasOverlayJS(SimulatorMap simulatorMap, int zIndex) {
this(simulatorMap, zIndex, null, null);
}
public native void setMapInstance(Object mapInstance) /*-{
$wnd.swarmMap = mapInstance;
}-*/;
public native void setCanvasProjectionInstance(Object instance) /*-{
$wnd.swarmCanvasProjection = instance;
}-*/;
public native void startStreamlets() /*-{
if ($wnd.swarmAnimator) {
$wnd.swarmUpdData = true;
$wnd.updateStreamlets($wnd.swarmUpdData);
} else {
$wnd.initStreamlets($wnd.swarmMap);
}
}-*/;
public native void setStreamletsStep(int step) /*-{
$wnd.swarmField.setStep(step);
}-*/;
public native void stopStreamlets() /*-{
if ($wnd.stopStreamlets) {
$wnd.stopStreamlets();
};
}-*/;
public void extendWindDataJSON() {
List<SimulatorWindDTO> data = this.windFieldDTO.getMatrix();
String jsonData = "data:[";
int p = 0;
int imax = this.windParams.getyRes() + 2*this.windParams.getBorderY();
int jmax = this.windParams.getxRes() + 2*this.windParams.getBorderX();
int steps = data.size() / (imax * jmax);
double maxWindSpeed = 0;
for(int s=0; s<steps; s++) {
jsonData +="[";
for(int i=0; i<imax; i++) {
jsonData +="[";
for(int j=0; j<jmax; j++) {
SimulatorWindDTO wind = data.get(p);
p++;
if (wind.trueWindSpeedInKnots > maxWindSpeed) {
maxWindSpeed = wind.trueWindSpeedInKnots;
}
double y = wind.trueWindSpeedInKnots*Math.cos(wind.trueWindBearingDeg*Math.PI/180.0);
double x = wind.trueWindSpeedInKnots*Math.sin(wind.trueWindBearingDeg*Math.PI/180.0);
jsonData += x + "," + y;
if (j<(jmax-1)) {
jsonData += ",";
}
}
if (i<(imax-1)) {
jsonData += "],";
} else {
jsonData += "]";
}
}
if (s<(steps-1)) {
jsonData += "],";
} else {
jsonData += "]";
}
}
this.windFieldDTO.windDataJSON += jsonData + "],maxLength:" + maxWindSpeed + "};";
}
public void setWindField(final WindFieldDTO windFieldDTO) {
this.windFieldDTO = windFieldDTO;
this.extendWindDataJSON();
this.setWindDataJSON(this.windFieldDTO.windDataJSON);
//this.getJSNIWind(this);
this.setMapInstance(this.simulatorMap.getMap().getJso());
this.setCanvasProjectionInstance(this.simulatorMap.getRegattaAreaCanvasOverlay().getMapProjection());
}
@Override
public boolean isVisible() {
return this.visible;
}
@Override
public void setVisible(boolean isVisible) {
if (getCanvas() != null) {
if (isVisible) {
this.startStreamlets();
if (timer.getTime().compareTo(this.windParams.getStartTime()) != 0) {
this.timeChanged(timer.getTime(), null);
}
this.visible = isVisible;
} else {
this.stopStreamlets();
this.visible = isVisible;
}
}
}
@Override
public void addToMap() {
if (timer != null) {
timer.addTimeListener(this);
}
}
@Override
public void removeFromMap() {
if (timer != null) {
timer.removeTimeListener(this);
}
this.setVisible(false);
}
@Override
protected void drawCenterChanged() {
}
@Override
protected void draw() {
super.draw();
if (mapProjection != null) {
if ((nParticles > 0)&&(swarm == null)) {
this.swarm = new Swarm(this,map);
this.swarm.start(40, null);
}
if (windFieldDTO != null) {
// drawing is done by external JavaScript for Streamlets
}
}
}
public Swarm getSwarm() {
return this.swarm;
}
private void clear() {
this.stopStreamlets();
}
@Override
public void timeChanged(final Date newDate, Date oldDate) {
int step = (int)((newDate.getTime() - this.windParams.getStartTime().getTime()) / this.windParams.getTimeStep().getTime());
this.setStreamletsStep(step);
}
@Override
public boolean shallStop() {
if (timer.getTime().getTime() >= this.windParams.getEndTime().getTime()) {
return true;
} else {
return false;
}
}
public void setTimer(final Timer timer) {
this.timer = timer;
}
public Timer getTimer() {
return timer;
}
}