[ka-Map-users] Ahora sí, definitive Area measurement tool
Jordi Cerdà
jordieumoll at gmail.com
Wed Jan 30 03:22:07 EST 2008
Hello,
We have developped an Area measurement tool based on the kaTool prototype.
It's not perfect but it's enough for our needs.
If someone is interested I send the code
Thanks,
Jordi
/**********************************************************************
*
*
* purpose: a simple tool for measuring area
*
*
*
**********************************************************************
*
* To use this tool:
*
* 1) add a script tag to your page
*
* <script type="text/javascript" src="myKaArea.js"></script>
*
* 2) create a new instance of myKaRuler
*
* myKaArea = new myKaArea( myKaMap);
*
* 3) provide some way of activating it.
*
* <img id="toolArea" onclick="switchMode(this.id)" title="Area"
alt="mesurar area" src="images/a_pixel.gif" >
*
*
*
*****************************************************************************/
/**
* myKaArea constructor
*
* construct a new myKaArea object of a given type for a given kaMap
instance
*
* oKaMap - a kaMap instance
*
*/
function myKaArea( oKaMap ) {
kaTool.apply( this, [oKaMap] );
this.name = 'myKaArea';
this.cursor = 'default';
this.canvas = null;
// the units abrevations (if map units is DD, the distance is in
kilometers)
this.unitsAbrevations = new Array("ft","in","km","m","mi","km");
//this is the HTML element that is visible
this.domObj = document.createElement( 'div' );
this.domObj.id = 'measureResult';
this.domObj.style.position = 'absolute';
this.domObj.style.top = '-300px';
this.domObj.style.left = '-300px';
this.domObj.style.width = '150px';
this.domObj.style.height = '65px';
this.domObj.style.zIndex = 300;
this.domObj.style.visibility = 'hidden';
this.domObj.style.backgroundColor = 'white';
this.domObj.style.border = '1px solid #999999';
this.domObj.style.fontFamily = 'Verdana, Arial';
this.domObj.style.fontSize = '10px';
document.body.appendChild( this.domObj );
// the jsgraphic object
this.jg = null;
// store the user clicks coordinates
this.startx = null;
this.starty = null;
this.endx = null;
this.endy = null;
this.arrayX = new Array();
this.arrayY = new Array();
this.nPunts = 0;
this.invalid = false;
// the total polyline length
this.total = 0.0;
this.input = getRawObject('coords');
for (var p in kaTool.prototype) {
if (!myKaArea.prototype[p])
myKaArea.prototype[p]= kaTool.prototype[p];
}
};
/**
* activate this tool. Activating the tool causes any existing tools to be
* deactivated.
*/
myKaArea.prototype.activate = function() {
this.kaMap.activateTool( this );
document.kaCurrentTool = this;
this.domObj.innerHTML = "<h3> Àrea: <input
type='text' id='measureTot'
style='border:none;background-color:transparent;width:75px;' />" +
this.unitsAbrevations[this.kaMap.getCurrentMap().units] +
"2<br/> <input type='text' id='missatge'
style='border:none;background-color:transparent;width:150px;'/>";
if(this.canvas == null){
this.canvas = this.kaMap.createDrawingCanvas( 500 );
this.canvas.id = "measureCanvas";
}
if(this.jg == null){
this.jg = new jsGraphics("measureCanvas");
this.jg.setColor("#ff0000");
this.jg.setStroke(3);
}
this.domObj.style.visibility='visible';
};
/**
* deactivate this tool.
*/
myKaArea.prototype.deactivate = function() {
this.kaMap.deactivateTool( this );
document.kaCurrentTool = null;
this.jg.clear();
this.jg=null;
this.kaMap.removeDrawingCanvas(this.canvas);
this.canvas=null;
this.domObj.style.visibility='hidden';
};
/*
* draw line representing the measure.
*
*/
myKaArea.prototype.drawPolygon = function() {
var i = 0;
this.jg.clear();
for (i=1;i<this.nPunts;i++)
{
this.jg.drawLine(
(this.arrayX[i-1]-this.kaMap.xOrigin), (this.arrayY[i-1]-this.kaMap.yOrigin),
(this.arrayX[i]-this.kaMap.xOrigin),
(this.arrayY[i]-this.kaMap.yOrigin)); // co-ordinates related to
"myCanvas"
}
this.jg.drawLine((this.arrayX[0]-this.kaMap.xOrigin),
(this.arrayY[0]-this.kaMap.yOrigin),
(this.arrayX[this.nPunts-1]-this.kaMap.xOrigin),
(this.arrayY[this.nPunts-1]-this.kaMap.yOrigin)); // co-ordinates
related to "myCanvas"
this.jg.paint();
this.startx = this.endx;
this.starty = this.endy;
};
/**
* myKaArea.onmouseout( e )
*
* called when the mouse leaves theInsideLayer. hide the result box
*
* e - object, the event object or null (in ie)
*/
myKaArea.prototype.onmouseout = function(e) {
e = (e)?e:((event)?event:null);
if (!e.target) e.target = e.srcElement;
this.domObj.style.visibility='hidden';
};
/**
* myKaArea.onmouseout( e )
*
* called when the mouse leaves theInsideLayer. show the result box
*
* e - object, the event object or null (in ie)
*/
myKaArea.prototype.onmouseover = function(e) {
e = (e)?e:((event)?event:null);
if (!e.target) e.target = e.srcElement;
this.domObj.style.visibility='visible';
};
/**
* myKaArea.onmousemove( e )
*
* called when the mouse moves over theInsideLayer.
*
* e - object, the event object or null (in ie)
*/
myKaArea.prototype.onmousemove = function(e) {
e = (e)?e:((event)?event:null);
//show coordinate
var x = e.pageX || (e.clientX +
(document.documentElement.scrollLeft ||
document.body.scrollLeft));
var y = e.pageY || (e.clientY +
(document.documentElement.scrollTop || document.body.scrollTop));
var aPixPos = this.adjustPixPosition( x,y );
var geoCoo= this.kaMap.pixToGeo(aPixPos[0],aPixPos[1]);
var gX = geoCoo[0];
var gY = geoCoo[1];
var gX= (parseInt(gX*10000))/10000;
var gY= (parseInt(gY*10000))/10000;
if(this.input)
{
if(this.kaMap.getCurrentMap().units == 5)
this.input.value = "Lon.: "+gX+" Lat.: "+gY;
else
this.input.value = "X: "+gX+" Y: "+gY;
}
//**//
this.domObj.style.left = (e.clientX+5)+"px";
this.domObj.style.top = (e.clientY+5)+"px";
if(this.startx !== null)
{
this.endx=-aPixPos[0];
this.endy=-aPixPos[1];
}
return false;
} ;
/**
* myKaArea.onmousedown( e )
*
* called when a mouse button is pressed over theInsideLayer.
*
* e - object, the event object or null (in ie)
*/
myKaArea.prototype.onmousedown = function(e) {
e = (e)?e:((event)?event:null);
if (e.button==2) {
this.jg.clear();
this.jg.clear();
this.invalid=false;
this.startx=this.starty=this.endx=this.endy=null;
document.getElementById("measureTot").value="0";
document.getElementById("missatge").value=" ";
this.total = 0.0;
return this.cancelEvent(e);
}
else {
if (this.kaMap.isIE4)
document.onkeydown = kaTool_redirect_onkeypress;
document.onkeypress = kaTool_redirect_onkeypress;
var x = e.pageX || (e.clientX + (document.documentElement.scrollLeft
|| document.body.scrollLeft));
var y = e.pageY || (e.clientY + (document.documentElement.scrollTop
|| document.body.scrollTop));
var aPixPos = this.adjustPixPosition( x,y );
if(this.endx == null)
{
this.arrayX[0]=this.startx=this.endx=-aPixPos[0];
this.arrayY[0]=this.starty=this.endy=-aPixPos[1];
this.nPunts=1;
}
else
{
this.arrayX[this.nPunts]=this.endx=-aPixPos[0];
this.arrayY[this.nPunts]=this.endy=-aPixPos[1];
this.nPunts++;
}
this.drawPolygon();
if (this.validPolygon())
{
this.total = this.measurePolygonArea();
document.getElementById("measureTot").value = parseInt(this.total*100)/100;
}
else
{
document.getElementById("measureTot").value = 0;
document.getElementById("missatge").value = "Polígon incorrecte";
}
e.cancelBubble = true;
e.returnValue = false;
if (e.stopPropogation) e.stopPropogation();
if (e.preventDefault) e.preventDefault();
return false;
}
};
/**
* myKaArea.onmouseup( e )
*
* called when a mouse button is clicked over theInsideLayer.
*
* e - object, the event object or null (in ie)
*/
myKaArea.prototype.onmouseup = function(e) {
e = (e)?e:((event)?event:null);
return false;
};
myKaArea.prototype.validPolygon = function()
{
if (this.invalid)
return false;
else if (this.nPunts<4)
return true;
else
{
var p3 = this.kaMap.pixToGeo(this.arrayX[this.nPunts-1],this.arrayY[this.nPunts-1]);
var p2 = this.kaMap.pixToGeo(this.arrayX[this.nPunts-2],this.arrayY[this.nPunts-2]);
for (i=0;i<this.nPunts-3;i++) {
p0 = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);
p1 = this.kaMap.pixToGeo(this.arrayX[i+1],this.arrayY[i+1]);
if (this.lineIntersect(Math.abs(p0[0]),Math.abs(p0[1]),Math.abs(p1[0]),Math.abs(p1[1]),Math.abs(p2[0]),Math.abs(p2[1]),Math.abs(p3[0]),Math.abs(p3[1])))
{
this.invalid = true;
return false;
}
}
p2 = this.kaMap.pixToGeo(this.arrayX[this.nPunts-1],this.arrayY[this.nPunts-1]);
p3 = this.kaMap.pixToGeo(this.arrayX[0],this.arrayY[0]);
for (i=1;i<this.nPunts-2;i++) {
p0 = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);
p1 = this.kaMap.pixToGeo(this.arrayX[i+1],this.arrayY[i+1]);
if (this.lineIntersect(Math.abs(p0[0]),Math.abs(p0[1]),Math.abs(p1[0]),Math.abs(p1[1]),Math.abs(p2[0]),Math.abs(p2[1]),Math.abs(p3[0]),Math.abs(p3[1])))
{
this.invalid=true;
return false;
}
}
return true;
}
};
myKaArea.prototype.lineIntersect = function(x0,y0,x1,y1,x2,y2,x3,y3) {
//codi extret de http://www.whisqu.se/per/docs/math28.htm
var a1,b1,c1,a2,b2,c2,det_inv,m1,m2,x,y;
if ((x1-x0)!=0)
m1 = (y1-y0)/(x1-x0);
else
m1 = 99999.9; // close enough to infinity
if ((x3-x2)!=0)
m2 = (y3-y2)/(x3-x2);
else
m2 = 99999.9; // close enough to infinity
a1 = m1;
a2 = m2;
b1 = -1;
b2 = -1;
c1 = (y0-m1*x0);
c2 = (y2-m2*x2);
// inverse of the determinate
det_inv = 1/(a1*b2 - a2*b1);
// use Kramers rule to compute xi and yi
x=((b1*c2 - b2*c1)*det_inv);
y=((a2*c1 - a1*c2)*det_inv);
if ( (x>=Math.min(x0,x1) && x<=Math.max(x0,x1) && y>=Math.min(y0,y1)
&& y<=Math.max(y0,y1)) && (x>=Math.min(x2,x3) && x<=Math.max(x2,x3) &&
y>=Math.min(y2,y3) && y<=Math.max(y2,y3)) )
return true;
else
return false;
} // end Intersect_Lines
// Implementació del càlcul de l'àrea basada en
http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
// Funciona amb polígons simples (sense encreuaments), tant convexos com còncavs
myKaArea.prototype.measurePolygonArea = function()
{
if (this.nPunts<3)
return 0.0;
else
{
var totalArea = 0;
var i,j;
var pi,pj;
for (i=0;i<this.nPunts;i++) {
j = (i + 1) % this.nPunts;
pi = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);
pj = this.kaMap.pixToGeo(this.arrayX[j],this.arrayY[j]);
totalArea += Math.abs(pi[0]) * Math.abs(pj[1]);
totalArea -= Math.abs(pi[1]) * Math.abs(pj[0]);
}
totalArea /= 2;
return Math.abs(totalArea);
}
};
/*
myKaArea.prototype.lineIntersect = function(x1,y1,x2,y2,x3,y3,x4,y4)
{
// Implementació de la intersecció de segments de línia basada en
http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
// var ua,ub;
//
// ua = (((x4-x3)*(y1-y3))-((y4-y3)*(x1-x3))) /
(((y4-y3)*(x2-x1))-((x4-x3)*(y2-y1)));
// ub = (((x2-x1)*(y1-y3))-((y2-y1)*(x1-x3))) /
(((y4-y3)*(x2-x1))-((x4-x3)*(y2-y1)));
// if (ua>0 && ua<1 && ub>0 && ub<1)
// return true;
// else {
// alert (ua + " ; " + ub);
// return false;
// }
var a1,b1,a2,b2,c1,c2,det,x,y;
a1 = y2-y1;
b1 = x1-x2;
c1 = a1*x1+b1*y1;
a2 = y4-y3;
b2 = x3-x4;
c2 = a2*x3+b2*y3;
det=a1*b2-a2*b1;
x = (b2*c1 - b1*c2)/det;
y = (a1*c2 - a2*c1)/det;
//alert(x +" ; "+y);
if ( x>=Math.min(x3,x4) && x<=Math.max(x3,x4) && y>=Math.min(y3,y4)
&& y<=Math.max(y3,y4) )
return true;
else
return false;
};
*/
/*
// Implementació del càlcul de l'àrea basada en triangles, però que
només funciona amb polígons convexos
myKaArea.prototype.measurePolygonArea = function()
{
if (this.nPunts<3)
return 0.0;
else
{
var i;
var p0,p1,p2;
var totalArea=0.0,area2=0.0;
p0 = this.kaMap.pixToGeo(this.arrayX[0],this.arrayY[0]);
for (i=1;i<this.nPunts-1;i++)
{
p1 = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);
p2 = this.kaMap.pixToGeo(this.arrayX[i+1],this.arrayY[i+1]);
//window.alert("p0="+p0[0]+";"+p0[1] +"\np1="+p1[0]+";"+p1[1]
+"\np2="+p2[0]+";"+p2[1]);
var triangleArea = Math.abs(
Math.abs(p0[0]*p2[1])-Math.abs(p0[0]*p1[1])+Math.abs(p1[0]*p0[1])-Math.abs(p1[0]*p2[1])+Math.abs(p2[0]*p1[1])-Math.abs(p2[0]*p0[1])
);
triangleArea *= 0.5;
//window.alert("Area triangle="+triangleArea);
totalArea += triangleArea;
}
area2=this.measurePolygonArea2();
window.alert("Area total 1 = "+totalArea + ". Area total 2 = "+area2);
return totalArea;
}
};
*/
More information about the ka-Map-users
mailing list