Depth Shifting

The Depth Shifting tool is a specialized manipulator used to edit the curve depth shifting points.

# Simple Depth Shifting

This example displays all the functionalities of the Curve Depth Mapping tool. The left curve is a regular curve and the right curve is a curve with Depth Mapping.
Both curves has exactly the same Data Source instance.

The Depth Mapping toolbar buttons enable/disable the three editing modes:

  • Edit Mode - Allows dragging the selected depth-mapping marker along the track, changing related depth range transformation
  • Insert Mode - Allows inserting a depth-mapping marker into the log curve at the depth at which the click occurred on the track. While dragging the mouse along the track, a host marker will be drawn across to show the corresponding depth.
  • Delete Mode - Allows deleting the selected depth-mapping marker by clicking.

Depth Mapping tool is active at the begining but you need to add at least one shift point to start.

import { EventDispatcher } from "@int/geotoolkit/util/EventDispatcher.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { HeaderType as LogAxisVisualHeaderHeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { TrackType as WellLogTrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { Layer } from "@int/geotoolkit/scene/Layer.ts";
import { LogCurveDataSource } from "@int/geotoolkit/welllog/data/LogCurveDataSource.ts";
import { NumericalDataSeries } from "@int/geotoolkit/data/NumericalDataSeries.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { CSVWriter } from "@int/geotoolkit/data/CSVWriter.ts";
import { TextStream } from "@int/geotoolkit/util/stream/TextStream.ts";
import { DepthShiftingTool } from "@int/geotoolkit/welllog/widgets/tools/DepthShiftingTool.ts";
import { Events as EditorEvents } from "@int/geotoolkit/controls/editing/Events.ts";
import { from } from "@int/geotoolkit/selection/from.ts";
import { Events as ToolEvents } from "@int/geotoolkit/controls/tools/AbstractTool.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { HoldTitle } from "@int/geotoolkit/welllog/header/HoldTitle.ts";
import { Elements } from "@int/geotoolkit/welllog/header/AdaptiveLogCurveVisualHeader.ts";
import { Sections } from "@int/geotoolkit/welllog/header/AdaptiveLogVisualHeader.ts";
import { LasWriter } from "/src/code/WellLog/utils/lasWriter.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
import { curveData } from "/src/code/WellLog/utils/curveData.ts";
export class DepthShifting extends EventDispatcher {
  constructor(canvas) {
    super();
    this._widget = this.initializeWidget();
    this._plot = this.addWidgetToCanvas(canvas, this._widget);
    const logCurve = from(this._widget).where((node) => node instanceof LogCurve).selectFirst();
    this._depthShiftingTool = this.createDepthShiftingTool(this._widget).setHandleStyles({ "ghostlinestyle": "blue" }).setShape(logCurve);
    const curves = from(this._widget.getTrack(3)).where((node) => node instanceof LogCurve).where((curve) => curve.getParent() instanceof Layer).selectToArray();
    const synchronize = () => {
      const depths = this.getShiftedDepths();
      if (depths == null) {
        return;
      }
      for (let i = 0; i < curves.length; i++) {
        const curve = curves[i];
        const logDataSource = new LogCurveDataSource().setData({
          depths,
          values: curve.getDataSource().getValues()
        }).setName(curve.getName());
        curve.setData(logDataSource);
      }
    };
    const restore = () => {
      for (let i = 0; i < curves.length; i++) {
        const curve = curves[i];
        const originalCurve = curve.getProperty("original");
        const logDataSource = new LogCurveDataSource().setData({
          depths: originalCurve.getDataSource().getDepths(),
          values: curve.getDataSource().getValues()
        }).setName(curve.getName());
        curve.setData(logDataSource);
      }
    };
    synchronize();
    this._depthShiftingTool.on(EditorEvents.Insert, synchronize).on(EditorEvents.Delete, synchronize).on(EditorEvents.Dragging, synchronize).on(EditorEvents.DragEnd, synchronize).on(EditorEvents.Clear, restore);
  }
  dispose() {
    if (this._widget != null) {
      this._widget.dispose();
      this._widget = null;
    }
    if (this._plot != null) {
      this._plot.dispose();
      this._plot = null;
    }
  }
  customizeCurveHeader(widget) {
    const headerProvider = widget.getHeaderContainer().getHeaderProvider();
    const header = headerProvider.getHeaderProvider(LogCurve.getClassName());
    const customHeder = header.clone();
    customHeder.setElement({
      [Elements.ScaleFrom]: {
        "section": Sections.Top
      },
      [Elements.ScaleTo]: {
        "section": Sections.Top
      },
      [Elements.Line]: {
        "section": Sections.Top
      }
    });
    customHeder.setSection({
      [Sections.Top]: {
        "paddingstyle": "5px 5px 5px"
      },
      [Sections.Middle]: {
        "visible": false,
        "size": 0
      },
      [Sections.Bottom]: {
        "visible": false,
        "size": 0
      }
    });
    headerProvider.registerHeaderProvider(LogCurve.getClassName(), customHeder);
  }
  initializeWidget() {
    const widget = createWellLogWidget({
      "track": {
        "header": {
          "titlefirst": false,
          "firsttolast": true,
          "toptobottom": false,
          "holdtitle": HoldTitle.Top
        }
      }
    }).setAxisHeaderType(LogAxisVisualHeaderHeaderType.Simple);
    this.customizeCurveHeader(widget);
    widget.addTrack(WellLogTrackType.IndexTrack);
    widget.addTrack(WellLogTrackType.LinearTrack).addChild([
      this.createCurve("CALI").setName("CALI - orig").setLineStyle({ "pattern": [2, 2] }, true)
    ]);
    widget.addTrack(WellLogTrackType.AnnotationTrack).setWidth(40);
    const shiftCurves = [
      this.createCurve("RHOB").setLineStyle("#404B97"),
      this.createCurve("DLT").setLineStyle("#76EAE8"),
      this.createCurve("SP").setLineStyle("#8EE48D"),
      this.createCurve("CALI").setLineStyle("#7E5381")
    ];
    widget.addTrack(WellLogTrackType.LinearTrack).addChild(shiftCurves.map(
      (curve) => curve.setLineStyle({ "pattern": [2, 2] }, true).setOpacity(0.5)
    )).addChild(
      new Layer().addChild(shiftCurves.map(
        (curve) => curve.clone().setProperty("original", curve).setLineStyle({ "pattern": null }, true).setOpacity(1)
      ))
    );
    widget.addTrack(WellLogTrackType.IndexTrack);
    const logCurve = from(widget).where((node) => node instanceof LogCurve).selectFirst();
    widget.setDepthLimits(logCurve.getModelLimits().getTop(), logCurve.getModelLimits().getBottom());
    return widget;
  }
  getEditMode() {
    return this._depthShiftingTool != null ? this._depthShiftingTool.getMode() : null;
  }
  addWidgetToCanvas(canvas, widget) {
    const plot = new Plot({
      "canvaselement": canvas,
      "root": widget
    });
    widget.setVisibleDepthLimits(1e4, 12e3);
    widget.setHeaderHeight("auto");
    return plot;
  }
  createDepthShiftingTool(widget) {
    const manipulatorLayer = new Layer({
      id: "curves.manipulator.layer"
    });
    widget.getTrackManipulatorLayer().addChild(manipulatorLayer);
    const depthShiftingTool = new DepthShiftingTool({
      "layer": manipulatorLayer,
      "handlestyles": {
        "activelinestyle": {
          "color": "blue"
        },
        "ghostlinestyle": {
          "color": "red"
        },
        "depthlabelfillstyle": "#D8F2D7",
        "depthlabelpaddingstyle": "5px 8px 2px"
      }
    });
    const tools = widget.getTool();
    const toolTip = tools.getToolByName("tooltip");
    depthShiftingTool.on(ToolEvents.onStateChanged, (event, tool) => {
      this.notify(ToolEvents.onStateChanged, this);
      toolTip.setEnabled(tool.isActive() === false);
    });
    tools.getToolByName("cross-hair").getParentTool().add(depthShiftingTool);
    return depthShiftingTool;
  }
  createTestData(dataMnemonic, from2, step) {
    from2 = from2 || 4500;
    step = step || 10;
    const depths = [];
    const values = [];
    const curveDat = curveData[dataMnemonic];
    const amountOfPoints = curveDat.length;
    for (let i = 0; i < amountOfPoints; i++) {
      depths.push(i * step + from2);
      values.push(curveDat[i]);
    }
    return new LogData({
      "name": dataMnemonic,
      "depths": depths,
      "values": values
    });
  }
  createCurve(dataSource) {
    if (typeof dataSource === "string") {
      dataSource = this.createTestData(dataSource);
    }
    return new LogCurve(dataSource, true).setId(dataSource.getName()).setName(dataSource.getName()).setLineStyle({
      "color": KnownColors["Blue"],
      "width": 2
    });
  }
  getShiftedDepths() {
    const logCurve = this._depthShiftingTool.getShape();
    if (logCurve == null) {
      return null;
    }
    const originalDepths = logCurve.getDataSource().getDepths();
    const depthLimits = this._depthShiftingTool.getRange();
    const mapping = this._depthShiftingTool.getDepthMappings();
    return DepthShiftingTool.mapDepths(depthLimits, mapping, originalDepths);
  }
  getDataSourcesToExport() {
    const originalCurves = from(this._widget.getTrack(3)).where((node) => node instanceof LogCurve).where((curve) => curve.getParent() instanceof Layer === false).selectToArray();
    return originalCurves.map((curve) => curve.getDataSource());
  }
  getExportDataTable() {
    const depths = this.getShiftedDepths();
    if (depths == null) {
      return null;
    }
    const depthSeries = new NumericalDataSeries({
      id: "depths",
      name: "depths",
      unit: "ft",
      data: depths
    });
    const columns = [depthSeries];
    this.getDataSourcesToExport().forEach((data) => {
      const valueSeries = new NumericalDataSeries({
        id: data.getName(),
        name: data.getName(),
        unit: data.getValueUnit(),
        data: data.getValues()
      });
      columns.push(valueSeries);
    });
    return new DataTable({
      "cols": columns,
      "meta": {
        "index": 0
      }
    });
  }
  saveToLAS() {
    const table = this.getExportDataTable();
    if (table == null) {
      return;
    }
    new LasWriter().save(table, "example.las");
  }
  exportToCSV() {
    const table = this.getExportDataTable();
    if (table == null) {
      return;
    }
    new CSVWriter({
      "stream": new TextStream({
        "filename": "csvfile.csv",
        "type": "text/csv",
        "save": true
      })
    }).writeTable(table, {
      "includeheaders": true
    }).close();
  }
  setMode(mode) {
    this._depthShiftingTool.setMode(mode);
    return this;
  }
  setEnable(enable) {
    this._depthShiftingTool.setEnabled(enable);
    if (enable) {
      const logCurve = from(this._widget).where((node) => node instanceof LogCurve).selectFirst();
      this._depthShiftingTool.setShape(logCurve);
    } else {
      this._depthShiftingTool.setShape(null);
      this._depthShiftingTool.clearDepthMapping();
    }
    return this;
  }
}
function createScene(canvas) {
  return new DepthShifting(canvas);
}
export { createScene };

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

# Advanced Depth Shifting

Depth Mapping tool is activated at second LogTrack.