化石原创文章,转载请注明来源并保留原文链接


Cesium本身不带比例尺,不过它提供了很多测距的方式,所以在查资料的过程中发现可以这样做一个比例尺。该方案只要在地球足够大(地球显示的部分跟屏幕下方有重合即可)的时候,就能显示出当前的比例尺。原理是根据屏幕上的点能计算出球面上的实际距离,然后进行转化就能得到。

直接上代码如下:

var geodesic = new EllipsoidGeodesic();

var distances = [
	1, 2, 3, 5,
	10, 20, 30, 50,
	100, 200, 300, 500,
	1000, 2000, 3000, 5000,
	10000, 20000, 30000, 50000,
	100000, 200000, 300000, 500000,
	1000000, 2000000, 3000000, 5000000,
	10000000, 20000000, 30000000, 50000000];

function updateDistanceLegendCesium(viewModel, scene) {
	if (!viewModel.enableDistanceLegend)
	{
		 viewModel.barWidth = undefined;
		viewModel.distanceLabel = undefined;
		return;
	}
	var now = getTimestamp();
	if (now < viewModel._lastLegendUpdate + 250) {
		return;
	}

	viewModel._lastLegendUpdate = now;

	// Find the distance between two pixels at the bottom center of the screen.
	var width = scene.canvas.clientWidth;
	var height = scene.canvas.clientHeight;

	var left = scene.camera.getPickRay(new Cartesian2((width / 2) | 0, height - 1));
	var right = scene.camera.getPickRay(new Cartesian2(1 + (width / 2) | 0, height - 1));

	var globe = scene.globe;
	var leftPosition = globe.pick(left, scene);
	var rightPosition = globe.pick(right, scene);

	if (!defined(leftPosition) || !defined(rightPosition)) {
		viewModel.barWidth = undefined;
		viewModel.distanceLabel = undefined;
		return;
	}

	var leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition);
	var rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition);

	geodesic.setEndPoints(leftCartographic, rightCartographic);
	var pixelDistance = geodesic.surfaceDistance;

	// Find the first distance that makes the scale bar less than 100 pixels.
	var maxBarWidth = 100;
	var distance;
	for (var i = distances.length - 1; !defined(distance) &amp;&amp; i >= 0; --i) {
		if (distances[i] / pixelDistance < maxBarWidth) {
			distance = distances[i];
		}
	}

	if (defined(distance)) {
		var label;
		if (distance >= 1000) {
			label = (distance / 1000).toString() + ' km';
		} else {
			label = distance.toString() + ' m';
		}

		viewModel.barWidth = (distance / pixelDistance) | 0;
		viewModel.distanceLabel = label;
	} else {
		viewModel.barWidth = undefined;
		viewModel.distanceLabel = undefined;
	}
}

化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


在Unity3d里面,GameObject是一个常见的概念:一个空的GameObject,只含有transform组件,可用来做其他物体的容器或者挂接各种component而具备特定功能。在Cesium中,差不多对等的应该算是Entity。Unity场景中,都是GameObject和它的child(ren)的组合。在Cesium场景中,viewer专门有entities这样的变量来管理所有的entity(当然还有primitives。但是官方推荐是entity)。

下面的代码可以看到Entity在空的时候,可以做为一个类似组的方式,组合它的child(ren)。而非空的时候,可以作为一个实际可见的物体显示在Cesium的场景中。

//Set the random seed for reproducible random colors.
Cesium.Math.setRandomNumberSeed(1234);

var viewer = new Cesium.Viewer('cesiumContainer', { infoBox : false });
var entities = viewer.entities;

//Create Entity "folders" to allow us to turn on/off entities as a group.
var spheres = entities.add(new Cesium.Entity());
var boxes = entities.add(new Cesium.Entity());
var ellipsoids = entities.add(new Cesium.Entity());

