Measuring Radius

Change the mouse mode to radius measurement mode, then measure the radius from the click point.

The first click point becomes the center, and the distance to the second click point forms the radius.

The measurement results are returned via an event and visualized as a POI.

Feature Implementation

Symbol

A texture map object that stores image textures is stored here.

For a brief explanation of JSSymbol, refer to the step 5. Creating a Distance Object section of the distance measurement tutorial.

POILayer

This variable stores the layer where the created JSPoint objects are saved.

The process of storing the layer is referred to in the step 1. Creating a Layer phase.

WallLayer

This is a layer that stores the wall polygon that delineates the radius.

The process of storing the layer is referred to in the step 1. Creating a Layer phase.

Here is the complete code that implements the above feature.
/* Initialization function to run after engine load (Module.postRun) */
function init() {
    Module.Start(window.innerWidth, window.innerHeight);

    // Set camera location
    Module.getViewCamera().setLocation(new Module.JSVector3D(129.128265, 35.171834, 1000.0));

    // Create a symbol for icon management
    GLOBAL.Symbol = Module.getSymbol();

    // Create an output POI layer for analysis
    var layerList = new Module.JSLayerList(true);
    GLOBAL.POILayer = layerList.createLayer("MEASURE_POI", Module.ELT_3DPOINT);
    GLOBAL.POILayer.setMaxDistance(20000.0);
    GLOBAL.POILayer.setSelectable(false);

    GLOBAL.WallLayer = layerList.createLayer("MEASURE_WALL", Module.ELT_POLYHEDRON);
    GLOBAL.WallLayer.setMaxDistance(20000.0);
    GLOBAL.WallLayer.setSelectable(false);
    GLOBAL.WallLayer.setEditable(true);

    initEvent(Module.canvas);
}

var GLOBAL = {
    Symbol: null, // Icon management symbol object
    POILayer: null, // POI storage layer
    WallLayer: 0, // POI, Icon creation index
};

/* Event setup */
function initEvent(canvas) {
    // Radius event setup
    canvas.addEventListener("Fire_EventAddRadius", function (e) {
        if (e.dTotalDistance > 0) {
            // Delete POI object
            clearIcon();

            // Create radius POI object
            createPOI(new Module.JSVector3D(e.dMidLon, e.dMidLat, e.dMidAlt), "rgba(255, 204, 198, 0.8)", e.dTotalDistance, true);
        }
    });
}

/* Change mouse state */
function setMouseState(_option) {
    // Set mouse mode
    Module.XDSetMouseState(_option);
}

/* Create POI for output analysis */
function createPOI(_position, _color, _value, _balloonType) {
    // Create a canvas to draw the POI icon image
    var drawCanvas = document.createElement("canvas");
    drawCanvas.width = 100;
    drawCanvas.height = 100;

    // Return icon image data
    var imageData = drawIcon(drawCanvas, _color, _value, _balloonType);

    // Register icon image in symbol
    if (GLOBAL.Symbol.insertIcon("Icon", imageData, drawCanvas.width, drawCanvas.height)) {
        // Return registered icon object
        var icon = GLOBAL.Symbol.getIcon("Icon");

        // Create JSPoint object
        var poi = Module.createPoint("POI");

        poi.setPosition(_position); // Set location
        poi.setIcon(icon); // Set icon

        // Add object to layer
        GLOBAL.POILayer.addObject(poi, 0);
    }
}

/* Return icon image data */
function drawIcon(_canvas, _color, _value, _balloonType) {
    // Return context and clear background
    var ctx = _canvas.getContext("2d"),
        width = _canvas.width,
        height = _canvas.height;
    ctx.clearRect(0, 0, width, height);

    // Set background Draw Path then draw text
    if (_balloonType) {
        drawBalloon(ctx, height * 0.5, width, height, 5, height * 0.25, _color);
        setText(ctx, width * 0.5, height * 0.2, _value);
    } else {
        drawRoundRect(ctx, 0, height * 0.3, width, height * 0.25, 5, _color);
        setText(ctx, width * 0.5, height * 0.5, _value);
    }

    return ctx.getImageData(0, 0, _canvas.width, _canvas.height).data;
}

