preface

Three-dimensional scenes often require a navigation marker to determine the location of the scene.

There are two general forms of expression: compass, small square box (azimuth rubik’s cube).

Refer to the Encyclopedia of Baidu
mayaInterface, you can see that there is a small box marking the location in the upper right corner, which is it:




Hightopo’s HT for Web product makes it easy to construct lightweight 3D visualization scenes. On the Web side, we can use the HT 2D engine and 3D rendering engine to achieve this function, and build a simple Maya like interface.

Preview the address: www.hightopo.com/demo/compas…

Interface introduction and effect preview

In this interface, we used a 2D scene and two 3D scenes, and the specific effects are as follows:

Function implementation

To describe the layout of the page:

The compassThrough the
ht.graph.GraphView To set a pre-drawn icon for a primitive, just put it in the top left corner of the drawing (position 1 in the image below).



Orientation Rubik’s Cube is achieved by placing a Rubik’s Cube OBJ model in a small scene (HT.graph3d.graph3DView) and placing this small scene in the upper right corner of the drawing (position 2 in the image below).

Main 3D scene (
ht.graph3d.Graph3dView) as the background at the bottom of the entire two-dimensional page (position 3 in the image below).

Code examples:

const g3d = new ht.graph3d.Graph3dView();
g3d.setOriginAxisVisible(true);
g3d.setGridVisible(true);
g3d.addToDOM();
const g2d = new ht.graph.GraphView();
g2d.deserialize('displays/test.json', json => {
    g2d.addToDOM(g3d.getView());
});Copy the code
Position relation:

Compass synchronization

Let’s first specify the orientation. Let’s take the direction of the negative half of the Z axis as north, the positive half of the Z axis as south, the positive half of the X axis as east and the negative half of the X axis as west.



Since the compass’s purpose is to indicate the direction in the aerial view, it has nothing to do with the Y-axis, and we can put the whole calculation process in two dimensions.

Code examples:

const eye = this.g3d.getEye();
const center = this.g3d.getCenter();
const v = new ht.Math.Vector2(eye[0], eye[2]);
const v2 = new ht.Math.Vector2(center[0], center[2]);
const angle = v.sub(v2).angle() - Math.PI / 2;
compass.setRotation(-angle);
compass.a('angle', angle);
compass.a('angle2', angle);Copy the code
In this code, we use
eye (Camera) and
center (observation point) to construct two two-dimensional vectors (
ht.Math.Vector2), and discard the Y-axis component.



Use vector subtraction to find the vector pointing from center to eye and store it in variable V. Use Angle () to obtain the Angle (in radians) between the current vector and the positive half axis of X (i.e., due east). Why subtract math.pi / 2? Because we calculate the Angle with the x axis, the positive direction of the compass (north) corresponds to the negative half of the Z axis.

After finding the Angle of rotation, we pass
setRotation() We can set the rotation Angle of the compass pixel, why take a negative value (
– angle)? Because when you look counterclockwise,
coordinate
The compassIt moves in the opposite direction to the human eye, that is, clockwise.



Using the data binding feature provided by the HT 2D engine, the rotation Angle of the wheel icon and the Angle icon can be dynamically changed in real time by setting property values to the compass node.

Each time the line of sight changes, the above calculations and Settings are required. We can achieve this by adding a property listener to the 3D scene component:

graph3dView.addPropertyChangeListener(e= >{
    if(e.property === 'eye' || e.property === 'center'){
        changeCompass();
        / /...}});Copy the code
Legend reference:

Azimuth rubik’s cube in sync

First of all, specify the orientation, X positive half axis is right, negative half axis is left; Y positive half axis is the top, negative half axis is the bottom; The positive Z axis is forward and the negative Z axis is backward.

The orientation Rubik’s cube is different from a compass in that it is used to show the direction of the line of sight in three dimensions.

At the same time, it is also an interactive azimuth joystick, which can easily and quickly change the current view to top view, side view, etc.

Vision change triggers rubik’s Cube transform

Code examples:

