如何在JavaScript中调整Google Maps多边形节点方向适配SQL Server
问题背景
我用套索工具允许用户在Google Maps上绘制多边形,完成后将多边形保存为JSON格式并适配SQL Server的geography字段。但遇到了方向问题:用户逆时针绘制时保存正常,顺时针绘制则geography字段保存失败。
相关代码
JavaScript捕获多边形的代码
function Polygon() { //metadata this.polygon = null; this.polygon_ = null; this.tract = null; this.zip = null; this._zip = null; this.user = null; this.name = null; //polygon definitions this.linecolor = "#000000"; this.fillcolor = "#000000"; this.opacity = 0.7; this.type = "geoid"; this.strokeweight = 2; //circle dimensions this.center = null; this.radius = null; //rectangle dimensions this.north = null; this.south = null; this.east = null; this.west = null; //polygon dimensions this.vertices = []; this.jsonpoints = []; this.bounds = null; this.getverticies = function () { //TODO: get polygon if (this.type === 'polygon') { this.bounds = new google.maps.LatLngBounds(); points = JSON.parse(this.jsonpoints); for (var i=0; i<points.length; i++) { var point = new google.maps.LatLng(points[i].lat, points[i].lng); // this.ispointinpoly(point); this.vertices[i] = point; this.bounds.extend(point); } } }; this.gettheBounds = function () { this.bounds = this.polygon.getDefaultViewport(); }; this.setkml = function() { }; this.plot = function (map) { if(this.type == 'polygon') { this.getverticies(); this.polygon = new google.maps.Polygon({ paths: this.vertices, strokeColor: this.linecolor, strokeWeight: this.strokeweight, fillColor: this.fillcolor, fillOpacity: this.opacity, map: map }) } else if (this.type == 'circle'){ lat = this.center.substring(this.center.lastIndexOf("(")+1,this.center.lastIndexOf(",")).trim(); lng = this.center.substring(this.center.lastIndexOf(",")+1,this.center.lastIndexOf(")")).trim(); this.polygon = new google.maps.Circle({ strokeColor: this.linecolor, strokeOpacity: this.opacity, strokeWeight: this.strokeweight, fillColor: this.fillcolor, fillOpacity: this.opacity, map: map, center: new google.maps.LatLng(lat, lng), radius: this.radius }) } else if (this.type == 'rectangle'){ this.polygon = new google.maps.Rectangle({ strokeColor: this.linecolor, strokeOpacity: this.opacity, strokeWeight: this.strokeweight, fillColor: this.fillcolor, fillOpacity: this.opacity, map: map, bounds: { north: this.north, south: this.south, east: this.east, west: this.west } }) } else if (this.type == 'geoid'){ var url = window.location.protocol + "//" + window.location.host + "/v7/app_territorybuilder/data/GET_GEOID.cfm?TYPE=GEOID&VALUE=" + this.zip + "&LC=641400FF&LW=3&FC=14F11C2E&F=1&FO=1&zip="+this.zip; // var url = window.location.protocol + "//" + window.location.host + "/v5/GIStest/data/GET_GEOID.cfm?TYPE=GEOID&VALUE=" + this.tract + "&LC=641400FF&LW=3&FC=14F11C2E&F=1&FO=1&zip="+this.zip; // var url = window.location.protocol + "//" + window.location.host + "/v5/GIStest/data/GET_ZIP.cfm?TYPE=GEOID&VALUE=" + this.tract + "&LC=641400FF&LW=3&FC=14F11C2E&F=1&FO=1"; this.polygon_ = new google.maps.KmlLayer(url, { suppressInfoWindows: true, // suppressInfoWindows: false, preserveViewport: false, map: map.map }); } }; this.ispointinpoly = function(point,p){ return google.maps.geometry.poly.containsLocation(point, p) // return google.maps.geometry.poly.containsLocation(point, this.polygon) }; this.savedrawingaspoly = function(event){ this.center = null; this.radius = null; this.north = null; this.south = null; this.vertices = []; this.jsonpoints = []; this.type = event.type; if (this.type === 'circle') { this.type = event.type; this.center = event.overlay.center; this.radius = event.overlay.radius; } else if (this.type === 'rectangle'){ this.north = event.overlay.getBounds().getNorthEast().lat(); this.south = event.overlay.getBounds().getSouthWest().lat(); this.east = event.overlay.getBounds().getNorthEast().lng(); this.west = event.overlay.getBounds().getSouthWest().lng(); } else if (this.type === 'polygon'){ var points = event.overlay.getPath(); console.log(points); console.log(event.overlay.getPaths()); var stringer = '['; for (var i = 0; i < points.getLength() ; i++) { var xy = points.getAt(i); stringer = stringer + ('{"lng":'+xy.lng()+',"lat":'+xy.lat()+'},'); } xy = points.getAt(0); this.jsonpoints = stringer + '{"lng":'+xy.lng()+',"lat":'+xy.lat()+'}]'; } }; this.saveaoi = function() { var datajson = "zip=" + this.zip;//.toString(); // var datajson = "tract=" + this.tract.toString(); // datajson = datajson + "&user=" + this.user.toString(); //Commented by umer on 2019/10/22 datajson = datajson + "&name=" + this.name.toString(); datajson = datajson + "&type=" + this.type.toString(); datajson = datajson + (this.center ? "¢er=" + this.center.toString(): ''); datajson = datajson + (this.radius ? "&radius=" + this.radius.toString(): ''); datajson = datajson + (this.north ? "&north=" + this.north.toString(): ''); datajson = datajson + (this.south ? "&south=" + this.south.toString(): ''); datajson = datajson + (this.east ? "&east=" + this.east.toString(): ''); datajson = datajson + (this.west ? "&west=" + this.west.toString(): ''); datajson = datajson + (this.jsonpoints ? "&vertices=" + this.jsonpoints.toString(): ''); var request = new XMLHttpRequest(); request.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { console.log(JSON.parse(this.responseText)); window.top.location.href = JSON.parse(this.responseText).RETURNURL; } }; request.open('GET', './data/SAVE_AOI.cfm?' + datajson, true); request.send(); }; this.setaoidata = function(DATA) { if (DATA[0][3] == 'circle'){ this.type = DATA[0][3]; this.center = DATA[0][4]; this.radius = DATA[0][5]; } else if (DATA[0][3] == 'rectangle'){ this.type = DATA[0][3]; this.north = DATA[0][6]; this.south = DATA[0][7]; this.east = DATA[0][8]; this.west = DATA[0][9]; } else if (DATA[0][3] == 'polygon'){ this.type = DATA[0][3]; this.jsonpoints = DATA[0][10] } }; this.getaoi = function() { // var datajson = "tract=" + tract.toString(); var datajson = "zip=" + this.zip;//.toString(); // datajson = datajson + "&user=" + user.toString(); datajson = datajson + "&id=" + this.tract.toString(); datajson = datajson + "&name=" + this.name.toString(); var _self = this; var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { _self.setaoidata(JSON.parse(this.responseText).DATA); } }; xhttp.open('GET', './data/GET_AOI_DATA.cfm?' + datajson, false); xhttp.send(); } this.setoptions = function() { this.polygon.setOptions({ strokeColor: this.linecolor, strokeWeight: this.strokeweight, fillColor: this.fillcolor, fillOpacity: this.opacity }); }; }
SQL保存语句
UPDATE [AOI] SET [geography] = CASE [type] WHEN 'circle' THEN GEOGRAPHY::STGeomFromText ('point('+dbo.GetLng(center)+' '+ dbo.GetLat(center)+')',4326) WHEN 'rectangle' THEN geography::STGeomFromText('POLYGON(('+try_cast(east as varchar(100))+' '+try_cast(north as varchar(100))+', '+try_cast(west as varchar(100))+' '+try_cast(north as varchar(100))+', '+try_cast(west as varchar(100))+' '+try_cast(south as varchar(100))+', '+try_cast(east as varchar(100))+' '+try_cast(south as varchar(100))+', '+try_cast(east as varchar(100))+' '+try_cast(north as varchar(100))+'))', 4326) WHEN 'polygon' THEN geography::STGeomFromText('POLYGON(' + replace(replace(replace(replace(replace(vertices,'{"lng":',''),',"lat":',' '),'[','('),']',')'),'}','') + ')', 4326) END WHERE [zip] = #URL.zip# AND [user] = #cookie.UserID# AND [name] = '#URL.name#';
核心问题
用户顺时针绘制多边形时,SQL Server的geography字段保存失败。已知可以在SQL中用ReOrientate()调整,但需要在JavaScript中标准化多边形节点顺序(统一为逆时针或符合SQL要求的方向),避免后续GIS操作和展示时出现点在多边形外的问题。
需求
如何在JavaScript中重新调整多边形节点的方向,以使其能正确保存到SQL Server的geography字段?
内容的提问来源于stack exchange,提问作者arcee123
相关产品推荐
相关产品推荐

