Usage of mxdraw with Mapbox

8/16/2022

# How do Mapbox maps and CAD drawings appear together?

Mapbox is an interactive map rendered through webgl, and mxdraw is also implemented with webgl rendering.

Therefore, we can combine the custom layers provided by Mapbox with the control instances of mxdraw to display CAD layers and maps together.

If you are not familiar with Mapbox, please refer to official documentation in Chinese (opens new window) / International site (opens new window)

The following code is the simplest example of using Mapbox and mxdraw together.


# Install the corresponding dependencies first

npm install mapbox-gl mxdraw

<div id="map"></div>


import mapboxgl from "mapbox-gl";
import Mx from "mxdraw"
import * as THREE from "three"

// Token needs to be applied for on the Mapbox official website 
mapboxgl.accessToken = "pk.eyJ1IjoibWFvcmV5IiwiYSI6ImNqNWhrenIwcDFvbXUyd3I2bTJxYzZ4em8ifQ.KHZIehQuWW9AsMaGtATdwA"

// GPS location of Beijing
const center = [116.391305, 39.90553]

const map = new mapboxgl.Map({
    // The HTML element that Mapbox GL JS renders the map in, or the element's string ID. This specified element cannot have children.
    container: 'map',
    // Map location 
    center,
    // Map style 
    style: 'mapbox://styles/mapbox/streets-v11',
    zoom: 16
})

// Height of the drawing or model
const modelAltitude = 100;

// Convert LngLat projection to Mercator projection coordinates
const point = mapboxgl.MercatorCoordinate.fromLngLat(
    center,
    modelAltitude
);
// Returns the distance of 1 meter in Mercator coordinate units at this latitude.
// For real-world coordinates using meters, this naturally provides a scale for converting to Mercator projection coordinates.
const lDistForM = point.meterInMercatorCoordinateUnits();

// The range of the CAD drawing in reality is currently determined to be 1 kilometer
const lCADArea = 1000 * lDistForM * 1;

// Provide some necessary Mapbox information and give some core methods provided by mxdraw
let mxMap = {
    // Canvas element generated by Mapbox 
    canvas: null,
    // gl context provided by custom layers
    gl: void 0,
    // Location 1 of the CAD drawing 
    cadLocation1: new THREE.Vector3(),
    // Location 2 of the CAD drawing 
    cadLocation2: new THREE.Vector3(),
    // Elevation 
    elevation: 0,
    // Custom layer information 
    customLayer: {},
    // CAD drawing control object 
    mxObj: null,
    // Coordinate transformation matrix 1 
    matCadToMap: new THREE.Matrix4(),
     // Coordinate transformation matrix 2
    matMapToCad: new THREE.Matrix4(),
    // Matrix for custom layer
    matrix: undefined,
    // Rendering function
    render(gl, matrix){

    },
    // Method for mutual transformation of coordinates
    cadToMercatorCoord(pt) {
        pt.applyMatrix4(this.matCadToMap);
        return new mapboxgl.MercatorCoordinate(pt.x,pt.y,pt.z); 
    },
    
    mercatorCoordToCad(pt){
        let ptRet = new THREE.Vector3(pt.x,pt.y,pt.z);
        ptRet.applyMatrix4(this.matMapToCad);
        return ptRet; 
    },

    cadLongToMercatorCoord(len){
        let pt1 = new THREE.Vector3(0,0,0);
        let pt2 = new THREE.Vector3(len,0,0);
        pt1.applyMatrix4(this.matCadToMap);
        pt2.applyMatrix4(this.matCadToMap);
        return pt1.distanceTo(pt2);
    }

}
// With the above information, you can determine the specific location of the CAD drawing
mxMap.cadLocation1 = new THREE.Vector3(point.x - lCADArea / 2, point.y - lCADArea, point.z);
mxMap.cadLocation2 = new THREE.Vector3(point.x + lCADArea, point.y + lCADArea / 2, point.z);

// Add a Mapbox custom layer
const customLayer = {
    id: "3d-model", // Any unique ID
    type: "custom",
    renderingMode: "3d",
    async onAdd(map, gl) {
        // Load mxdraw core library synchronously
        await Mx.loadCoreCode()
        // Get the canvas element of Mapbox
        mxMap.canvas = map.getCanvas();
        // Get the webgl context as well 
        mxMap.gl = gl
        // Create a drawing control object
        Mx.MxFun.createMxObject({
            // Parameters required by MapBox
            mapBox: mxMap,
            // Drawing to be opened
            cadFile: "../../demo/buf/$hhhh.dwg",
            callback: (mxObj) => {
                mxMap.mxObj = mxObj;
                mxObj.addEvent("loadComplete", () => {
                    // Update Mapbox
                    map.triggerRepaint()
                });
            }
        }); 
  
    },
    render(gl, matrix) {

        // Assign matrix information 
        mxMap.matrix = matrix
        // After creating the drawing, a rendering function will be provided to update the drawing
        mxMap.render(gl, matrix);

        // Refresh Mapbox
        map.triggerRepaint()
    }
};
// Assign the information of this custom layer
mxMap.customLayer = customLayer
// Add the custom layer

map.on('style.load', ()=> {
    map.addLayer(customLayer)
})

Effect: