Last updated

Seismic Horizon

This tutorial demonstrates how to display an overlay layer — like a horizon — on top of a seismic display. A seismic horizon refers to a surface where there is marked change in the characteristic lithology or fossil content. The horizon shape is built as a Polyline based on the trace values and depths. It is added to the widget using .addChild().

# Simple Seismic Display

Create a seismic MemoryReader and display it inside a seismic widget.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { createPipeline, createSeismicReader, createWidget } from "/src/code/Seismic/ImagesAndLayers/SeismicHorizon/common.ts";
function createScene(canvas) {
  const sampleRate = 1;
  const sampleCount = 350;
  const traceCount = 600;
  const seismicReader = createSeismicReader(sampleRate, sampleCount, traceCount);
  const pipeline = createPipeline(seismicReader);
  const widget = createWidget(pipeline);
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Overlay a Horizon on the Seismic Display

The seismic widget displays the seismic pipeline model inside of a seismic image. This seismic image is housed inside of a built-in stacked view. Users can add other views or shapes on top of this stacked view. This example shows how to display another layer, for example a horizon, on the seismic.

import { Polyline } from "@int/geotoolkit/scene/shapes/Polyline.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { buildHorizon, createPipeline, createSeismicReader, createWidget } from "/src/code/Seismic/ImagesAndLayers/SeismicHorizon/common.ts";
function createScene(canvas) {
  const sampleRate = 1;
  const sampleCount = 350;
  const traceCount = 600;
  const seismicReader = createSeismicReader(sampleRate, sampleCount, traceCount);
  const pipeline = createPipeline(seismicReader);
  const horizon = buildHorizon(traceCount);
  const horizonPolyline = new Polyline({
    "x": horizon.traces,
    "y": horizon.depths
  });
  horizonPolyline.setLineStyle({ "color": "red", "width": 4 });
  const widget = createWidget(pipeline);
  const indexOfManipulatorLayer = widget.getModel().indexOfChild(widget.getManipulatorLayer());
  widget.getModel().insertChild(indexOfManipulatorLayer, horizonPolyline);
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# The Horizon with ColorProvider

This example shows to use a colorprovider while creating the horizon shape. Click on the horizon to display the selected segment information.

import { Rect } from "@int/geotoolkit/util/Rect.ts";
import { SelectionMode } from "@int/geotoolkit/controls/tools/SelectionMode.ts";
import { Events as SelectionEvents } from "@int/geotoolkit/controls/tools/Selection.ts";
import { DefaultColorProvider } from "@int/geotoolkit/util/DefaultColorProvider.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { buildHorizon, createPipeline, createSeismicReader, createWidget } from "/src/code/Seismic/ImagesAndLayers/SeismicHorizon/common.ts";
import { Horizon } from "/src/code/Seismic/ImagesAndLayers/SeismicHorizon/horizon.ts";
function createScene(canvas, info) {
  const sampleRate = 1;
  const sampleCount = 350;
  const traceCount = 600;
  const seismicReader = createSeismicReader(sampleRate, sampleCount, traceCount);
  const pipeline = createPipeline(seismicReader);
  const horizon = buildHorizon(traceCount);
  const widget = createWidget(pipeline);
  const horizonShape = new Horizon(horizon.depths, horizon.traces, new DefaultColorProvider([60, 150], ["yellow", "red"]), 4);
  let selectedSegments = [];
  widget.getToolByName("pick").setNodeFilter((nodes) => nodes.filter((node) => node instanceof Horizon)).on(SelectionEvents.onSelectionEnd, (evt, selector, args) => {
    horizonShape.setStyle(selectedSegments, horizonShape.getDefaultStyle());
    selectedSegments = [];
    if (args.getSelection().length === 0) {
      return;
    }
    let bounds;
    if (selector.getSelectionMode() === SelectionMode.Pointer) {
      const p = args.getPlotPoint();
      bounds = new Rect(p.getX(), p.getY(), p.getX() + selector.getMouseRadius(), p.getY() + selector.getMouseRadius());
      bounds = selector.getManipulatorLayer().getSceneTransform().inverseTransform(bounds);
    }
    if (selector.getSelectionMode() === SelectionMode.RubberBand) {
      const startX = Math.min(selector.getStartPoint().getX(), selector.getEndPoint().getX());
      const startY = Math.min(selector.getStartPoint().getY(), selector.getEndPoint().getY());
      const endX = Math.max(selector.getStartPoint().getX(), selector.getEndPoint().getX());
      const endY = Math.max(selector.getStartPoint().getY(), selector.getEndPoint().getY());
      bounds = new Rect(startX, startY, endX, endY);
    }
    selectedSegments = horizonShape.hitTest(bounds);
    horizonShape.setStyle(selectedSegments, horizonShape.getDefaultStyle().setWidth(6));
    const segment = horizonShape.getSegment(selectedSegments[0]);
    if (segment) {
      info.innerHTML = "trace: " + segment.getFrom().getX() + " depth: " + segment.getFrom().getY();
    }
  });
  const indexOfManipulatorLayer = widget.getModel().indexOfChild(widget.getManipulatorLayer());
  widget.getModel().insertChild(indexOfManipulatorLayer, horizonShape);
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'), document.querySelector('[ref="info"]'));