//Create the entities and assign each entity's parent to the group to which it belongs.
for (var i = 0; i < 5; ++i) {
    var height = 100000.0 + (200000.0 * i);
    entities.add({
        parent : boxes,
        position : Cesium.Cartesian3.fromDegrees(-106.0, 45.0, height),
        box : {
            dimensions : new Cesium.Cartesian3(90000.0, 90000.0, 90000.0),
            material : Cesium.Color.fromRandom({alpha : 1.0})
        }
    });

    entities.add({
        parent : ellipsoids,
        position : Cesium.Cartesian3.fromDegrees(-102.0, 45.0, height),
        ellipsoid : {
            radii : new Cesium.Cartesian3(45000.0, 45000.0, 90000.0),
            material : Cesium.Color.fromRandom({alpha : 1.0})
        }
    });

    entities.add({
        parent : spheres,
        position : Cesium.Cartesian3.fromDegrees(-98.0, 45.0, height),
        ellipsoid : {
            radii : new Cesium.Cartesian3(67500.0, 67500.0, 67500.0),
            material : Cesium.Color.fromRandom({alpha : 1.0})
        }
    });
}

viewer.zoomTo(viewer.entities);

Sandcastle.addToolbarButton('Toggle Boxes', function(){
    boxes.show = !boxes.show;
});

Sandcastle.addToolbarButton('Toggle Ellipsoids', function(){
    ellipsoids.show = !ellipsoids.show;
});

Sandcastle.addToolbarButton('Toggle Spheres', function(){
    spheres.show = !spheres.show;
});


化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


如果想基于Cesium制作编辑器,那么这个可能是绕不过的必须要用到的一个点,在编辑器上显示本地的角度会更直观。准备尝试用下面的方式来控制:

import {
    Cartesian3,
    HeadingPitchRoll,
    Matrix3,
    Matrix4,
    Quaternion,
    Transforms,
} from "cesium";

/**
 * Convert a local heading/pitch/range rotation to an earth-axis-relative Quaternion
 * @param position a Cartesian3 point in space
 * @param heading degrees from North, rotation around Earth-normal vector
 * @param pitch degrees from horizontal, rotation around earth-tangent X axis
 * @param roll degrees from vertical, rotation around earth-tangent Y axis
 */
export function relativeOrientation(position: Cartesian3,
        heading: number, pitch: number, roll: number): Quaternion {
    // Build a Quaternion that represents the rotation between absolute and
    // local-surface frames of reference
    const transform4 = Transforms.eastNorthUpToFixedFrame(position);
    const transform3 = new Matrix3();
    Matrix4.getRotation(transform4, transform3);
    const transformQ = Quaternion.fromRotationMatrix(transform3);

    // Convert the h/p/r values to a (local-reference) Quaternion
    const localHpr = HeadingPitchRoll.fromDegrees(heading, pitch, roll);
    const localQ = Quaternion.fromHeadingPitchRoll(localHpr);

    // Result is local times transform
    const ret = new Quaternion();
    Quaternion.multiply(localQ, transformQ, ret);
    return ret;
}

或者,这段代码能给你一些提示吗?

var getModelMatrix = function(lon, lat, rotationZ) {
    // 1) create a translation position matrix
    var posMat = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(lon, lat));
    // 2) create a Matrix3 with a given Z rotation
    var rotMat3 = Cesium.Matrix3.fromRotationZ(Math.random() * 360);                        
    // 3) transform the Matrix3 into a Matrix4 with no translation
    var rotMat4 = Cesium.Matrix4.fromRotationTranslation(rotMat3, undefined, undefined);
    // 4) empty matrix to place result in
    var result = new Cesium.Matrix4();
    // 5) multiply position by rotation
    return Cesium.Matrix4.multiply(posMat, rotMat4, result);             
};

结论:第一段里面的代码是可行的,不过实验中发现一个细节:

 Quaternion.multiply( localQ, quaternion, ret); 

的第1参数和第2参数需要调换一下顺序。总体思路是对的。


化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


在Cesium的demo演示用例中,有不少用到UI的地方。因为整个引擎是架构在html和javascript之上,所以这里的UI的核心脱不开html、css等。但是因为现在的javascript也日新月异,Cesium在这里用了Knockout库。这个库提供javascript和html物体的绑定关系:一旦绑定后,那么html中已绑定的元素相关值的“ 设置 ”和“值改变的侦听”都比传统的纯html方便很多。

