Measurement

How to measure a model

There are two ways to measure a model. We can measure with the triangulated data, or for models that contain BREP data, we can measure using the data that is embedded when the model is converted. Using the BREP data will give us a more accurate measurement. This will work for faces and edges, however for point to point measurement, we will have to use the triangulated data.

The subentity properties for a face or edge can be retrieved using the getFaceProperty and getEdgeProperty functions.

The subentity properties contains measurement data for the corresponding face or line. Each property object corresponds to the type of edge or line, and the measurement properties that can be accessed will differ accordingly.

For example, a LineElement, which corresponds to a Line edge type, will have a length property. Some face or edge types may have properties that are the same. For example, a CircleElement, CylinderElement, and ConeElement, will all have radius, origin, and normal properties.

To see all the subentity property types, please refer to the docs here

When measuring, it is important to take into account the unit scale. The unit scale is a number that represents the size of the unit. A model measured in inches would have a unit scale of 25.4.

All measurements values are in millimeters. To get inches, divide by the unit scale of 25.4. For example, when measuring the length of an edge, a value of 50.8 represents 2 inches.

For more information on unit scaling, see the Model Units Programming Guide.

Edge / face / point measure

Communicator has native four measurement operators:

MeasureEdgeLengthOperator - Measures the length of edges. For circles, measures the radius. MeasureFaceFaceAngleOperator - Measures the angles between two faces. MeasureFaceFaceDistanceOperator - Measures the distance between two faces. MeasurePointPointDistanceOperator - Measures the distance between two points.

How to insert 2D and 3D text

3D text can be inserted by creating a texture. [See the text_insertion example] 2D text can be inserted by creating a markup item with a text shape.

    class CustomMarkupItem extends Communicator.Markup.MarkupItem {
        constructor(viewer, position, text) {
            super();
            this._textShape = new Communicator.Markup.Shape.TextBox();
            this._viewer = viewer;
            this._position = position;
            this._textShape.setTextString(text);
            this._textShape.getBoxPortion().setFillOpacity(1);
            this._textShape.getBoxPortion().setFillColor(new Communicator.Color(255, 255, 255));
        }
        draw() {
            const updatedPosition = Communicator.Point2.fromPoint3(this._viewer.view.projectPoint(this._position));
            this._textShape.setPosition(updatedPosition);
            const renderer = this._viewer.markupManager.getRenderer();
            renderer.drawTextBox(this._textShape);
        }
    }
    PG_Viewing_measurement.CustomMarkupItem = CustomMarkupItem;
            const item = new CustomMarkupItem(this._viewer, position, text);
            this._viewer.markupManager.registerMarkup(item);

Measure operator

In the following sample operator, we select a node, and fetch its subentity properties. In this case, we use the markup item above to add a text box with the length of an edge, or radius of a cylinder.

    class CustomMeasureOperator {
        constructor(viewer) {
            this._viewer = viewer;
        }
        onMouseDown(event) {
            event.setHandled(true);
            const position = event.getPosition();
            this._viewer.view
                .pickFromPoint(position, new Communicator.PickConfig(Communicator.SelectionMask.Line))
                .then((selection) => {
                this._addMeasurement(selection);
            });
        }
        async _addMeasurement(selection) {
            const faceEntity = selection.getFaceEntity();
            const lineEntity = selection.getLineEntity();
            const nodeId = selection.getNodeId();
            const position = selection.getPosition();
            if (nodeId === null || position === null) {
                return;
            }
            const unitMultiplier = this._viewer.model.getNodeUnitMultiplier(nodeId);
            if (faceEntity !== null) {
                const property = await this._viewer.model.getFaceProperty(nodeId, faceEntity.getCadFaceIndex());
                this._addFaceMeasurement(property, position, unitMultiplier);
            }
            else if (lineEntity !== null) {
                const property = await this._viewer.model.getEdgeProperty(nodeId, lineEntity.getLineId());
                this._addLineMeasurement(property, position, unitMultiplier);
            }
        }
        _addFaceMeasurement(property, position, unitMultiplier) {
            if (property instanceof Communicator.SubentityProperties.CylinderElement) {
                const text = `Radius: ${Communicator.Util.formatWithUnit(property.radius / unitMultiplier, unitMultiplier)}`;
                this._createMarkup(position, text);
            }
        }
        _addLineMeasurement(property, position, unitMultiplier) {
            if (property instanceof Communicator.SubentityProperties.LineElement) {
                const text = `Length: ${Communicator.Util.formatWithUnit(property.length / unitMultiplier, unitMultiplier)}`;
                this._createMarkup(position, text);
            }
        }
        _createMarkup(position, text) {
            //! [add_markup_item]
            const item = new CustomMarkupItem(this._viewer, position, text);
            this._viewer.markupManager.registerMarkup(item);
            //! [add_markup_item]
        }
    }
    PG_Viewing_measurement.CustomMeasureOperator = CustomMeasureOperator;

Callbacks

The following callbacks are used to detect when measurement values are created and deleted, or modified.

  • measurementBegin

  • measurementCreated

  • measurementDeleted

  • measurementHidden

  • measurementLoaded

  • measurementShown

  • measurementValueSet