记:Arcgis for JavaScript 4.5 在3D 地球表面画弧线

弧线

如图所示,在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,请不吝指出……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,071评论 25 707
  • 贝塞尔曲线开发的艺术 一句话概括贝塞尔曲线:将任意一条曲线转化为精确的数学公式。 很多绘图工具中的钢笔工具,就是典...
    eclipse_xu阅读 27,708评论 38 370
  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,679评论 2 32
  • 过分在意的东西,会永远带给我们困扰。在我们没有得到的时候,我们要求是极低的,而一旦所有权落到我们手中,我们就会不断...
    呓兜兜阅读 213评论 0 0
  • 自我亲身经历来说,我小学二年级的时候就被送到离家三个半小时的某大城市的私立小学去了。 可能是还小,有同学每天在身边...
    布谷娘阅读 1,216评论 0 0