Cs3000.SnapToRoute=Class.create({
initialize:function(map,coords,projection){
this.map=map;
this.coords=coords;
this.projection=projection;
this._pixelRoute=new Cs3000.PixelRoute();
this._initRouteData();
this._initMapListeners();
},
getSnapped:function(fromPoint){
if(true){
var ret={
point:null,
distance:Number.MAX_VALUE,
index:-1
};
try{
for(var index=1,len=this.coords.length;index<len;++index){
var p1=this.coords[index-1];
var p2=this.coords[index];
var dist=Math.min(p1.distanceFrom(fromPoint),p2.distanceFrom(fromPoint));
if(dist!=null&&dist<ret.distance){
ret.distance=dist;
ret.point=p1;
ret.index=index;
}
}
}catch(e){Novajax.handleError('',e)}
return ret;
}
var pixelPoint=this.projection.fromLatLngToPixel(fromPoint,this.map.getZoom());
var r=this._pixelRoute.getClosestPoint(pixelPoint);
var d=this._pixelRoute.getDistanceTo(r.i-1);
d+=this.coords[r.i-1].distanceFrom(this.coords[r.i])*r.fTo;
return{
point:this.projection.fromPixelToLatLng(this.map.createPixelPoint(r.x,r.y),this.map.getZoom()),
distance:d
};
},
getRouteLength:function(){
return this._pixelRoute.getDistanceTo(this._pixelRoute.getLength()-1);
},
getPointAtLength:function(length){
var i=this._pixelRoute.getIndexOfDistance(length);
return this.coords[i];
},
_initMapListeners:function(){
Object.observe(this.map,'zoomend',this.onMapZoomend.bind(this));
},
onMapZoomend:function(){
Cs3000.PixelRoute.recalcFromCoords(this._pixelRoute,this.coords,this.projection,this.map.getZoom());
},
_initRouteData:function(){
Cs3000.PixelRoute.initFromCoords(this._pixelRoute,this.coords,this.projection,this.map.getZoom());
}
});
Cs3000.PixelRoute=Class.create({
initialize:function(){
this.route=[];
},
push:function(p){
this.route.push(p);
},
getItemAt:function(i){
return this.route[i];
},
getLength:function(){
return this.route.length;
},
getClosestPoint:function(point){
var minDist;
var fTo;
var fFrom;
var x;
var y;
var i;
var dist;
if(this.route.length>1){
for(var n=1;n<this.route.length;n++){
if(this.route[n].x!=this.route[n-1].x){
var a=(this.route[n].y-this.route[n-1].y)/(this.route[n].x-this.route[n-1].x);
var b=this.route[n].y-a*this.route[n].x;
dist=Math.abs(a*point.x+b-point.y)/Math.sqrt(a*a+1);
}
else{
dist=Math.abs(point.x-this.route[n].x)
}
var rl2=Math.pow(this.route[n].y-this.route[n-1].y,2)+Math.pow(this.route[n].x-this.route[n-1].x,2);
var ln2=Math.pow(this.route[n].y-point.y,2)+Math.pow(this.route[n].x-point.x,2);
var lnm12=Math.pow(this.route[n-1].y-point.y,2)+Math.pow(this.route[n-1].x-point.x,2);
var dist2=Math.pow(dist,2);
var calcrl2=ln2-dist2+lnm12-dist2;
if(calcrl2>rl2){
dist=Math.sqrt(Math.min(ln2,lnm12));
}
if((minDist==null)||(minDist>dist)){
fTo=((Math.sqrt(lnm12-dist2))/Math.sqrt(rl2));
minDist=dist;
i=n;
}
}
if(fTo>1){
fTo=1;
}
fFrom=1-fTo;
var dx=this.route[i-1].x-this.route[i].x;
var dy=this.route[i-1].y-this.route[i].y;
x=this.route[i-1].x-(dx*fTo);
y=this.route[i-1].y-(dy*fTo);
}
return{'x':x,'y':y,'i':i,'fTo':fTo,'fFrom':fFrom};
},
getDistanceTo:function(index){
return this.route[index].cumDist;
},
getIndexOfDistance:function(maxLength){
var f=0;
for(var index=0,len=this.route.length;index<len;++index){
var r=this.route[index];
if(r&&maxLength>r.cumDist){
f=index;
}
}
return f;
}
});
Cs3000.PixelRoute.initFromCoords=function(pixelRoute,coords,projection,zoom){
var distFromLast=0;
var cumDist=0;
for(var index=0,len=coords.length;index<len;++index){
if(index>0){
distFromLast=coords[index-1].distanceFrom(coords[index]);
cumDist+=distFromLast;
}
var point=projection.fromLatLngToPixel(coords[index],zoom);
pixelRoute.push({
x:point.x,
y:point.y,
distFromLast:distFromLast,
cumDist:cumDist
});
}
};
Cs3000.PixelRoute.recalcFromCoords=function(pixelRoute,coords,projection,zoom){
for(var index=0,len=coords.length;index<len;++index){
var point=projection.fromLatLngToPixel(coords[index],zoom);
pixelRoute.getItemAt(index).x=point.x;
pixelRoute.getItemAt(index).y=point.y;
}
console.log('recalced '+zoom);
};
dotLineIntersection=function(x,y,x0,y0,x1,y1){
if(!(x1-x0))
return{x:x0,y:y};
else if(!(y1-y0))
return{x:x,y:y0};
var left,tg=-1/((y1-y0)/(x1-x0));
return{x:left=(x1*(x*tg-y+y0)+x0*(x*-tg+y-y1))/(tg*(x1-x0)+y0-y1),y:tg*left-tg*x+y};
};