graph3dView.addPropertyChangeListener(e= > {
    if (e.property === 'eye') {
        const newValue = e.newValue;
        const vEye = new ht.Math.Vector3(newValue[0], newValue[1], newValue[2]).normalize();
        graph3dView2.setEye([300 * vEye.x, 300 * vEye.y, 300* vEye.z]); }});Copy the code
In the above code we listen to the main 3D scene (
graph3dView)
eye Property changes to dynamically change small scenes (
graph3dView2) to achieve the linkage effect.



Where, e.newValue will get the value of the scene view after the change. We use this value to build a THREE-DIMENSIONAL vector (HT.math.vector3) and call normalize() to normalize, so that the distance obtained from any Angle and position can be consistent.

The reason why I’m multiplying this by 300 is that this is a good distance to look at, but you can change it to something else if you want.

Examples of effects:

Click the Rubik’s Cube to change the perspective of the scene

In order to change the sight in the main scene by clicking the Rubik’s Cube, a very key information is needed, that is, which side of the cube is clicked with the mouse.



Here we need to use a intersection method: graph3dView. IntersectObject (event, data), the method returns an object, the object is used to describe location information, click the world properties used to represent click on the location of world coordinates.

Code examples:

graph3dView2.addInteractorListener(event= > {
    if (event.kind === 'clickData') {
        const obj = graph3dView2.intersectObject(event.event, event.data);
        if(obj) {
            const world = obj.world;
            / /...}}});Copy the code
So with this world property that describes where we clicked on it, we can easily figure out which side we clicked on, because our little square is placed at the origin, and it’s a regular hexahedron, and these two key pieces of information determine which side we clicked on, The value of the component of the axis corresponding to the plane clicked must be greater than that of the other two axes. Therefore, we can simply judge which value of the three components is larger to determine which axis the line of sight is closer to, and then judge whether it is on the positive or negative axis by judging the sign of the component.



After determining which side to click on, you only need to set the position of each view point (eye) in the two 3D scenes.

Code examples:

const world = obj.world;
const x = world.x;
const y = world.y;
const z = world.z;
if (Math.abs(x) - Math.abs(y) > 0 && Math.abs(x) - Math.abs(z) > 0) {
    if (x > 0) {
        graph3dView2.setEye([300.0.0]);
        graph3dView.setEye([this._distance, 0.0]);
        graph3dView2.setCenter([0.0.0]);
        this._g3d.setCenter([0.0.0]);
    } else {
        graph3dView2.setEye([- 300..0.0]);
        graph3dView.setEye([-this._distance, 0.0]);
        graph3dView2.setCenter([0.0.0]);
        graph3dView.setCenter([0.0.0]); }}else if (Math.abs(y) - Math.abs(x) > 0 && Math.abs(y) - Math.abs(z) > 0) {
    / /...
}Copy the code


Where, this._distance is used to describe the distance between the line of sight and the origin in the main scene, which can be adjusted according to needs. 300 is consistent with the previous description, which is a more suitable Angle of view in a small scene, and can also be adjusted according to needs.

Finally, we need to deal with the issue of small squares changing color when clicked (this is not a problem, depending on your needs). We can set the following Settings at the end of the click event listener:

1 const sm = graph3dView2.dm().getSelectionModel();
2 sm.setSelection(null);Copy the code
Click on each side of the Rubik’s Cube to demonstrate the effect:

conclusion

The intuitive orientation indicator is widely used in indoor positioning, GIS, station, airport and many other scenarios. It can be easily realized by using the 2D and 3D engine provided by HT.



Web 3D has unlimited imagination, rich data presentation methods, and many eye-catching visualizations, waiting for us to apply these data presentation methods to various industries. HT has made a lot of exploration and attempts in this aspect, such as this interesting solar system monitoring system: www.hightopo.com/demo/solar-…



In 2019, we have also updated hundreds of 2D/3D visualization case sets of industrial Internet, where you can find many novel examples and discover different industrial Internet: Share hundreds of 2D 3D Visualization cases of HT Industrial Internet 2019. For more industrial application examples, please refer to the case link on the official website:

www.hightopo.com/demos/index…