官方主页就有简单的例子:

https://knockoutjs.com/documentation/text-binding.html

简单来说,Knockout库使用只要几个简单步骤:

1、在html5的要绑定元素的属性中,加入一个data-bind字眼,如

    <table id="mytable">
    <tbody>
    <tr><td class="header">Translation</td></tr>
    <tr>
        <td>
            <input type="text" size="5" data-bind="value: translationX">
        </td>
        <td>
            <input type="text" size="5" data-bind="value: translationY">
        </td>
        <td>
            <input type="text" size="5" data-bind="value: translationZ">
        </td>
    </tr>
    </tbody></table>

2、在javascript中写对应的viewmodel,如

 var viewModel = {
      translationX : 0,
      translationY : 0,
      translationZ : 0,
 }; 

3、让Knockout库跟踪viewmodel,

     Cesium.knockout.track(viewModel); 

4、实施绑定,比如

var table = document.getElementById('mytable');   Cesium.knockout.applyBindings(viewModel, table); 

5、绑定后我们可以通过这样改变相应的元素的值

viewModel.translationX = cartographic.longitude.toFixed(4);

6、如果相应的元素有改变,我们可以这样知道它改变了

 Cesium.knockout.getObservable(viewModel, 'translationX').subscribe(
        function(newValue) {
            console.log("new value of translation X is: " + newValue);
        }
    ); 

化石原创文章,转载请注明来源并保留原文链接



化石原创文章,转载请注明来源并保留原文链接


看到一个通过顶点和索引值来构造自定义模型的官方文档,看说明应该是老的版本才能用,所以就没有测试。但是把链接和代码放在这里,用来理解内部的东西有用。

/*global define*/
define([
        './Cartesian3',
        './ComponentDatatype',
        './PrimitiveType',
        './BoundingSphere',
        './GeometryAttribute',
        './GeometryAttributes',
        './GeometryPipeline',
        './VertexFormat',
        './Geometry'
    ], function(
        Cartesian3,
        ComponentDatatype,
        PrimitiveType,
        BoundingSphere,
        GeometryAttribute,
        GeometryAttributes,
        GeometryPipeline,
        VertexFormat,
        Geometry) {
    "use strict";

    var TetrahedronGeometry = function() {
        var negativeRootTwoOverThree = -Math.sqrt(2.0) / 3.0;
        var negativeOneThird = -1.0 / 3.0;
        var rootSixOverThree = Math.sqrt(6.0) / 3.0;

        var positions = new Float64Array(4 * 3);

        // position 0
        positions[0] = 0.0;
        positions[1] = 0.0;
        positions[2] = 1.0;

        // position 1
        positions[3] = 0.0;
        positions[4] = (2.0 * Math.sqrt(2.0)) / 3.0;
        positions[5] = negativeOneThird;

        // position 2
        positions[6] = -rootSixOverThree;
        positions[7] = negativeRootTwoOverThree;
        positions[8] = negativeOneThird;

        // position 3
        positions[9] = rootSixOverThree;
        positions[10] = negativeRootTwoOverThree;
        positions[11] = negativeOneThird;

        var attributes = new GeometryAttributes({
            position : new GeometryAttribute({
                componentDatatype : ComponentDatatype.DOUBLE,
                componentsPerAttribute : 3,
                values : positions
            })
        });

        var indices = new Uint16Array(4 * 3);

        // back triangle
        indices[0] = 0;
        indices[1] = 1;
        indices[2] = 2;

        // left triangle
        indices[3] = 0;
        indices[4] = 2;
        indices[5] = 3;

        // right triangle
        indices[6] = 0;
        indices[7] = 3;
        indices[8] = 1;

        // bottom triangle
        indices[9] = 2;
        indices[10] = 1;
        indices[11] = 3;

        this.attributes = attributes;
        this.indices = indices;
        this.primitiveType = PrimitiveType.TRIANGLES;
        this.boundingSphere = undefined;
    };

    return TetrahedronGeometry;
});

代码出处:https://github.com/AnalyticalGraphicsInc/cesium/wiki/Geometry-and-Appearances


化石原创文章,转载请注明来源并保留原文链接