You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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 ? "&center=" + 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:30:59