[Mapbender-commits] r3205 - branches/noframes/http/javascripts

svn_mapbender at osgeo.org svn_mapbender at osgeo.org
Fri Nov 7 05:21:36 EST 2008


Author: christoph
Date: 2008-11-07 05:21:35 -0500 (Fri, 07 Nov 2008)
New Revision: 3205

Modified:
   branches/noframes/http/javascripts/geometry.js
Log:
merged from trunk...now supports multigeometries and enclaves

Modified: branches/noframes/http/javascripts/geometry.js
===================================================================
--- branches/noframes/http/javascripts/geometry.js	2008-11-07 10:19:04 UTC (rev 3204)
+++ branches/noframes/http/javascripts/geometry.js	2008-11-07 10:21:35 UTC (rev 3205)
@@ -102,8 +102,11 @@
  * @type Point
  * @returns the Point object at the given indices
  */
-GeometryArray.prototype.getPoint = function(i,j,k){
-	return this.get(i).get(j).get(k);
+GeometryArray.prototype.getPoint = function(i, j, k, l){
+	if (l == undefined) {
+		return this.get(i).get(j).get(k);
+	}
+	return this.get(i).get(j).innerRings.get(k).get(l);
 };
 
 /**
@@ -128,7 +131,9 @@
  * @param {Integer} j index of the Geometry
  */
 GeometryArray.prototype.delGeometry = function(i,j){
-	if (this.get(i).del(j) === false) {this.del(i);}
+	if (this.get(i).del(j) === false) {
+		this.del(i);
+	}
 };
 	
 /**
@@ -138,9 +143,11 @@
  * @param {Integer} j index of the Geometry
  * @param {Integer} k index of the Point
  */
-GeometryArray.prototype.delPoint = function (i,j,k){
-	var res = this.get(i).delPoint(j,k);
-	if (res === false) {this.del(i);}
+GeometryArray.prototype.delPoint = function (i, j, k, l) {
+	var res = this.get(i).delPoint(j, k, l);
+	if (res === false) {
+		this.del(i);
+	}
 };
 	
 /**
@@ -152,8 +159,12 @@
 		this.delGeometry(-1, -1);
 	}
 	else {
-		if (this.get(-1).get(-1).count() === 0) {this.get(-1).del(-1);}
-		if (this.get(-1).count() === 0) {this.del(-1);}
+		if (this.get(-1).get(-1).count() === 0) {
+			this.get(-1).del(-1);
+		}
+		if (this.get(-1).count() === 0) {
+			this.del(-1);
+		}
 	}
 	
 };
@@ -169,6 +180,22 @@
 		finished = true;
 		for (var i = 0 ; finished === true && i < this.count() ; i++){
 			for (var j = 0 ; finished === true && j < this.get(i).count() ; j++){
+
+				var currentGeometry = this.get(i).get(j);
+				if (currentGeometry.geomType == geomType.polygon && currentGeometry.innerRings) {
+					for (var k = 0; finished === true && k < currentGeometry.innerRings.count(); k++) {
+						for (var l = 0; finished === true && l < currentGeometry.innerRings.get(k).count(); l++) {
+							if (this.getPoint(i, j, k, l).equals(point)) {
+								this.delPoint(i, j, k, l);
+								finished = false;
+							}
+						}
+					}
+				}
+				if (!finished) {
+					break;
+				}
+
 				for (var k = 0 ; finished === true && k < this.get(i).get(j).count() ; k++){
 					if (this.getPoint(i,j,k).equals(point)){
 						this.delPoint(i,j,k);
@@ -247,36 +274,37 @@
 	var geometryType = tmpArray[0];
 
 	switch (geometryType) {
-		case "POLYGON":
-			var text = text.replace(/\)/, "");
-			text = text.replace(/\(\(/, "(");
-			var tmpArray = text.split("(");
-
-			var coordinatesArray = tmpArray[1].split(",");
-
-			this.addMember(geomType.polygon);
-			this.get(-1).addGeometry();
-			for (var m = 0; m < -1 + coordinatesArray.length; m++) {
-				var currentPoint = coordinatesArray[m].split(" ");
-				this.getGeometry(-1, -1).addPointByCoordinates(parseFloat(currentPoint[0]), parseFloat(currentPoint[1]));
-			}
-			this.close();
-			break;
 		case "MULTIPOLYGON":
-			var text = text.replace(/\)/, "");
-			text = text.replace(/\(\(\(/, "(");
-
-			var tmpArray = text.split("(");
-
-			var coordinatesArray = tmpArray[1].split(",");
-
+			var text = text.replace(/\)/g, "");
+			var sepArray = text.split("(((");
+			var polyArray = sepArray[1].split(",((");
+			
 			this.addMember(geomType.polygon);
-			this.get(-1).addGeometry();
-			for (var m = 0; m < -1 + coordinatesArray.length; m++) {
-				var currentPoint = coordinatesArray[m].split(" ");
-				this.getGeometry(-1, -1).addPointByCoordinates(parseFloat(currentPoint[0]), parseFloat(currentPoint[1]));
+			for (var i = 0; i < polyArray.length; i++) {
+				var ringArray = polyArray[i].split(",(");
+				for (var j = 0; j < ringArray.length; j++) {
+					var coordinatesArray = ringArray[j].split(",");
+					if (j === 0) {
+						// add outer ring
+						this.get(-1).addGeometry();
+						for (var m = 0; m < -1 + coordinatesArray.length; m++) {
+							var currentPoint = coordinatesArray[m].split(" ");
+							this.getGeometry(-1, -1).addPointByCoordinates(parseFloat(currentPoint[0]), parseFloat(currentPoint[1]));
+						}
+						this.close();
+					}		
+					else {
+						// add inner ring
+						var ring = new Geometry(geomType.polygon);
+						for (var m = 0; m < -1 + coordinatesArray.length; m++) {
+							var currentPoint = coordinatesArray[m].split(" ");
+							ring.addPointByCoordinates(parseFloat(currentPoint[0]), parseFloat(currentPoint[1]));
+						}
+						ring.close();
+						this.getGeometry(-1,-1).addInnerRing(ring);				
+					}
+				}
 			}
-			this.close();
 			break;
 	}
 };
@@ -533,7 +561,6 @@
 			var tmpLength = this.count() - 1;
 			for (var z = i; z < tmpLength ; z ++){
 				this.list[z] = this.list[z+1];
-				e[z] = e[z+1];
 			}
 			this.list.length -= 1;
 			if (this.list.length === 0) {return false;}
@@ -661,9 +688,20 @@
  * @return true if the deletion succeded; else false.
  * @type Boolean
  */
-MultiGeometry.prototype.delPoint = function(i,j){
-	var res = this.get(i).del(j);
-	if (res === false) {return this.del(i);}
+MultiGeometry.prototype.delPoint = function(i, j, k){
+	var res;
+	if (k == undefined) {
+		res = this.get(i).del(j);
+		if (res === false) {
+			return this.del(i);
+		}
+	}
+	else {
+		res = this.get(i).innerRings.get(j).del(k);
+		if (res === false) {
+			this.get(i).innerRings.del(j);
+		}
+	}
 	return true;
 };
 
@@ -679,27 +717,20 @@
 	var numOfGeom = this.count();
 	if (numOfGeom >= 1) {
 		if (this.geomType == geomType.polygon) {
-			text += "POLYGON (";
-
-			for (var i = 0; i < this.count(); i++) {
-				if (i > 0) {
-					text += ", ";
-				}
-				text += "(";
-
-				var currentPolygon = this.get(i);
-				for (var j = 0; j < currentPolygon.count(); j++) {
-					if (j > 0) {
+			if (numOfGeom > 1) {
+				text += "MULTIPOLYGON (";
+				for (var i = 0; i < numOfGeom; i++) {
+					if (i > 0) {
 						text += ", ";
 					}
-	
-					var currentPoint = currentPolygon.get(j);
-					text += currentPoint.x + " " + currentPoint.y
+					var currentPolygon = this.get(i);
+					text += "(" + currentPolygon.toText() + ")";
 				}
-
 				text += ")";
 			}
-			text += ")";
+			else {
+				text += "POLYGON (" + this.get(0).toText() + ")";
+			}
 		}
 		else if (this.geomType == geomType.line) {
 			text += "LINESTRING (";
@@ -780,6 +811,13 @@
 	return false;
 };
 
+
+function InnerRings () {
+	this.list = [];	
+};
+
+InnerRings.prototype = new List();
+
 /**
  * @class a Geometry is a List of Point objects. If it is a polygon, the last point has 
  * to equal the first point.
@@ -988,10 +1026,44 @@
 
 	this.geomType = aGeomtype;
 	this.name = nameGeometry;
+
+	// add these members if the geometry is a polygon
+	if (this.geomType == geomType.polygon) {
+		this.innerRings = new InnerRings();
+		this.addInnerRing = function (somePolygon) {
+			this.innerRings.add(somePolygon);
+		};
+		this.delInnerRing = function (index) {
+			this.innerRings.del(index);
+		};
+	}
 }
 
 Geometry.prototype = new List();
 
+Geometry.prototype.toText = function () {
+	var text = "";
+	switch (this.geomType) {
+		case geomType.polygon:
+			text += "(";
+			for (var j = 0; j < this.count(); j++) {
+				if (j > 0) {
+					text += ", ";
+				}
+				var currentPoint = this.get(j);
+				text += currentPoint.x + " " + currentPoint.y
+			}
+			text += ")";
+			if (this.innerRings && this.innerRings.count() > 0) {
+				for (var k = 0; k < this.innerRings.count(); k++) {
+					text += ", ";
+					text += this.innerRings.get(k).toText();
+				}				
+			}
+			break;
+	}
+	return text;
+};
 /**
  * gets the bounding box of this {@link Geometry}
  *
@@ -1010,6 +1082,19 @@
 		if (pos.y < min.y) {min.y = pos.y;}
 		else if (pos.y > max.y) {max.y = pos.y;}
 	}
+	if (this.geomType == geomType.polygon) {
+		for (var i = 0; i < this.innerRings.count(); i++) {
+			var currentRing = this.innerRings.get(i);
+			for (var j=0; j<currentRing.count(); j++){
+				var pos = currentRing.get(j);
+				if (pos.x < min.x) {min.x = pos.x;}
+				else if (pos.x > max.x) {max.x = pos.x;}
+				if (pos.y < min.y) {min.y = pos.y;}
+				else if (pos.y > max.y) {max.y = pos.y;}
+			}
+		}
+	}
+	
 	return [min, max];
 };
 
@@ -1031,6 +1116,22 @@
 			else {this.updatePointAtIndex(newP, i);}
 		}
 	}
+	if (this.geomType == geomType.polygon) {
+		for (var j = 0; j < this.innerRings.count(); j++) {
+			var len = this.innerRings.get(j).count();
+			for (var i = 0; i < len ; i++){
+				if (oldP.equals(this.innerRings.get(j).get(i))){
+					if (i>0 && newP.equals(this.innerRings.get(j).get(i-1))){
+						this.innerRings.get(j).del(i);
+						len--;
+						i--;
+					}
+					else {this.innerRings.get(j).updatePointAtIndex(newP, i);}
+				}
+			}
+			
+		}
+	}
 };
 
 /**
@@ -1046,9 +1147,130 @@
 	for (var i=0; i < this.count(); i++) {
 		if (!this.get(i).equals(geom.get(i))) {return false;}
 	}
+	if (!this.innerRings && !geom.innerRings) {
+		// no inner rings; fine
+	}
+	else if (this.innerRings && geom.innerRings) {
+		if (this.innerRings.count() != geom.innerRings.count()) {
+			return false;
+		}
+		for (var j = 0; j < this.innerRings.count(); j++) {
+			if (!this.innerRings.get(j).equals(geom.innerRings.get(j))) {
+				return false;
+			}
+		}
+	}
+	else {
+		// inner ring mismatch
+		return false;
+	}	
 	return true;
 };
 
+/**
+ * creates a polygon geometry object which form a buffer around the line geometry
+ * 
+ * @param {float} real world units to buffer around the line
+ * @param {float} (optional) units to buffer around the line in Y direction
+ * 
+ * @return linebuffer polygon
+ * @type Geometry
+ */
+Geometry.prototype.bufferLine = function(bufferX, bufferY){
+	if(typeof(bufferY)=='undefined')
+		bufferY = bufferX;
+	if(this.geomType!=geomType.line || this.count()<2)
+		return false;
+	
+	var ret = new Geometry(geomType.polygon)
+	
+	//get vector from point 0 to point 1
+	last_vec = this.get(1).minus(this.get(0));
+
+	//get 90° rotated vector
+	last_vec_o = new Point(-last_vec.y, last_vec.x);
+
+	//resize vectors with apropriate linebuffer length
+	last_vec_o = last_vec_o.dividedBy(last_vec_o.dist(new Point(0,0)));
+	last_vec_o.x*=bufferX; last_vec_o.y*=bufferY;
+	last_vec = last_vec.dividedBy(last_vec.dist(new Point(0,0)));
+	last_vec.x*=bufferX; last_vec.y*=bufferY;
+		
+	//add first pointsets
+	ret.list.unshift(this.get(0).plus(last_vec_o).minus(last_vec));
+	ret.list.push(this.get(0).minus(last_vec_o).minus(last_vec));
+		
+	for(var i=1;i<this.count()-1;i++){
+		//get vector from point n to point n+1
+		vec = this.get(i+1).minus(this.get(i));
+		//get orthogonal (90° rotated) vector		
+		vec_o = new Point(-vec.y, vec.x);
+
+		//resize vectors to linebuffer length
+		vec_o = vec_o.dividedBy(vec_o.dist(new Point(0,0)));
+		vec_o.x*=bufferX; vec_o.y*=bufferY;
+		vec = vec.dividedBy(vec.dist(new Point(0,0)));
+		vec.x*=bufferX; vec.y*=bufferY;
+			
+		//if direction is the same continue
+		if(vec.equals(last_vec))
+			continue;
+			
+		// calculate directed angle between the two vectors by 
+		// calculating the argument diffenrences between complex numbers
+		// arg(x + i*y) (because law of cosine can onlycalculate undirected angle)
+		var angle = (Math.atan2(vec.x,vec.y)-Math.atan2(last_vec.x,last_vec.y))
+		//ensure that angle is -180<=angle<=180
+		if(angle<-Math.PI)angle=2*Math.PI+angle;
+		if(angle>+Math.PI)angle=2*Math.PI-angle;
+		
+		//calculate the distance between the next points on boundary
+		//and the line point
+		//the point will be in the direction of angle/2 relative to last_vec_o
+		//since cosine is adjacent side / hypothenuse and we know that 
+		//the adjacent side is lineBuffer the hypothenus (our distance) is
+		var ndist = 1/(Math.cos(angle/2))
+		//direction of next points on boundary
+		var int_vec = vec_o.plus(last_vec_o);
+		//resize direction vector to our distance
+		int_vec = int_vec.times(ndist/int_vec.dist(new Point(0,0)));
+		int_vec.x*=bufferX; int_vec.y*=bufferY;
+		
+		//look if we have an outer sharp corner (>90°)
+		if(angle>Math.PI/2){
+			//push cutted edge points
+			ret.list.unshift(this.get(i).plus(last_vec_o).plus(last_vec));
+			ret.list.unshift(this.get(i).plus(vec_o).minus(vec));
+		}
+		else{
+			//push inner/light edge
+			ret.list.unshift(this.get(i).plus(int_vec));
+		}
+
+		//look if we have an inner sharp corner (<-90°)
+		if(angle<-Math.PI/2){
+			//push cutted edge points
+			ret.list.push(this.get(i).minus(last_vec_o).plus(last_vec));
+			ret.list.push(this.get(i).minus(vec_o).minus(vec));
+		}
+		else{
+			//push inner/light edge
+			ret.list.push(this.get(i).minus(int_vec));
+		}
+			
+		//copy for next point
+		last_vec = vec;
+		last_vec_o = vec_o;
+	}
+	//add last pointsets
+	ret.list.unshift(this.get(i).plus(last_vec_o).plus(last_vec));
+	ret.list.push(this.get(i).minus(last_vec_o).plus(last_vec));
+	
+	ret.close();
+
+	return ret;	
+}
+
 Geometry.prototype.toString = function () {
 	var str = "";
 	
@@ -1066,6 +1288,20 @@
 			}
 			str += this.get(i).toString();
 		}
+
+		if (typeof(this.innerRings) == "object" && this.innerRings.count() > 0) {
+			for (var j = 0; j < this.innerRings.count(); j++) {
+				var currentRing = this.innerRings.get(j);
+
+				str += "],[";
+				for (var i = 0; i < currentRing.count(); i++) {
+					if (i > 0) {
+						str += ", ";
+					}
+					str += currentRing.get(i).toString();
+				}
+			}
+		}
 		str += "]]}";
 	}
 	else if (this.geomType == geomType.line) {
@@ -1272,6 +1508,26 @@
 		else if(t == geomType.line || t==geomType.polygon) {
 			for(var i=0, ilen = g.count(); i < ilen; i++){
 				var currentGeom = g.get(i);
+				// paint inner rings
+				if (t==geomType.polygon && currentGeom.innerRings.count() > 0) {
+					for (var k = 0; k < currentGeom.innerRings.count(); k++) {
+						var currentRing = currentGeom.innerRings.get(k);
+						var previousPoint = realToMap(mapframe, currentRing.get(0));
+						for (var j=1, jlen = currentRing.count(); j < jlen; j++) {
+							(function () {
+								var currentPoint = realToMap(mapframe, currentRing.get(j));
+								
+								var pq = calculateVisibleDash(previousPoint, currentPoint, mapframeWidth, mapframeHeight);
+								if (pq) {
+									drawLine([pq[0].x-1, pq[1].x-1], [pq[0].y-1, pq[1].y-1], col);
+								}
+								previousPoint = currentPoint;
+							})();
+						}
+						
+					}					
+				}
+				// paint line or outer ring
 				var previousPoint = realToMap(mapframe, currentGeom.get(0));
 				for (var j=1, jlen = currentGeom.count(); j < jlen; j++) {
 					(function () {
@@ -1468,7 +1724,16 @@
 	 * @param {String} color a color
 	 */	
 	this.del = function(m, color) {
-		var a = gA.findMultiGeometry(m);
+		var newMultiGeom;
+		if (m.name == nameMultiGeometry) {
+			newMultiGeom = m;
+		}
+		else if (m.name == nameGeometry) {
+			var newMultiGeom = new MultiGeometry(m.geomType);
+			newMultiGeom.add(m);
+		}
+
+		var a = gA.findMultiGeometry(newMultiGeom);
 		var del = false;
 		for (var i=0; i<a.length && del === false; i++) {
 			if (gA.get(a[i]).color == color) {
@@ -1485,7 +1750,15 @@
 	 * @param {String} color the color of the highlight
 	 */	
 	this.add = function(m, color) {
-		gA.addCopy(m);
+
+		if (m.name == nameMultiGeometry) {
+			gA.addCopy(m);
+		}
+		else if (m.name == nameGeometry) {
+			var newMultiGeom = new MultiGeometry(m.geomType);
+			newMultiGeom.add(m);
+			gA.addCopy(newMultiGeom);
+		}
 		if (typeof(color) != 'undefined') {gA.get(-1).color = color;} 
 		else {gA.get(-1).color = lineColor;}
 	};
@@ -1717,6 +1990,19 @@
 		if (geom.name == nameGeometryArray || geom.name == nameMultiGeometry){
 			for (var j = 0 ; j < geom.get(i).count() ; j++){
 				if (geom.get(i).name == nameMultiGeometry){
+					// inner rings
+					if (geom.get(i).get(j).geomType == geomType.polygon && geom.get(i).get(j).innerRings && geom.get(i).get(j).innerRings.count() > 0) {
+						for (var l = 0; l < geom.get(i).get(j).innerRings.count(); l++) {
+							var currentRing = geom.get(i).get(j).innerRings.get(l);
+							for (var k = 0 ; k < currentRing.count() ; k++){
+								if ((currentRing.isComplete() === true && typeof(point) == 'undefined') || (typeof(point) != 'undefined' && !currentRing.get(k).equals(point))){
+									this.add(currentRing.get(k));
+								}
+							}
+							
+						}
+					}
+					// lines, points, outer rings
 					for (var k = 0 ; k < geom.get(i).get(j).count() ; k++){
 						if ((geom.get(i).get(j).isComplete() === true && typeof(point) == 'undefined') || (typeof(point) != 'undefined' && !geom.get(i).get(j).get(k).equals(point))){
 							this.add(geom.getPoint(i, j, k));



More information about the Mapbender_commits mailing list