zoukankan      html  css  js  c++  java
  • SkylineGlobe 邻近度(Proximity)分析JavaScript源代码

    邻近度(Proximity)描述了地理空间中两个地物距离相近的程度,是空间分析的一个重要手段。

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>ToolTitle</title>
    
    
        <script language="javascript" src="ToolsCommon65.js"></script>
    
        <link rel="StyleSheet" href="Style.css" type="text/css">
        <style>
            .MenuButton
            {
                height: 78px;
                width: 65px;
                margin: 5px;
                white-space: normal;
            }
            .MenuButtonHighlight
            {
                color: Red;
                font-weight: bold;
            }
        </style>
    </head>
    <body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0" style="border: 0;
        overflow: auto; background-color: #ffffff" id="Body" onload="Init()" onunload="Reset(0,0);DeleteTarget();">
        <!--oncontextmenu="return false;"  onclick="bHide=true;HideOptionsNow()" > -->
           <table border="0" width="100%" cellspacing="0" cellpadding="2">
            <tr>
                <td id="TopAreaTD" height="50px" width="100%" valign="middle" style="background-color: #CAD8E2">
                    <table border="0" width="100%" cellspacing="0" cellpadding="0">
                        <tr>
                            <td width="12px"></td>
                            <td width="55px"><img src="images/ProximityIcon.gif" align="absmiddle" /></td>
                            <td id="TitleTD" align="center" class="s12b  i18n">ToolName</td>
                            <!--<td valign="top" align="right" id="CloseHelpTd"><img src="../CommonImg/help.gif" border="0" class="i18n" alt="help" title="help" onclick="DisplayHelpPopup6 (SGLang.i18nFile('help.html'),SGLang.i18n('help'))" style="cursor: pointer;"></td>-->
                        </tr>
                    </table>
                </td>
            </tr>
            <tr height="1px">
                <td style="background-repeat: repeat-x;" background="../CommonImg/separator.gif">
                </td>
            </tr>
            <tr>
                <td>
                    <br />
                </td>
            </tr>
        </table>
                   <table border="0" cellspacing="1" cellpadding="3" bgcolor="#ffffff" class="s8" width="100%">
                        <tr >
                            <td class="s8b">
                                <label for="createAs" class="i18n">Text30</label>
                            </td>
                            <td align="left">
                            <input id="targetID"  type="text"  value="" style="100px" readonly="readonly"/>
    <!--                        &nbsp;&nbsp;<button id="SetTargetFromSelected" type="button" onclick="SetTargetFromSelectedPress()"><span id="Span1" class="i18n">Text31</span></button>
                            &nbsp;&nbsp;<button id="CreateTarget" type="button" onclick="CreateTargetPress()"><span id="Span3" class="i18n">Text43</span></button>-->
                            <br />
                            <a id="SetTargetFromSelected" class="link i18n" onclick="SetTargetFromSelectedPress();">Text31</a> | 
                            <a id="CreateTarget" class="link i18n" class="link" onclick="CreateTargetPress();">Text43</a></div>
                            </td>            
                        </tr>  
                        <tr class='TableOtherLine'>
                            <td class="s8b">
                                <label for="createAs" class="i18n">Text32</label>
                            </td>
                            <td align="left">
                            <input id="trackedGroupID"  type="text"  value="" style="100px" readonly="readonly"/>
                            <!--&nbsp;&nbsp;<button id="SetGroupFromSelected" type="button" onclick="SetGroupFromSelectedPress()"><span id="Span2" class="i18n">Text31</span></button>-->
                            <br />
                            <a id="SetGroupFromSelected" class="link i18n" onclick="SetGroupFromSelectedPress();">Text31</a> <span id="Span1" >
                            </td>            
                        </tr>
                       <tr >
                            <td align="top" class="s8b i18n">
                                <label for="createAs" class="i18n">Text33</label>
                            </td>
                            <td align="left">
                            <input id="warningRadiusID"  type="text"  value="700"  style="100px; background-color:#FFD7C1"/><label for="createAs" class="i18n">Text35</label>
                            </td>
                        </tr>
                        <tr class='TableOtherLine'>
                            <td class="s8b">
                                <label for="createAs" class="i18n">Text34</label>
                            </td>
                            <td align="left">
                            <input id="dangerRadiusID"  type="text" value="300"  style="100px; background-color:#FFD7D7;"/><label for="createAs" class="i18n">Text35</label>
                            </td>            
                        </tr>  
                        <tr >
                            <td class="s8b">
                                <label for="createAs" class="i18n">Text42</label>
                            </td>
                            <td align="left">
                            <input id="chkTint" type="checkbox" style="20px;" onclick="bTint = document.getElementById('chkTint').checked;" checked="checked"/>
                            </td>            
                        </tr> 
                        <tr>
                            <td colspan="2" valign="top" class="s8b i18n" align="center">
                            
                        <button id="startStopButton" class="MenuButton" onclick="StartStop()"><img src="images/startCursor.gif" /><br /> <span id="startstopSpan" class="i18n">Text36</span></button> 
    
                            </td>
                            </tr>
        </table>
    
     <object id="SGWorld" classid="CLSID:3a4f9197-65a8-11d5-85c1-0001023952c1">    </object>
    
    
    <script language="JavaScript">
    function DetectTEMode()
    {
    var vMode = document.documentMode;
    var rMode = 'IE5 Quirks Mode';
    if(vMode == 8){
      rMode = 'IE8 Standards Mode';
    } else if(vMode == 7){
      rMode = 'IE7 Strict Mode';
    } else if(vMode == 9){
      rMode = 'IE9 Strict Mode';
    }
    //alert('Rendering in: ' + rMode);
    }
    DetectTEMode();
    
    //***delete the uneeded ones at the end
    var gDisplayHeadingSlope ;
    var gDisplayMinMaxSlope ;
    var gDisplayCoordinateInfo;
    var gLastClickMouseX;
    var gLastClickMouseY;
    ///var popupMsg;
    var timeoutID;
    var measureDistance;
    var warningSlope;
    var alertSlope;
    var arrowMaxPositive;
    var arrowMaxNegative;
    var arrowHeading;
    var labelMaxPositive;
    var labelMaxNegative;
    var labelHeading;
    var labelCoordinateInfo;
    var groupID;
    var colorNormalPositive ;
    var colorNormalNegative;
    var colorHeading;
    var colorLinewarning ;
    var colorLineAlert;
    var colorLabel;
    var colorTextNormal;
    var colorTextWarning;
    var colorTextAlert;
    var gNameIndex = 1;
    
    var cameraClickPos;
    var rootId;
    
    //Proximity globals
    var isStart = false;
    var warningRadius;
    var dangerRadius;
    var targetObj;
    var trackedObjArray = [];
    var colorLineWarning;
    var colorLineDanger;
    var bTint = true;
    var tmpGroup;
    var bInPlaceTarget = false;
    var manualTargetLabel;
    
    //--------------
    // Init
    function Init() {
    
        targetObj = null;
        manualTargetLabel = null;
    
        SGWorld.AttachEvent("onFrame", onFrame);
    
        colorLineWarning = SGWorld.Creator.CreateColor(238, 173, 23, 255);
        colorLineDanger = SGWorld.Creator.CreateColor(255, 117, 117, 255);
    
        Reset(true, false);
    
        TargetPathNameParam = GetParamValue("TargetPathName", "");
        if (TargetPathNameParam != "")
            SetTargetFromPathName(TargetPathNameParam);
        else {
            if (SGWorld.ProjectTree.FindItem("Target") != 0)
                SetTargetFromPathName("Target");
        }
    
        TrackedGroupPathNameParam = GetParamValue("TrackedGroupPathName", "");
        if (TrackedGroupPathNameParam != "")
            SetTrackedGroupFromPathName(TrackedGroupPathNameParam);
        else {
            if (SGWorld.ProjectTree.FindItem("Tracked Group") != 0)
                SetTrackedGroupFromPathName("Tracked Group");
        }
    
        if (document.getElementById("targetID").value != "" && document.getElementById("trackedGroupID").value != "")
            StartStop();
    
    
    }
    
    //------------
    //onFrame
    function onFrame() {
        if (isStart == false || targetObj == null)
            return;
    
        displayProximityInfo();
    
    }
    
    //--------------
    // SetTargetFromSelectedPress
    function SetTargetFromSelectedPress() {
        var node = SGWorld.ProjectTree.GetNextItem("", 10);
        if (node == 0 || SGWorld.ProjectTree.IsGroup(node)) {
            alert(SGLang.i18n("Text38"));
            return;
        }
        SetTarget(node);    
    }
    
    //--------------
    // SetTargetFromPathName
    function SetTargetFromPathName(pathName) {
        var node = SGWorld.ProjectTree.FindItem(pathName);
        if (node == 0 || SGWorld.ProjectTree.IsGroup(node)) {
            alert(SGLang.i18n("Text38"));
            return;
        }
        SetTarget(node);    
    }
    
    //--------------
    // SetTarget
    function SetTarget(node) {
    
        try {
            var object = SGWorld.ProjectTree.GetObject(node);
            var targetPosition = object.Position;
            if (!targetPosition) {
                alert(SGLang.i18n("Text38"));
                return;
            }
            document.getElementById("targetID").value = object.TreeItem.Name;
            DeleteTarget();
            targetObj = object;
        }
        catch (err) {
            alert(SGLang.i18n("Text38"));
            return;
        }
    }
    
    //--------------
    // CreateTargetPress
    function CreateTargetPress() {
        if (!bInPlaceTarget) {
            bInPlaceTarget = true;
            SGWorld.AttachEvent("OnLButtonUp", CreateTarget);
            SGWorld.AttachEvent("OnRButtonUp", CreateTargetRButtonUp);
            SGWorld.AttachEvent("OnInputModeChanged", ResetCreateTarget);
    
            document.getElementById("CreateTarget").innerText = SGLang.i18n("Text46");
    
            SGWorld.Window.SetInputMode(1, abspath() + "/cursor_m.cur");
            SGWorld.Window.ShowMessageBarText(SGLang.i18n("Text44"));
        }
        else {
            ResetCreateTarget();
        }
    }
    
    //--------------
    // CreateTargetRButtonUp
    function CreateTargetRButtonUp(Flags, X, Y) {
        ResetCreateTarget();
    }
    
    //--------------
    // ResetCreateTarget
    function ResetCreateTarget() {
        document.getElementById("CreateTarget").innerText = SGLang.i18n("Text43");
    
        SGWorld.DetachEvent("OnLButtonUp", CreateTarget);
        SGWorld.DetachEvent("OnInputModeChanged", ResetCreateTarget);
        bInPlaceTarget = false;
        SGWorld.Window.SetInputMode(0);
    }
    
    //--------------
    // CreateTarget
    function CreateTarget(Flags, X, Y) {
        var CursorCoord = SGWorld.Window.pixelToWorld(X, Y);
        if (CursorCoord == null)
            ResetCreateTarget();
    
        var imageLabelStyle = SGWorld.Creator.CreateLabelStyle(0);
        imageLabelStyle.Scale = 1.0;
    
        DeleteTarget();
    
        manualTargetLabel = SGWorld.Creator.CreateImageLabel(CursorCoord.Position, abspath() + "/Images/icon.png", imageLabelStyle, SGWorld.ProjectTree.HiddenGroupID, SGLang.i18n("Text45"));
        manualTargetLabel.SaveInFlyFile = false;
        document.getElementById("targetID").value = manualTargetLabel.TreeItem.Name;
        targetObj = manualTargetLabel;
        ResetCreateTarget();
    }
    
    //--------------
    // DeleteTarget
    function DeleteTarget() {
        if (manualTargetLabel != null) {
            SGWorld.Creator.DeleteObject(manualTargetLabel.ID);
            manualTargetLabel = null;
        }
    }
    
    
    //--------------
    // SetGroupFromSelectedPress
    function SetGroupFromSelectedPress() {
        var node = SGWorld.ProjectTree.GetNextItem("", 10);
        SetTargetGroup(node);
    }
    
    //--------------
    // SetTrackedGroupFromPathName
    function SetTrackedGroupFromPathName(pathName) {
        var node = SGWorld.ProjectTree.FindItem(pathName);
        SetTargetGroup(node);
    }
    
    
    //--------------
    // SetGroupFromSelectedPress
    function SetTargetGroup(nodeID) {
        var node = nodeID;
        /*To allow layers as well ViewshedQuery tool uses:     if (node == 0 || !(SGWorld.ProjectTree.IsGroup(node) || SGWorld.ProjectTree.IsLayer(node))) { */
        if (node == 0 || SGWorld.ProjectTree.IsLayer(node)) {
            alert(SGLang.i18n("Text39"));
            return;
        }
        if (SGWorld.ProjectTree.IsGroup(node)) {//group
            EmptytrackedObjArray();
            searchObjects2(node, AddObjectToArray);
            document.getElementById("trackedGroupID").value = SGWorld.ProjectTree.GetItemName(node);
        }
        else {//object
            var object = SGWorld.ProjectTree.GetObject(node);
            var trackedPosition = object.Position;
            if (!trackedPosition) {
                alert(SGLang.i18n("Text38"));
                return;
            }
    
            EmptytrackedObjArray();
            PushtrackedObj2Array(object);
            document.getElementById("trackedGroupID").value = object.TreeItem.Name;
        }
    
    }
    
    
    
    //--------------
    // StartStop
    function StartStop() {
        if (!isStart) {
            isStart = true;
            document.getElementById("targetID").disabled = true;
            document.getElementById("SetTargetFromSelected").disabled = true;
            document.getElementById("CreateTarget").disabled = true;
            document.getElementById("trackedGroupID").disabled = true;
            document.getElementById("SetGroupFromSelected").disabled = true;
            document.getElementById("warningRadiusID").disabled = true;
            document.getElementById("dangerRadiusID").disabled = true;
            document.getElementById("chkTint").disabled = true;
            
    
            startstopSpan.innerHTML = SGLang.i18n("Text37");
    
            warningRadius = document.getElementById("warningRadiusID").value;
            dangerRadius = document.getElementById("dangerRadiusID").value;
    
        }
        else {
            Reset(false, false);
        }
    
    }
    
    //------------------
    // Reset
    //------------------
    function Reset(FirstTime, FromMouseInputMode) {
    
        try {
            startstopSpan.innerHTML = SGLang.i18n("Text36");
            if (isStart && SGWorld.Project.Name != "") {
                isStart = false;
                deleteObjs();
            }
            isStart = false;
    
            document.getElementById("targetID").disabled = false;
            document.getElementById("SetTargetFromSelected").disabled = false;
            document.getElementById("trackedGroupID").disabled = false;
            document.getElementById("SetGroupFromSelected").disabled = false;
            document.getElementById("warningRadiusID").disabled = false;
            document.getElementById("dangerRadiusID").disabled = false;
            document.getElementById("chkTint").disabled = false;
            document.getElementById("CreateTarget").disabled = false;
        }
        catch (err) { isStart = false; }
    }
    
    
    //-------------
    // AddObjectToArray
    function AddObjectToArray(object, type, altitudeType) {
    
        SGWorld.Window.ShowMessageBarText(SGLang.i18n("Text40"));
        SGWorld.ProjectTree.EnableRedraw(0);
    
        if (type == 1) {
            //In the future may want to work on the pivot of the polyline. was: if (!DrawOnPolyline(geometry, type, altitudeType))
                return false;
        }
        else if (type == 2)
        {
            //In the future may want to work on the pivot of the polyline. was: if (!DrawOnPolygon(geometry, type, altitudeType))
                return false;
        }
        else // Selected points
        {
            PushtrackedObj2Array(object);
        }
        return true;
    }
    
    //-------------------
    //searchObjects2 - modified from ToolsCommon65 searchGeometries
    function searchObjects2(parentNode, callbackFunc) {
        SGWorld.ProjectTree.EnableRedraw(0);
        searchObjectsLeaf2(parentNode, callbackFunc);
        SGWorld.ProjectTree.EnableRedraw(1);
    }
    //-------------------
    // searchObjectsLeaf2 - modified from ToolsCommon65 searchGeometriesLeaf2
    function searchObjectsLeaf2(parentNode, callbackFunc) {
    
        if (SGWorld.ProjectTree.IsLayer(parentNode))  // Layer
        {
            var layer = SGWorld.ProjectTree.GetLayer(parentNode);
            var featureGroups = layer.FeatureGroups;
            for (var i = 0; i < featureGroups.Count; i++) // Traverse all sub-layers
            {
                var featureGroup = featureGroups.Item(i);
                var altitudeType = AltitudeMethodToAltitudeType(featureGroup.GetProperty("Altitude Method"));
                var features = featureGroup.Features;
                for (var j = 0; j < features.Count; j++) {
                    var ret;
                    if (featureGroup.GeometryType != 0)
                        ret = callbackFunc(features.Item(j).Geometry, featureGroup.GeometryType, altitudeType);
                    else {
                        if (features.Item(j).Geometry.GeometryType == 0) // Point
                        {
                            var position = SGWorld.Creator.CreatePosition(features.Item(j).Geometry.X, features.Item(j).Geometry.Y, features.Item(j).Geometry.Z);
                            ret = callbackFunc(position, featureGroup.GeometryType, altitudeType);
                        }
                    }
                    if (!ret)
                        return;
                }
            }
        }
        else {
            var node = SGWorld.ProjectTree.GetNextItem(parentNode, 11);
            while (node != "") {
                if (SGWorld.ProjectTree.IsGroup(node) || SGWorld.ProjectTree.IsLayer(node))
                    searchObjectsLeaf2(node, callbackFunc);
                else {
                    var Object = SGWorld.Creator.GetObject(node);
                    if (Object != null) {
                        var altitudeType = Object.Position.AltitudeType;
                        var ret;
                        if (Object.ObjectType == 1 || Object.ObjectType == 2)
                           ret = callbackFunc(Object/*.Geometry*/, Object.ObjectType, altitudeType);
                        else
                            ret = callbackFunc(Object/*.Position*/, Object.ObjectType, altitudeType);
    
                        if (!ret)
                            return;
                    }
                }
    
                node = SGWorld.ProjectTree.GetNextItem(node, 13);
            }
        }
    }
    
    //--------------
    // EmptytrackedObjArray
    function EmptytrackedObjArray() {
        while (trackedObjArray.length > 0) {
            trackedObjArray.pop();
        }
    }
    
    //--------------
    // PushtrackedObj2Array
    function PushtrackedObj2Array(object) {
        trackedObjArray.push({
            "object": object,
            "lineObj": null,
            "distLabelObj": null,
            "level": "undefined"
        });
    }
    
    //------------
    //deleteObjs
    function deleteObjs() {//In the future move logic to deleteObj that can be called from here and from other places.
        try {
            //while (trackedObjArray.length > 0)
            for (var i = 0; i < trackedObjArray.length; i++) {
                //var item = trackedObjArray.pop();
                var item = trackedObjArray[i];
                if (item.lineObj != null) {
                    SGWorld.Creator.DeleteObject(item.lineObj.ID);
                    item.lineObj = null;
                }
                if (item.distLabelObj != null) {
                    SGWorld.Creator.DeleteObject(item.distLabelObj.ID);
                    item.distLabelObj = null;
                }
                item.level = "undefined";
                if (bTint) item.object.Terrain.Tint = SGWorld.Creator.CreateColor(0, 0, 0, 0);
    
            }
        }
        catch (err) { alert(SGLang.i18n("Text41") + err); Reset(0, 0); }
    }
    
    
    //------------
    //displayProximityInfo
    function displayProximityInfo() {
        //debugger;
        if (!isStart || targetObj == null ) {
            return false;
        }
        try {
            for (var i = 0; i < trackedObjArray.length; i++) {
    
                //calculate distance
                var dist = SGWorld.CoordServices.GetDistance3D(targetObj.Position, trackedObjArray[i].object.Position);
                if (dist <= warningRadius) {
                    //Create/Update polygon
                    if (trackedObjArray[i].lineObj == null) {
                        var absoluteTargetObj = targetObj.Position.ToAbsolute(0);
                        var absoluteTrackedObj = trackedObjArray[i].object.Position.ToAbsolute(0);
                        var pointsArray = [absoluteTargetObj.X, absoluteTargetObj.Y, absoluteTargetObj.Altitude, absoluteTrackedObj.X, absoluteTrackedObj.Y, absoluteTrackedObj.Altitude];
                        trackedObjArray[i].lineObj = SGWorld.Creator.CreatePolylineFromArray(pointsArray, colorLineDanger, 3, SGWorld.ProjectTree.HiddenGroupID); //leave this comment: ATC_TERRAIN_ABSOLUTE = 3
                        trackedObjArray[i].lineObj.SaveInFlyFile = false;
                        trackedObjArray[i].lineObj.SetParam(5440, 1);
                        trackedObjArray[i].lineObj.LineStyle.Width = -2
                    }
                    else {
                        trackedObjArray[i].lineObj.Geometry.StartEdit()
                        //update second point
                        var absolutePosition = trackedObjArray[i].object.Position.ToAbsolute(0);
                        trackedObjArray[i].lineObj.Geometry.Points.Item(1).X = absolutePosition.X;
                        trackedObjArray[i].lineObj.Geometry.Points.Item(1).Y = absolutePosition.Y;
                        trackedObjArray[i].lineObj.Geometry.Points.Item(1).Z = absolutePosition.Altitude;
                        trackedObjArray[i].lineObj.Geometry.EndEdit()
                    }
                    //Create/Update Text ***arik: Does it look good? what to do when below ground
                    if (trackedObjArray[i].distLabelObj == null) {
                        var absoluteTargetObj = targetObj.Position.ToAbsolute(0);
                        var absoluteTrackedObj = trackedObjArray[i].object.Position.ToAbsolute(0);
                        var middlePosition = absoluteTargetObj.MoveToward(absoluteTrackedObj, dist / 2);
                        middlePosition.Altitude = middlePosition.Altitude + warningRadius / 40;
                        
                        var labelStyle = SGWorld.Creator.CreateLabelStyle(0);
                        labelStyle.Bold = true;
                        //labelStyle.LineToGround = false;
                        labelStyle.Scale = warningRadius / 20; 
                        labelStyle.FontSize = 10;
    
                        trackedObjArray[i].distLabelObj = SGWorld.Creator.CreateTextLabel(middlePosition, dist.toFixed(2), labelStyle, SGWorld.ProjectTree.HiddenGroupID);
                        trackedObjArray[i].distLabelObj.SaveInFlyFile = false;
    
                    }
                    else {
                        var absoluteTargetObj = targetObj.Position.ToAbsolute(0);
                        var absoluteTrackedObj = trackedObjArray[i].object.Position.ToAbsolute(0);
                        var middlePosition = absoluteTargetObj.MoveToward(absoluteTrackedObj, dist / 2);
                        middlePosition.Altitude = middlePosition.Altitude + warningRadius / 40;
                        trackedObjArray[i].distLabelObj.Position = middlePosition;
                        trackedObjArray[i].distLabelObj.Text = dist.toFixed(2);
                    }
    
    
    
                    //Color objects
                    var newLevel = (dist > dangerRadius) ? "warning" : "danger";
                    if (trackedObjArray[i].level != newLevel) {
                        trackedObjArray[i].lineObj.LineStyle.Color = (newLevel == "danger") ? colorLineDanger : colorLineWarning;
                        trackedObjArray[i].distLabelObj.Style.TextColor = (newLevel == "danger") ? colorLineDanger : colorLineWarning;
                        if (bTint) {
                            trackedObjArray[i].object.Terrain.Tint = (newLevel == "danger") ? colorLineDanger : colorLineWarning;
                            trackedObjArray[i].object.Terrain.Tint.SetAlpha(0.5);
                        }
                    }
    
    
                }
                else {
                    if (trackedObjArray[i].lineObj != null) {
                        SGWorld.Creator.DeleteObject(trackedObjArray[i].lineObj.ID);
                        trackedObjArray[i].lineObj = null;
                    }
                    if (trackedObjArray[i].distLabelObj != null) {
                        SGWorld.Creator.DeleteObject(trackedObjArray[i].distLabelObj.ID);
                        trackedObjArray[i].distLabelObj = null;
                    }
                    trackedObjArray[i].object.Terrain.Tint = SGWorld.Creator.CreateColor(0, 0, 0, 0);
                }
    
            }
    
        }
        catch (err) { alert(SGLang.i18n("Text41") + err); Reset(0, 0); }
    }
    
    </script>
    
    </body>
    </html>
  • 相关阅读:
    VUE DEVTOOLS 安装方法(npm cnpm 安装失败找不到安装工具问题解决方法)
    idea 注释模版
    阿里巴巴编码规范
    JRebel 实现热部署
    SPRING 扩展组件
    oracle 闪回
    ORACLE 日常
    springboot log4j
    支付宝异步回调验证签名的那些走过的坑
    ASP.NET MVC5(一)—— URL路由
  • 原文地址:https://www.cnblogs.com/yitianhe/p/5085069.html
Copyright © 2011-2022 走看看