ArcGIS api for JavaScript 4+版本面內(nèi)點(diǎn)(標(biāo)注點(diǎn))及貝塞爾曲線及兩點(diǎn)貝塞爾曲線中點(diǎn)計(jì)算

簡介

面內(nèi)點(diǎn)算法是通過研究ol里面的方法改寫得(抄的),貝塞爾曲線則是通過研究turfjs的源碼改寫的肯腕。其中上一篇文章中的tooltip就用到了標(biāo)注點(diǎn)的計(jì)算实撒。

兩點(diǎn)之間貝塞爾曲線繪制

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;

});

小結(jié)

這兩個(gè)算法基本上算是抄的庶柿,本人貢獻(xiàn)的基本就只有兩點(diǎn)根據(jù)屏幕距離繪制貝塞爾曲線中那個(gè)中點(diǎn)的計(jì)算浮庐,代碼中的L即為待求中點(diǎn)距離兩點(diǎn)連線的屏幕像素距離审残。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搅轿,一起剝皮案震驚了整個(gè)濱河市富玷,隨后出現(xiàn)的幾起案子既穆,更是在濱河造成了極大的恐慌幻工,老刑警劉巖会钝,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件工三,死亡現(xiàn)場離奇詭異俭正,居然都是意外死亡掸读,警方通過查閱死者的電腦和手機(jī)儿惫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門肾请,熙熙樓的掌柜王于貴愁眉苦臉地迎上來更胖,“玉大人,你說我怎么就攤上這事饵逐”氡辏” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坷襟。 經(jīng)常有香客問我,道長廓奕,這世上最難降的妖魔是什么桌粉? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮患亿,結(jié)果婚禮上步藕,老公的妹妹穿的比我還像新娘挑格。我一直安慰自己,他們只是感情好漂彤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布立润。 她就那樣靜靜地躺著,像睡著了一般桑腮。 火紅的嫁衣襯著肌膚如雪到旦。 梳的紋絲不亂的頭發(fā)上巨缘,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天若锁,我揣著相機(jī)與錄音,去河邊找鬼仲器。 笑死仰冠,一個(gè)胖子當(dāng)著我的面吹牛洋只,可吹牛的內(nèi)容都是我干的昼捍。 我是一名探鬼主播肢扯,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乍钻,長吁一口氣:“原來是場噩夢啊……” “哼铭腕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起欢摄,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎害捕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尝盼,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盾沫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年赴精,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蕾哟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莲蜘。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡票渠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昂秃,到底是詐尸還是另有隱情,我是刑警寧澤械蹋,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布哗戈,位于F島的核電站,受9級(jí)特大地震影響唯咬,放射性物質(zhì)發(fā)生泄漏胆胰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一瞎嬉、第九天 我趴在偏房一處隱蔽的房頂上張望氧枣。 院中可真熱鬧别垮,春花似錦、人聲如沸烧董。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胶背,卻和暖如春钳吟,著一層夾襖步出監(jiān)牢的瞬間窘拯,已是汗流浹背坝茎。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工嗤放, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留次酌,地道東北人岳服。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓吊宋,卻偏偏與公主長得像颜武,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子盒刚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 背景: 給一系列頂點(diǎn),如果只是用直線將其中的各個(gè)點(diǎn)依次連接起來涡上,最終形成一個(gè)折線圖,這種很容易實(shí)現(xiàn)吩愧。但是現(xiàn)實(shí)...
    狂風(fēng)無跡閱讀 39,224評論 12 70
  • 貝塞爾曲線開發(fā)的藝術(shù) 一句話概括貝塞爾曲線:將任意一條曲線轉(zhuǎn)化為精確的數(shù)學(xué)公式增显。 很多繪圖工具中的鋼筆工具,就是典...
    eclipse_xu閱讀 27,715評論 38 370
  • 談?wù)勜惾麪柷€ 最近在做項(xiàng)目的時(shí)候,需要用到一個(gè)動(dòng)畫炸站,非常簡單的動(dòng)畫旱易,簡單到就是直接對一個(gè)View做平移… 然而雖...
    雨潤聽潮閱讀 6,001評論 1 16
  • 前言 近段時(shí)間我在工作中實(shí)現(xiàn)了一個(gè)動(dòng)畫功能,其中涉及到動(dòng)畫元素要按一定的軌跡在屏幕上移動(dòng)如暖,運(yùn)動(dòng)軌跡的生成我使用了P...
    Alexyz123閱讀 6,569評論 0 11
  • 最近在做項(xiàng)目的時(shí)候酗洒,需要用到一個(gè)動(dòng)畫寝蹈,非常簡單的動(dòng)畫登淘,簡單到就是直接對一個(gè)View做平移... 然而雖然動(dòng)畫簡單箫老,...
    IAMDAEMON閱讀 4,285評論 12 69