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"]'));