ArcGIS api for JavaScript 4+版本面内点(标注点)及贝塞尔曲线及两点贝塞尔曲线中点计算

简介

面内点算法是通过研究ol里面的方法改写得(抄的),贝塞尔曲线则是通过研究turfjs的源码改写的。其中上一篇文章中的tooltip就用到了标注点的计算。

两点之间贝塞尔曲线绘制

Paste_Image.png

代码

define([
    "../geometry/Polyline",
    "../geometry/Point",
    "../geometry/Polygon"
], function (Polyline, Point, Polygon) {
    /* eslint-disable */

    /**
      * BezierSpline
      * https://github.com/leszekr/bezier-spline-js
      *
      * @private
      * @copyright
      * Copyright (c) 2013 Leszek Rybicki
      *
      * Permission is hereby granted, free of charge, to any person obtaining a copy
      * of this software and associated documentation files (the "Software"), to deal
      * in the Software without restriction, including without limitation the rights
      * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      * copies of the Software, and to permit persons to whom the Software is
      * furnished to do so, subject to the following conditions:
      *
      * The above copyright notice and this permission notice shall be included in all
      * copies or substantial portions of the Software.
      *
      * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      * SOFTWARE.
      */
    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].z = this.points[i].z || 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.x + p2.x) / 2,
                y: (p1.y + p2.y) / 2,
                z: (p1.z + p2.z) / 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].x - (this.centers[i].x + this.centers[i + 1].x) / 2;
            var dy = this.points[i + 1].y - (this.centers[i].y + this.centers[i + 1].y) / 2;
            var dz = this.points[i + 1].z - (this.centers[i].y + this.centers[i + 1].z) / 2;
            this.controls.push([{
                x: (1.0 - this.sharpness) * this.points[i + 1].x + this.sharpness * (this.centers[i].x + dx),
                y: (1.0 - this.sharpness) * this.points[i + 1].y + this.sharpness * (this.centers[i].y + dy),
                z: (1.0 - this.sharpness) * this.points[i + 1].z + this.sharpness * (this.centers[i].z + dz)
            },
            {
                x: (1.0 - this.sharpness) * this.points[i + 1].x + this.sharpness * (this.centers[i + 1].x + dx),
                y: (1.0 - this.sharpness) * this.points[i + 1].y + this.sharpness * (this.centers[i + 1].y + dy),
                z: (1.0 - this.sharpness) * this.points[i + 1].z + 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)
        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) {
            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);
            var pos = {
                x: p2.x * b[0] + c2.x * b[1] + c1.x * b[2] + p1.x * b[3],
                y: p2.y * b[0] + c2.y * b[1] + c1.y * b[2] + p1.y * b[3],
                z: p2.z * b[0] + c2.z * b[1] + c1.z * b[2] + p1.z * 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;
        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 || {}));

            for (var i = 0; i < spline.duration; i += 10) {
                var pos = spline.pos(i);
                if (Math.floor(i / 100) % 2 === 0) {
                    coords.push([pos.x, pos.y]);
                }
            }
            var line = new Polyline({
                paths: [coords],
                spatialReference: mapView.spatialReference
            });
            return line
        },
        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;

});

小结

这两个算法基本上算是抄的,本人贡献的基本就只有两点根据屏幕距离绘制贝塞尔曲线中那个中点的计算,代码中的L即为待求中点距离两点连线的屏幕像素距离。

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

推荐阅读更多精彩内容

  • 背景: 给一系列顶点,如果只是用直线将其中的各个点依次连接起来,最终形成一个折线图,这种很容易实现。但是现实...
    狂风无迹阅读 39,099评论 12 70
  • 贝塞尔曲线开发的艺术 一句话概括贝塞尔曲线:将任意一条曲线转化为精确的数学公式。 很多绘图工具中的钢笔工具,就是典...
    eclipse_xu阅读 27,686评论 38 370
  • 谈谈贝塞尔曲线 最近在做项目的时候,需要用到一个动画,非常简单的动画,简单到就是直接对一个View做平移… 然而虽...
    雨润听潮阅读 5,981评论 1 16
  • 前言 近段时间我在工作中实现了一个动画功能,其中涉及到动画元素要按一定的轨迹在屏幕上移动,运动轨迹的生成我使用了P...
    Alexyz123阅读 6,556评论 0 11
  • 最近在做项目的时候,需要用到一个动画,非常简单的动画,简单到就是直接对一个View做平移... 然而虽然动画简单,...
    IAMDAEMON阅读 4,272评论 12 69