/* Draw balloon background */
function drawBalloon(ctx, marginBottom, width, height, barWidth, barHeight, color) {
    var wCenter = width * 0.5,
        hCenter = height * 0.5;

    // Set the shape of the balloon Draw Path
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, height - barHeight - marginBottom);
    ctx.lineTo(wCenter - barWidth, height - barHeight - marginBottom);
    ctx.lineTo(wCenter, height - marginBottom);
    ctx.lineTo(wCenter + barWidth, height - barHeight - marginBottom);
    ctx.lineTo(width, height - barHeight - marginBottom);
    ctx.lineTo(width, 0);
    ctx.closePath();

    // Draw the balloon
    ctx.fillStyle = color;
    ctx.fill();
}

/* Draw rounded rectangle background */
function drawRoundRect(ctx, x, y, width, height, radius, color) {
    if (width < 2 * radius) radius = width * 0.5;
    if (height < 2 * radius) radius = height * 0.5;

    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.arcTo(x + width, y, x + width, y + height, radius);
    ctx.arcTo(x + width, y + height, x, y + height, radius);
    ctx.arcTo(x, y + height, x, y, radius);
    ctx.arcTo(x, y, x + width, y, radius);
    ctx.closePath();

    // Draw the rectangle
    ctx.fillStyle = color;
    ctx.fill();

    return ctx;
}

/* Draw text */
function setText(_ctx, _posX, _posY, _value) {
    var strText = "";

    // Set text string
    if (typeof _value == "number") {
        strText = setKilloUnit(_value, 0.001, 0);
    } else {
        strText = _value;
    }

    // Set text style
    _ctx.font = "bold 16px sans-serif";
    _ctx.textAlign = "center";
    _ctx.fillStyle = "rgb(0, 0, 0)";

    // Draw text
    _ctx.fillText(strText, _posX, _posY);
}

/* Convert to m/km text */
function setKilloUnit(_text, _meterToKilloRate, _decimalSize) {
    if (_decimalSize < 0) {
        _decimalSize = 0;
    }
    if (typeof _text == "number") {
        if (_text < 1.0 / (_meterToKilloRate * Math.pow(10, _decimalSize))) {
            _text = _text.toFixed(1).toString() + "m";
        } else {
            _text = (_text * _meterToKilloRate).toFixed(2).toString() + "㎞";
        }
    }
    return _text;
}

/* Clear analysis content */
function clearAnalysis() {
    // Clear ongoing analysis content
    Module.XDClearCircleMeasurement();

    if (GLOBAL.WallLayer == null) {
        return;
    }

    // Delete icon
    clearIcon();

    // Delete POI object
    GLOBAL.WallLayer.removeAll();
}

/* Clear icon */
function clearIcon() {
    if (GLOBAL.POILayer == null) {
        return;
    }

    // Delete registered icon list
    var icon, poi;

    poi = GLOBAL.POILayer.keyAtObject("POI");

    if (poi == null) {
        return;
    }

    icon = poi.getIcon();

    // Delete POI referencing icon
    GLOBAL.POILayer.removeAtKey("POI");

    // Delete icon from symbol
    GLOBAL.Symbol.deleteIcon(icon.getId());
}

Following are the detailed steps of the code.

step 1. Creating a Layer

Create a layer to visualize the radius measurement Icon and radius value.

For an explanation of layer types, refer here.

var layerList = new Module.JSLayerList(true);

GLOBAL.POILayer = layerList.createLayer("MEASURE_POI", Module.ELT_3DPOINT);
GLOBAL.POILayer.setMaxDistance(20000.0);
GLOBAL.POILayer.setSelectable(false);

GLOBAL.WallLayer = layerList.createLayer("MEASURE_WALL", Module.ELT_POLYHEDRON);
GLOBAL.WallLayer.setMaxDistance(20000.0);
GLOBAL.WallLayer.setSelectable(false);
GLOBAL.WallLayer.setEditable(true);

step 2. Registering an Event

Register an event to receive the calculated radius.

function initEvent(canvas) {
    // Radius event setup
    canvas.addEventListener("Fire_EventAddRadius", function (e) {
        if (e.dTotalDistance > 0) {
            // Create radius POI object
            createPOI(new Module.JSVector3D(e.dMidLon, e.dMidLat, e.dMidAlt), "rgba(255, 204, 198, 0.8)", e.dTotalDistance);
        }
        j;
    });
}

The Fire_EventAddRadius event occurs when the mouse mode is set to MML_ANALYS_AREA_CIRCLE.

step 3. Changing Mouse Mode

Change the mouse mode for radius measurement.

For an explanation of mouse modes, refer here.

Module.XDSetMouseState(Module.MML_ANALYS_AREA_CIRCLE);

step 4 - 1. Creating a Radius Icon

Create an Icon to render the returned radius value.

