美文网首页开源工具技巧gis程序员
记:Arcgis for JavaScript 4.5 在3D

记:Arcgis for JavaScript 4.5 在3D

作者: 天上月丶 | 来源:发表于2017-11-14 19:28 被阅读29次
    弧线
    如图所示,在Arcgis地图绘制弧线。
    arcgis Api中提供了点,折线,多边形,圆绘制,但并没有弧线绘制,因公司有此需求,就研究了一下。刚好看到http://www.jianshu.com/p/4a0fdf10d55e,这篇文章讲述了如何绘制贝塞尔曲线,如此。便借用该段代码来实现地球上的弧线绘制。
    define([
        "esri/geometry/Polyline",
        "esri/geometry/Point",
        "esri/geometry/Polygon"
    ], function (Polyline, Point, Polygon) {
        /* eslint-disable */
    
        var Spline = function (options) {
            this.points = options.points || [];
            this.duration = options.duration || 100000;
            this.sharpness = options.sharpness || 0.85;
            this.centers = [];
            this.controls = [];
            this.stepLength = options.stepLength || 60;
            this.length = this.points.length;
            this.delay = 0;
            // this is to ensure compatibility with the 2d version
            for (var i = 0; i < this.length; i++) this.points[i][2] = this.points[i][2] || 0;
            for (var i = 0; i < this.length - 1; i++) {
                var p1 = this.points[i];
                var p2 = this.points[i + 1];
                this.centers.push({
                    x: (p1[0] + p2[0]) / 2,
                    y: (p1[1] + p2[1]) / 2,
                    z: (p1[2] + p2[2]) / 2
                });
            }
            this.controls.push([this.points[0], this.points[0]]);
            for (var i = 0; i < this.centers.length - 1; i++) {
                var p1 = this.centers[i];
                var p2 = this.centers[i + 1];
                var dx = this.points[i + 1][0] - (this.centers[i].x + this.centers[i + 1].x) / 2;
                var dy = this.points[i + 1][1]- (this.centers[i].y + this.centers[i + 1].y) / 2;
                var dz = this.points[i + 1][2] - (this.centers[i].y + this.centers[i + 1].z) / 2;
                this.controls.push([[
                    (1.0 - this.sharpness) * this.points[i + 1][0] + this.sharpness * (this.centers[i].x + dx),
                     (1.0 - this.sharpness) * this.points[i + 1][1] + this.sharpness * (this.centers[i].y + dy),
                    (1.0 - this.sharpness) * this.points[i + 1][2] + this.sharpness * (this.centers[i].z + dz)
            ],
                    [
                         (1.0 - this.sharpness) * this.points[i + 1][0] + this.sharpness * (this.centers[i + 1].x + dx),
                         (1.0 - this.sharpness) * this.points[i + 1][1] + this.sharpness * (this.centers[i + 1].y+ dy),
                         (1.0 - this.sharpness) * this.points[i + 1][2] + this.sharpness * (this.centers[i + 1].z + dz)
            ]]);
            }
            this.controls.push([this.points[this.length - 1], this.points[this.length - 1]]);
            this.steps = this.cacheSteps(this.stepLength);
            console.log("-----------this.controls-------------");
            console.log(this.controls)
            return this;
        };
    
        /*
         Caches an array of equidistant (more or less) points on the curve.
         */
        Spline.prototype.cacheSteps = function (mindist) {
            var steps = [];
            var laststep = this.pos(0);
            steps.push(0);
            for (var t = 0; t < this.duration; t += 10) {
                var step = this.pos(t);
                var dist = Math.sqrt((step.x - laststep.x) * (step.x - laststep.x) + (step.y - laststep.y) * (step.y - laststep.y) + (step.z - laststep.z) * (step.z - laststep.z));
                if (dist > mindist) {
                    steps.push(t);
                    laststep = step;
                }
            }
            return steps;
        };
    
        /*
         returns angle and speed in the given point in the curve
         */
        Spline.prototype.vector = function (t) {
            var p1 = this.pos(t + 10);
            var p2 = this.pos(t - 10);
            return {
                angle: 180 * Math.atan2(p1.y - p2.y, p1.x - p2.x) / 3.14,
                speed: Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y) + (p2.z - p1.z) * (p2.z - p1.z))
            };
        };
    
        /*
         Gets the position of the point, given time.
         WARNING: The speed is not constant. The time it takes between control points is constant.
         For constant speed, use Spline.steps[i];
         */
        Spline.prototype.pos = function (time) {
    
            function bezier(t, p1, c1, c2, p2) {
                if(time<10){
                   /* console.log("==============bez2222ier============");
                    console.log(t);
                    console.log(p1);
                    console.log(c1);
                    console.log(c2);
                    console.log(p2);*/
    
                }
                var B = function (t) {
                    var t2 = t * t, t3 = t2 * t;
                    return [(t3), (3 * t2 * (1 - t)), (3 * t * (1 - t) * (1 - t)), ((1 - t) * (1 - t) * (1 - t))];
                };
                var b = B(t);
                if(time<10){
                    /*console.log("========b=====")
                    console.log(b)*/
                }
                var pos = {
                    x: p2[0] * b[0] + c2[0] * b[1] + c1[0] * b[2] + p1[0] * b[3],
                    y: p2[1] * b[0] + c2[1] * b[1] + c1[1] * b[2] + p1[1] * b[3],
                    z: p2[2] * b[0] + c2[2] * b[1] + c1[2] * b[2] + p1[2] * b[3]
                };
                return pos;
            }
            var t = time - this.delay;
            if (t < 0) t = 0;
            if (t > this.duration) t = this.duration - 1;
            //t = t-this.delay;
            var t2 = (t) / this.duration;
            if (t2 >= 1) return this.points[this.length - 1];
    
            var n = Math.floor((this.points.length - 1) * t2);
            var t1 = (this.length - 1) * t2 - n;
            if(time<10){
                /*console.log("==============bezier============");
                console.log(t);
                console.log(t1);
                console.log(t2);
                console.log(this.points);
                console.log(this.controls);*/
    
            }
            return bezier(t1, this.points[n], this.controls[n][1], this.controls[n + 1][0], this.points[n + 1]);
        };
    
    
        var customLib = {
            getBesselLine: function (points, mapView, params) {
                var coords = [];
    
                var spline = new Spline(dojo.mixin({
                    points: points
                }, params || {}));
                console.log("------------spline---------------");
                console.log(spline);
                for (var i = 0; i < spline.duration; i += 10) {
                    var pos = spline.pos(i);
                   if(i<10){
                       console.log("-------------pos------------");
                       console.log(pos);
                   }
                    if (Math.floor(i / 100) % 2 === 0) {
                        coords.push([pos.x, pos.y,pos.z]);
                    }
                }
                var polyline = {
                    type: "polyline", // autocasts as new Polyline()
                    paths: [coords]
                };
              /*  var line = new Polyline({
                    paths: [coords],
                    spatialReference: { wkid: 4326 }
                });*/
                return polyline
            },
            getBesselCenterPoint: function (p1, p2, mapView, L) {
                L || (L = 30);
                var point1 = mapView.toScreen(p1);
                var point2 = mapView.toScreen(p2);
                var a = point1.x, b = point1.y, c = point2.x, d = point2.y;
                var e = (point1.x + point2.x) / 2;
                var f = (point1.y + point2.y) / 2;
                var g = Math.pow(a - e, 2) + Math.pow(b - f, 2) + Math.pow(L, 2);
                var h = 2 * e - 2 * a;
                var i = 2 * f - 2 * b;
                var j = Math.pow(a, 2) - Math.pow(e, 2) + Math.pow(b, 2) - Math.pow(f, 2) + Math.pow(L, 2) - g;
                var k = 1 + Math.pow(h / i, 2);
                var m = (2 * b * h) / i - 2 * a + (2 * h * j) / Math.pow(i, 2);
                var n = Math.pow(a, 2) + Math.pow(j / i, 2) + (2 * b * j) / i + Math.pow(b, 2) - g;
                var x = (-m + Math.sqrt(Math.pow(m, 2) - 4 * k * n)) / (2 * k);
                var y = -(h / i) * x - j / i;
    
                var value = (a - x) * (d - y) - (b - y) * (c - x);
                if (value < 0) {
                    x = (-m - Math.sqrt(Math.pow(m, 2) - 4 * k * n)) / (2 * k);
                    y = -(h / i) * x - j / i;
                }
                console.log('ddd', value)
    
                var np = mapView.toMap({
                    x: x, y: y
                });
                return new Point({
                    x: np.x,
                    y: np.y,
                    spatialReference: mapView.spatialReference
                });
            },
            getInterPointFromRing: function (ring, mapView) {
                var i, ii, x, x1, x2, y1, y2;
                var polygon = new Polygon({
                    "rings": [ring]
                });
                var extentCenter = polygon.extent.center;
                var y = extentCenter.y;
                var intersections = [];
                var flatCoordinates = [];
                for (var i = 0, len = ring.length; i < len; i++) {
                    flatCoordinates.push(ring[i][0], ring[i][1]);
                }
                var end = flatCoordinates.length;
                x1 = flatCoordinates[end - 2];
                y1 = flatCoordinates[end - 2 + 1];
                for (i = 0; i < end; i += 2) {
                    x2 = flatCoordinates[i];
                    y2 = flatCoordinates[i + 1];
                    if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {
                        x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;
                        intersections.push(x);
                    }
                    x1 = x2;
                    y1 = y2;
                }
                var pointX = NaN;
                var maxSegmentLength = -Infinity;
                intersections.sort(function (a, b) {
                    return a - b;
                });
                x1 = intersections[0];
                var xs = [];
                for (i = 1, ii = intersections.length; i < ii; ++i) {
                    x2 = intersections[i];
                    var segmentLength = Math.abs(x2 - x1);
                    if (segmentLength > maxSegmentLength) {
                        x = (x1 + x2) / 2;
                        if (this._judgeCoordinates(
                                flatCoordinates, 0, end, 2, x, y)) {
                            pointX = x;
                            maxSegmentLength = segmentLength;
                            xs.push(x);
                        }
                    }
                    x1 = x2;
                }
                if (isNaN(pointX)) {
                    pointX = extentCenter.x;
                }
                return new Point({
                    x: pointX,
                    y: y,
                    spatialReference: mapView.spatialReference
                });
            },
            _judgeCoordinates: function (flatCoordinates, offset, end, stride, x, y) {
                var wn = 0;
                var x1 = flatCoordinates[end - stride];
                var y1 = flatCoordinates[end - stride + 1];
                for (; offset < end; offset += stride) {
                    var x2 = flatCoordinates[offset];
                    var y2 = flatCoordinates[offset + 1];
                    if (y1 <= y) {
                        if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) {
                            wn++;
                        }
                    } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) {
                        wn--;
                    }
                    x1 = x2;
                    y1 = y2;
                }
                var result = (wn !== 0);
                if (!result) {
                    return false;
                }
                return true;
            }
        };
    
        return customLib;
    
    });
    
    

    以上是修改过后的文件(其实就改了几个属性),将上述代码保存放置于项目下(我的放置在js文件夹下,重命名为curve.js),

      require([
                    "esri/Graphic",
                    "../js/curve.js",
                    "dojo/domReady!"
                ],
                function (Graphic, Curve) {});
    

    仿照以上引入使用即可。
    下来回归正题,图中所示分为两个部分,一部分是在地球表面绘制点,其次就是在地球上方绘制一条两点之间有一定弧度高度的线,就是上方的贝塞尔曲线的代码部分了。
    绘制点。如下所示:传入参数为多个点坐标,即

                        [{
                            type: "point", 
                            longitude:150.32,
                            latitude: 45.23
                        },{.....}]
    

    symbol的url换为自己的图片地址即可。

     drawPoint: function (points) {
            require([
                    "esri/Graphic",
                    "dojo/domReady!"
                ],
                function (Graphic) {
    
                    points.forEach(function (point) {
                         var symbol = {
                            type: "picture-marker",  // autocasts as new PictureMarkerSymbol()
                            url: "../img/route.png",
                            width: "50px",
                            height: "50px"
                        };
    
    
                        var pop={ // autocasts as new PopupTemplate()
                            title: item['name'],
    
                            // Set content elements in the order to display.
                            // The first element displayed here is the fieldInfos.
                            content: [ {
                                // You can also set a descriptive text element. This element
                                // uses an attribute from the featurelayer which displays a
                                // sentence giving the total amount of trees value within a
                                // specified census block. Text elements can only be set within the content.
                                type: "text",
                                text: "There are {Point_Count} trees within census block {BLOCKCE10}"
                            },]
                        };
                        var graphic = new Graphic({
                            geometry: point,
                            symbol: symbol,
                            popupTemplate:pop
                        });
                        ArcMap.v.graphicsLayer.add(graphic);
                    });
    
                });
        }
    

    绘制弧线。如下所示:传入参数为多条线坐标,即:

           [
                      [{
                            type:'point',
                            longitude:142.23,
                            latitude:35.65
                        },{
                            type:'point',
                            longitude:15.25,
                            latitude:35.25
                        }],[.....]
            ]
    

    线为两个点组成,即起始点与终止点,在drawLine中,会根据两点计算出中间点的经纬度和高度,将此三点传入上述贝塞尔曲线中,进行绘制即可。中间点的坐标可依据自己实际情况进行修改。

    drawLine: function (lines) {
            require([
                    "esri/Graphic",
                    "../js/curve.js",
                    "dojo/domReady!"
                ],
                function (Graphic, Curve) {
    
                    lines.forEach(function (line) {
                        var sub1 = Math.abs(line[0].longitude - line[1].longitude);
                        var sub2 = Math.abs(line[0].latitude - line[1].latitude);
                        var height = (sub1 + sub2) * 5000;
                        var curve = [];
                        var curve1 = [line[0].longitude, line[0].latitude, 0];
                        var curve2 = [line[1].longitude, line[1].latitude, 0];
                        var curve3 = [(line[0].longitude + line[1].longitude) / 2, (line[0].latitude + line[1].latitude) /2, height];
                        curve.push(curve1);
                        curve.push(curve3);
                        curve.push(curve2);
    
                        var curveLine = Curve.getBesselLine(curve, ArcMap.v.view);
                        console.log("--------------------curveLine------------------------");
                        console.log(curveLine);
                        var lineSymbol = {
                            type: "simple-line", // autocasts as SimpleLineSymbol()
                            color: '#FFFF00',
                            width: 3
                        };
                        var pop={ // autocasts as new PopupTemplate()
                            title: item[0]['name']+'---'+item[1]['name'],
    
                            // Set content elements in the order to display.
                            // The first element displayed here is the fieldInfos.
                            content: [ {
                             // You can also set a descriptive text element. This element
                             // uses an attribute from the featurelayer which displays a
                             // sentence giving the total amount of trees value within a
                             // specified census block. Text elements can only be set within the content.
                             type: "text",
                             text: "There are {Point_Count} trees within census block {BLOCKCE10}"
                             },]
                        };
    
                        var polylineGraphic = new Graphic({
                            geometry: curveLine,
                            symbol: lineSymbol,
                            popupTemplate:pop
                        });
                        ArcMap.v.graphicsLayer.add(polylineGraphic);
                    });
    
    
                });
        }
    

    也是初学,记录一下,如有bug,请不吝指出……

    相关文章

      网友评论

        本文标题:记:Arcgis for JavaScript 4.5 在3D

        本文链接:https://www.haomeiwen.com/subject/zbgfvxtx.html