Цезий как масштабировать многоугольник, чтобы он соответствовал положениям широты и долготы при увеличении / уменьшении масштаба

Я ищу цезиевого гуру, который немного поможет мне найти то, что мне нужно. Я новичок в Cesium, но я работал с учебными пособиями и некоторым существующим кодом, который я унаследовал.

В моем приложении Cesium я ввожу свой адрес, и вид приближается к моей улице. Ура! Затем я увеличиваю масштаб, чтобы нарисовать многоугольник вокруг своего дома. Существующий код делает это очень хорошо. Однако когда я уменьшаю, а затем снова увеличиваю масштаб, мой многоугольник не соответствует положению моего дома по широте и долготе.

Содержит ли Cesium утилиту для масштабирования пикселей по координатам широты и долготы, или мне нужно использовать что-то вроде distanceToBoundingSphere (boundingSphere) и рассчитывать его самостоятельно? Мне нужны только координаты x, y; Меня вообще не волнует рост.

Я искал демонстрации и обучающие программы и до сих пор не нашел того, что, как мне кажется, ищу. Возможно, я нашел что-то близкое, но я еще не знаю достаточно, чтобы знать, нашел я это или нет. Помощь!

============================ КОД ================== ================

Сбор позиций для многоугольника:

SingleClick фиксирует только координаты этой точки и рисует ломаную линию, когда пользователь перетаскивает мышь к новой точке. Следовательно, набор полилиний и набор координат для каждой точки.

    positionHandler.setInputAction(function (click) {
        cartesian = scene.camera.pickEllipsoid(click.position, ellipsoid);
        if (cartesian) {
            var setCartographic = ellipsoid.cartesianToCartographic(cartesian);
            asset.latlonalt.push(
                Cesium.Math.toDegrees(setCartographic.latitude).toFixed(15),
                Cesium.Math.toDegrees(setCartographic.longitude).toFixed(15),
                Cesium.Math.toDegrees(setCartographic.height).toFixed(15)
            );
            lla.push(Cesium.Math.toDegrees(setCartographic.longitude), Cesium.Math.toDegrees(setCartographic.latitude));
            if (lla.length >= 4) {
                self.loggingMessage((lla.length / 2) + ' Points Added');
            }
            Cesium.sampleTerrain(terrainProvider, 11, [cartographic])
                .then(function (updatedPositions) {
                    asset.latlonalt[2] = updatedPositions[0].height;
                    stage = 1;
                });
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

Затем doubleClick берет координаты, записанные в функции singleClick, и вызывает self.createAsset ('add', asset) для создания многоугольника.

    positionHandler.setInputAction(function (doubleClick){
        if (asset.shape == 'Polygon') {
            var len = asset.latlonalt.length;
            if(len > 9) {
                asset.rad = (len / 3);
                console.log("Creating Asset");
                self.loggingMessage("Creating Asset");
                socket.emit('newElement', asset.cType, asset);
                self.createAsset('add', asset);
                viewer.entities.remove(entity);
                viewer.entities.remove(newCircle);
                viewer.entities.remove(newPolygon);
                viewer.entities.remove(newOutline);
                positionHandler = positionHandler && positionHandler.destroy();
            }else{
                console.log('3+ Positions Required');
                loggingMessage('3+ Positions Required.');
            }
        }
    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

Создание многоугольника:

            var newPolygon = viewer.entities.add({
                name : asset.id,
                polygon : {
                    hierarchy : Cesium.Cartesian3.fromDegreesArray(vertices),
                    material : rgba[0],
                    outline : true,
                    outlineColor : rgba[1]
                }
            });
            var newLabel = viewer.entities.add({
                position: Cesium.Cartesian3.fromDegrees(asset.latlonalt[1], asset.latlonalt[0], 1000),
                name: asset.id,
                label: {
                    text: asset.name,
                    font : '16px Helvetica'
                }
            });
            var newPoint = viewer.entities.add({
                position: Cesium.Cartesian3.fromDegrees(asset.latlonalt[1], asset.latlonalt[0], 0),
                name: asset.id,
                point : {
                pixelSize : 5,
                    color : Cesium.Color.RED,
                    outlineColor : Cesium.Color.RED,
                    outlineWidth : 2
                }
            });
            self.currentGeometry[asset.id] = {shape: newPolygon, label: newLabel, point: newPoint};

Похоже, мы используем Terrain (я думаю).

Изображение местности

Какие числа меня должны интересовать:

введите описание изображения здесь

Когда координаты собираются, только первые z не нули:

введите описание изображения здесь

Я беру это значение и заполняю другие значения z:

введите описание изображения здесь

Теперь, когда я добавил значения z, в методе createAsset что-то не так. Мне нужно отследить эту проблему, чтобы увидеть результаты. Прямо сейчас это выглядит так:

введите описание изображения здесь

ДЕЙСТВИТЕЛЬНО БОЛЬШОЙ, и очертания не удаляются.


person Patricia    schedule 10.03.2016    source источник
comment
Добро пожаловать в Цезий, мисс Люси. Ваше приложение случайно использует Terrain? Если это так, вы можете видеть свой дом на правильной высоте, но рисуете многоугольник на нулевой высоте (эталонная высота WGS84). Такие подземные полигоны часто кажутся дрейфующими при движении камеры.   -  person emackey    schedule 11.03.2016
comment
Точно! Я могу перемещать камеру и увеличивать или уменьшать масштаб, пока многоугольник не совпадет с моим домом, а когда я перемещаю землю, многоугольник смещается от моего дома. Если под ландшафтом вы имеете в виду деревья, машины, траву и прочее, тогда да, это должно быть использование ландшафта. В ПОРЯДКЕ. Я собираюсь изучить это подробнее. Возможно, вы дадите мне ответ, и я дам вам очки. :-)   -  person Patricia    schedule 11.03.2016
comment
Подождите ... код учитывает только координаты x, y. Вы хотите сказать, что просто добавив координату z, мой многоугольник останется с моим домом?   -  person Patricia    schedule 11.03.2016
comment
Под использованием ландшафта я имею в виду, что если вы приблизитесь к некоторым горам и наклоните камеру к горизонту, вы увидите горы, торчащие вертикально, а не изображения гор, лежащих на эллипсоиде WGS84. Если первое (3D горы), то да, рельеф используется, и вы должны размещать полигоны на ненулевой высоте даже в плоских областях. Я вижу, вы добавили вызов sampleTerrain, это что-то исправило?   -  person emackey    schedule 12.03.2016
comment
Я считаю, что мы используем рельеф. Лучшее, что я мог сделать, это крышка экрана. Нет, я не добавлял sampleTerrrain (он уже был). Но я начинаю понимать, в чем может быть проблема. Я не знаю, почему он использует sampleTerrain в этом методе (первом блоке кода), когда он только собирает координаты. Несмотря на то, что updatedPositions [0] .height является правильным в методе sampleTerrain, значения z не заполняются. Возможно, нам следует использовать sampleTerrain в коде, который фактически создает многоугольник (третий блок кода). Я заполняю значения z в массиве вершин.   -  person Patricia    schedule 12.03.2016
comment
См. Обсуждаемые обновления. Я просматриваю этот код, и он кажется немного запутанным. Можете ли вы взглянуть на числа x, y, z и помочь мне разобраться в правильной логике. За исключением того факта, что значения z не сохраняются в массиве asset.latlonalt, значения x и y выглядят хорошо. Но даже при заполнении значений z в массиве вершин многоугольник работает некорректно. Я все еще смотрю sampleTerrain. Может просто не в том месте.   -  person Patricia    schedule 12.03.2016


Ответы (1)


По одному вопросу происходит много всего, но я постараюсь затронуть ключевые части.

Во-первых, сам класс Cartesian3. Внутри, после построения, этот класс содержит x, y, z членов, содержащих такие значения, как 314923.1. Вы, вероятно, должны думать об этом как о непрозрачных значениях черного ящика. Фактически, они представляют собой декартово положение в метрах от центра планеты, которое необходимо механизму рендеринга, но обычно не полезно для картографов-людей. Ключевой момент, который нужно понять, это то, что z всегда будет заполнено реальным значением, и это НЕ означает, что высота была учтена или нет при создании значения.

Существует отдельный класс Cartographic, который содержит знакомые значения долготы (радианы) и широты. (Радианы) и Высота (в метрах). Обычно они должны быть преобразованы в Cartesian3 перед передачей механизму рендеринга. Для этого преобразования требуется знание Ellipsoid (по умолчанию эллипсоид WGS84), и поэтому нулевое значение высоты указывает точку, находящуюся на этом эллипсоиде (обычно это означает, что точка находится под землей, когда включен режим ландшафта).

Набор вспомогательных функций принимает общие значения (например, долгота / широта в градусах) и конвертируется в любой из этих двух форматов. Некоторые из этих вспомогательных функций не включают параметр высоты, другие включают его. В документации для этих двух классов перечислены эти помощники.

Получить точные координаты долготы и широты одним щелчком мыши просто, когда рельеф отключен, но сложнее, когда он включен, из-за использования перспективной 3D-камеры. Без ландшафта вы можете просто вызвать scene.camera.pickEllipsoid, как вы делали в первом примере кода выше, и получить точное место. Но когда рельеф включен, даже щелчок по плоской равнине будет вычислять неправильные координаты, обнаруживая подземное место ниже и позади местности, на которую вы смотрите.

Обычный поиск не позволяет найти правильный код для этого, но золотой стандарт выглядит встроен в существующий контроллер камеры здесь. Выглядит это так:

    var depthIntersection;
    if (scene.pickPositionSupported) {
        depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
    }

    var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
    var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);

    var pickDistance = defined(depthIntersection) ?
        Cartesian3.distance(depthIntersection, camera.positionWC) :
        Number.POSITIVE_INFINITY;
    var rayDistance = defined(rayIntersection) ?
        Cartesian3.distance(rayIntersection, camera.positionWC) :
        Number.POSITIVE_INFINITY;

    if (pickDistance < rayDistance) {
        return Cartesian3.clone(depthIntersection, result);
    }

    return Cartesian3.clone(rayIntersection, result);

Этот код пытается использовать двоякий подход: он пытается выбрать эллипсоид, как и раньше, а также пытается выбрать из «буфера глубины», который является частью системы трехмерной графики, которая позволяет Cesium проверять, насколько далеко были расположены полигоны. с камеры при рендеринге. Два результата сравниваются, и победителем объявляется тот, который ближе к камере. Это позволяет вообще избежать необходимости в вызове sampleTerrain, потому что местоположение мыши использовалось для непосредственного выбора декартовой точки в пространстве, где был визуализирован многоугольник (который, вероятно, является ландшафтом, но может быть даже верхом здания и т. Д.).

В следующем блоке кода вы используете asset.latlonalt для заполнения lon и lat, но затем у вас alt жестко запрограммировано на 0 или 1000, а не на основе той же структуры данных. Это может быть то место, где информация о высоте теряется, если она была там с самого начала (а это не так, если вы просто выбираете сам эллипсоид, хотя он может быть добавлен sampleTerrain позже. Помните, что sampleTerrain является асинхронным из-за к тайлам ландшафта, загружаемым с сервера). Если вы решите попробовать метод выбора глубины, это даст Cartesian3 напрямую, поэтому вам не придется беспокоиться о его преобразовании или сохранении высоты и т. Д.

Последний комментарий, последние версии Cesium действительно поддерживают _20 _, что позволяет накладываться на поверхность полигонов . Это не избавит вас от необходимости «выбирать» правильные широты и долготы для начала (с учетом перспективного ландшафта), но позволит многоугольнику лежать на неровной поверхности и не торчать сквозь него.

person emackey    schedule 14.03.2016
comment
Отличная информация !!! Я не хочу, чтобы многоугольник драпировался на местности, потому что я просто пытаюсь определить периметр (что-то вроде невидимого забора для домашних животных). В ПОРЯДКЕ. Я углублюсь в предоставленную вами информацию и «надеюсь» заставлю мой многоугольник придерживаться соответствующих позиций при масштабировании и перемещении камеры. Спасибо. :-) - person Patricia; 14.03.2016
comment
Привет, мисс Люси, я видела ваш следующий вопрос, но не успела продумать полный ответ на него. На самом деле похоже, что его только что удалили. В любом случае вы можете получить ссылку на глобус от viewer.scene.globe, и вы правы, что высота включена в ваш декартово3. - person emackey; 21.03.2016
comment
Привет, emackey! Да, я просто удалил его, потому что подумал, что в этом вопросе тоже может быть слишком много. Я начинаю понимать, но до сих пор не знаю, как получить определенные (т.е. Cesium.defined (depthIntersection) и Cesium.defined (rayIntersection)) и как установить для scene.pickPositionSupported значение true. Итак, я отправляю еще один вопрос, который намного меньше. Я отправлю тебя, когда он там поднимется. - person Patricia; 21.03.2016
comment
С нетерпением жду новых вопросов :) А пока scene.pickPositionSupported отражает возможности браузера (доступно расширение WebGL Fragment Depth), которые, я думаю, недоступны в IE 11, но доступны на большинстве графических устройств в Chrome, Firefox и Edge. - person emackey; 21.03.2016