function drawIcon(_canvas, _color, _value) {
    // Return context and clear background
    var ctx = _canvas.getContext("2d"),
        width = _canvas.width,
        height = _canvas.height;
    ctx.clearRect(0, 0, width, height);

    // Set background Draw Path then draw text
    drawBalloon(ctx, height * 0.5, width, height, 5, height * 0.25, _color);
    setText(ctx, width * 0.5, height * 0.2, _value);

    return ctx.getImageData(0, 0, _canvas.width, _canvas.height).data;
}

First, create a canvas to draw the image, paint a background for the text (step 4-2. Creating a Radius Balloon Icon), and then input the returned altitude value as text (step 4-3. Creating a Radius Measurement Result Icon).

step 4 - 2. Creating a Radius Balloon Icon

Draw a balloon on the canvas to visualize the returned radius value.

function drawBalloon(ctx, marginBottom, width, height, barWidth, barHeight, color) {
    var wCenter = width * 0.5,
        hCenter = height * 0.5;

    // Set the shape of the balloon Draw Path
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, height - barHeight - marginBottom);
    ctx.lineTo(wCenter - barWidth, height - barHeight - marginBottom);
    ctx.lineTo(wCenter, height - marginBottom);
    ctx.lineTo(wCenter + barWidth, height - barHeight - marginBottom);
    ctx.lineTo(width, height - barHeight - marginBottom);
    ctx.lineTo(width, 0);
    ctx.closePath();

    // Draw the balloon
    ctx.fillStyle = color;
    ctx.fill();
}

step 4 - 3. Creating a Radius Measurement Result Icon

Draw the returned radius value as text on the balloon.

function setText(_ctx, _posX, _posY, _value) {
    var strText = "";

    // Set text string
    if (typeof _value == "number") {
        strText = setKilloUnit(_value, 0.001, 0);
    } else {
        strText = _value;
    }

    // Set text style
    _ctx.font = "bold 16px sans-serif";
    _ctx.textAlign = "center";
    _ctx.fillStyle = "rgb(0, 0, 0)";

    // Draw text
    _ctx.fillText(strText, _posX, _posY);
}

step 4 - 4. Converting to m/km Text

Convert the returned radius value to m/km text.

function setKilloUnit(_text, _meterToKilloRate, _decimalSize) {
    if (_decimalSize < 0) {
        _decimalSize = 0;
    }
    if (typeof _text == "number") {
        if (_text < 1.0 / (_meterToKilloRate * Math.pow(10, _decimalSize))) {
            _text = _text.toFixed(1).toString() + "m";
        } else {
            _text = (_text * _meterToKilloRate).toFixed(2).toString() + "㎞";
        }
    }
    return _text;
}

step 5. Creating a Radius Object

Create an object with the created Icon and add it to the layer.

function createPOI(_position, _color, _value) {
    // Create a canvas to draw the POI icon image
    var drawCanvas = document.createElement("canvas");
    drawCanvas.width = 100;
    drawCanvas.height = 100;

    // Return icon image data
    var imageData = drawIcon(drawCanvas, _color, _value);

    // Register icon image in symbol
    if (GLOBAL.Symbol.insertIcon("Icon", imageData, drawCanvas.width, drawCanvas.height)) {
        // Return registered icon object
        var icon = GLOBAL.Symbol.getIcon("Icon");

        // Create JSPoint object
        var poi = Module.createPoint("POI");

        poi.setPosition(_position); // Set location
        poi.setIcon(icon); // Set icon

        // Add object to layer
        GLOBAL.POILayer.addObject(poi, 0);
    }
}

step 6. Clearing Radius Measurement

Clear the radius measurement results and objects.

function clearAnalysis() {
    // Clear ongoing analysis content
    Module.XDClearCircleMeasurement();

    if (GLOBAL.WallLayer == null) {
        return;
    }

    // Delete icon
    clearIcon();

    // Delete POI object
    GLOBAL.WallLayer.removeAll();
}

/* Clear icon */
function clearIcon() {
    if (GLOBAL.POILayer == null) {
        return;
    }

    // Delete registered icon list
    var icon, poi;

    poi = GLOBAL.POILayer.keyAtObject("POI");

    if (poi == null) {
        return;
    }

    icon = poi.getIcon();

    // Delete POI referencing icon
    GLOBAL.POILayer.removeAtKey("POI");

    // Delete icon from symbol
    GLOBAL.Symbol.deleteIcon(icon.getId());
}

Result Screen

If you want to check the live code of the radius measurement process, click here.

Last updated