[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>&nbsp;&Agrave;rea: <input
type='text' id='measureTot'
style='border:none;background-color:transparent;width:75px;' />" +
this.unitsAbrevations[this.kaMap.getCurrentMap().units] +
"2<br/>&nbsp;<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