Cross-section

What is it?

The Cross-section tool allows you to examine cross-sections of 3D mesh and point cloud data. A cross-section is the thin slice of the data that you get when you cut straight through a 3D dataset along a rectangular plane. The slice contains the part of the 3D data that interacts with the cross-section plane.

HxDR StartApp shows the slicing plane and the cross-section on the map and in the cross-section panel, an overlay panel at the bottom of the map.

You can control the cross-section by moving and rotating the slicing shape on the 3D map, you can zoom in and out on the cross-section panel to change the size of the cross-section view, and you can pan on the cross-section panel to move the cross-section on its own plane.

The cross-section panel also features an orthogonal measurement tool that allows you to measure distances between points of your choosing on the cross-section.

An example of a cross-section shown on the map and in the cross-section panel overlaid on the map.
An example of a cross-section shown on the map and in the cross-section panel overlaid on the map.

How to create a cross-section from the UI

To create a cross-section of a 3D structure:

  1. Add the 3D data set to your map, and pan and rotate the map until you have the 3D structure in full view. Choose an angle that's convenient for the cross-section you want to create.
  2. Slide open the Cross-section drawer by clicking the Cross-section icon in the left navigation bar.
  3. Click on the data once to choose the center of your cross-section.
  4. Drag the + cursor outwards from the center to define the height and width of your cross-section plane.
  5. Once your cross-section plane is large enough, click again.
    HxDR StartApp calculates the cross-section, and displays it in the cross-section panel at the bottom of your map.

Manipulate the cross-section

Rotating the cross-section To rotate the cross-section on its central vertical axis, click-and-drag the rotate arrow at the upper right corner of the cross-section on the map.

Moving the cross-section plane horizontally To move the cross-section plane horizontally, click-and-drag the central arrows on the top border of the cross-section plane.

Fitting the map To fit the map on the cross-section, click the Fit on the plane icon in the cross-section panel.

Re-size your cross-section To make your cross-section larger or smaller, drag the Zoom slider in the cross-section panel or scroll/pinch on the cross-section panel.

Move the cross-section on its plane To move the cross-section up, down, or to the side, pan the view in the cross-section panel.

To start over, and create a new cross-section from scratch, click the Replace the plane icon in the cross-section panel.

cross-section with move and rotate handles and a measurement
cross-section with move and rotate handles and a measurement

Measure distances in a cross-section

Once the cross-section panel shows your cross-section, you can use the orthogonal measurement tool to measure distances and angles.

The +-cursor in the cross-section panel shows the start position of the orthogonal measurement tool.

To start measuring:

  1. Click once in the cross-section panel to set the start position of your measurement.
  2. Move the cursor to the second and final position.
  3. Click at the final measurement position. HxDR StartApp shows the measurement results on the cross-section panel and on the map.

To delete the measurement, click the Delete the current measurement icon on the cross-section panel.

How to create a cross-section from code

To create a cross-section, you must first create div elements on which LuciadRIA can render the cross-section. These div elements are then used to create a CrossSectionView. Once you have this view, you can set a CrossSectionController on the map to place and move the cross-section.

const CrossSectionOverlay = ({mainMap}: {mainMap: Map}) => {
  const sliceMapNodeRef = useRef<HTMLDivElement>(null);
  const cartesianMapNodeRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    //create the view using the main map and overlapping divs for the cross-section rendering
    const newView = new CrossSectionView(
      mainMap,
      sliceMapNodeRef.current,
      cartesianMapNodeRef.current,
      mainMap.layerTree.findLayerGroupById(ANNOTATION_LAYER_GROUP_ID)
    );
    
    const handle = newView.on(CARTESIAN_MAP_CREATED_EVENT, (map: Map) => {
      //this controller is used to place and move the slice on the main map
      mainMap.controller = new CrossSectionController(mainMap, newView);
      handle.remove();
    });

    //clean up when the overlay isn't rendered anymore
    return () => {
      newView.destroy();
      mainMap.controller = null;
    };
  }, []);

  return (
    <>
      {/*div on which the actual cross-section will be rendered*/}
      <div
        ref={sliceMapNodeRef}
        style={{
          position: 'absolute',
          height: '35%',
          bottom: '37px',
          left: '50%',
          width: '50%',
          zIndex: '5',
          backgroundColor: 'black',
          transform: 'translate(-50%, 0)',
        }}
      />
      {/*div on which the measurements will be rendered and that can be interacted with*/}
      <div
        ref={cartesianMapNodeRef}
        style={{
          position: 'absolute',
          height: '35%',
          bottom: '37px',
          left: '50%',
          width: '50%',
          zIndex: '10',
          pointerEvents: 'auto',
          transform: 'translate(-50%, 0)',
        }}
      />
    </>
  );
};

You can also programmatically modify the cross-section:

const targetWidth = 100;
const targetHeight = 50;

//constrain the target width and height to the min/max cross-section size and aspect ratio.
const [viewWidth, viewHeight] = crossSectionView.cartesianMap.viewSize;
const aspectRatio = viewWidth / viewHeight;
const minWidth = viewWidth / (MAX_CARTESIAN_MAP_SCALE * (DPI / INCH_TO_CM) * CM_TO_METER);
const maxWidth = viewWidth / (MIN_CARTESIAN_MAP_SCALE * (DPI / INCH_TO_CM) * CM_TO_METER);
const width = clamp(
    Math.max(targetWidth, targetHeight * aspectRatio),
    minWidth,
    maxWidth
);
const height = width / aspectRatio;

//update the plane's dimensions and the slicing maps
crossSectionView.plane.updateDimensions(width, height);
crossSectionView.updateSliceMaps();