This tutorial demonstrates how to:
Parse a local LAS3.0 (or LAS2.0) file, then put its sections data to DataTable-s;
Display the sections data read as DataTableView-s;
Write the tables' data back to LAS3.0 (or LAS2.0) file. Note that when a LAS3.0 file previously opened is written back as LAS2.0 file then some data sections are going to be lost due to LAS2.0-format limitations.
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { HttpClient } from "@int/geotoolkit/http/HttpClient.ts";
import { LineReader } from "@int/geotoolkit/util/stream/LineReader.ts";
import { BrowserFileStream } from "@int/geotoolkit/util/stream/BrowserFileStream.ts";
import { Las20Stream } from "@int/geotoolkit/las/Las20Stream.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { DataSeries } from "@int/geotoolkit/data/DataSeries.ts";
import { NumericalDataSeries } from "@int/geotoolkit/data/NumericalDataSeries.ts";
import { LasSectionGroup } from "@int/geotoolkit/las/LasSectionGroup.ts";
import { Las30Writer } from "@int/geotoolkit/las/Las30Writer.ts";
import { Las20Writer } from "@int/geotoolkit/las/Las20Writer.ts";
import { StringStream } from "@int/geotoolkit/util/stream/StringStream.ts";
import { LasWellSection } from "@int/geotoolkit/las/LasWellSection.ts";
import { LasVersionSection } from "@int/geotoolkit/las/LasVersionSection.ts";
import { log } from "@int/geotoolkit/base.js";
import { LasParser } from "@int/geotoolkit/las/LasParser.ts";
import { TableView } from "@int/geotoolkit/widgets/TableView.ts";
import { DataTableAdapter } from "@int/geotoolkit/widgets/data/DataTableAdapter.ts";
import { LasParameterSection } from "@int/geotoolkit/las/LasParameterSection.ts";
import { LasDataSection } from "@int/geotoolkit/las/LasDataSection.ts";
import { Las30Consts } from "@int/geotoolkit/las/Las30Consts.ts";
import { ParserFactory } from "@int/geotoolkit/welllog/data/las/ParserFactory.ts";
const http = HttpClient.getInstance().getHttp();
let delimiterName, delimiterDescription;
let dataTables = [];
let plots = [];
let tableParentDivs = [];
let asciiSectionGroupName = null;
function emptyParameterSection(parameterSection) {
return !parameterSection || !parameterSection.getData() || parameterSection.getData().length < 1;
}
function tableToParameterSection(table, parameterSection, uniqueMnemonics) {
const nRows = table.getNumberOfRows();
if (nRows < 1) {
log("Table " + table.getName() + ": NO rows found");
return;
}
if (table.getRow(0).length !== 4) {
log("Table " + table.getName() + ": row length == " + table.getRow(0).length + " vs. expected 4");
return;
}
const meta = table.getMetaData();
const comments = meta && meta["comments"] ? meta["comments"] : null;
if (comments && !comments.empty()) {
for (let i = comments.getMinPosition(); i <= comments.getMaxPosition(); ++i) {
const strComment = comments.getComment(i);
if (strComment != null) {
parameterSection.addComment(i, strComment);
}
}
}
for (let i = 0; i < nRows; ++i) {
const row = table.getRow(i);
if (row.length === 4) {
const mnemonic = row[0];
parameterSection.setParameter(
mnemonic,
row[1],
row[2],
row[3],
uniqueMnemonics != null && uniqueMnemonics.indexOf(mnemonic) > -1 ? false : true
);
}
}
}
function tableToDataSection(dataTable, dataSection) {
const sectionData = [];
for (let i = 0; i < dataTable.getNumberOfColumns(); i++) {
const column = dataTable.getColumn(i);
const columnData = column.toArray(true);
sectionData.push(columnData);
}
dataSection.setData(sectionData);
}
function onFileOpen(evt, canvasesParent, fileInfo) {
evt.stopPropagation();
evt.preventDefault();
const files = evt.target.files;
return handleFileSelect(files, canvasesParent, fileInfo);
}
function isAsciiSectionName(name) {
name = name.toLowerCase();
if (LasParser.isDataMainSectionName(name) || name === "las2" || name === "main section" || name === "log" || name.startsWith("curve_data") || name.startsWith("log_data")) {
return true;
}
return false;
}
function getAsciiSectionGroup(sections) {
for (let i = 0; i < sections.length; ++i) {
if (isAsciiSectionName(sections[i].getName())) {
return sections[i];
}
}
return null;
}
function createLAS20Writer() {
const res = dataTables.filter((t) => isAsciiSectionName(t.getName()));
if (!res || res.length < 1) {
return null;
}
const table = res[0];
const metaData = table.getMetaData();
const indexDataSeries = metaData["index"] ? table.getColumnByName(metaData["index"]) : table.getColumn(0);
const lasWriter = new Las20Writer(indexDataSeries);
return lasWriter;
}
function createLAS30Writer() {
const lasWriter = new Las30Writer();
lasWriter.setDataValuesDelimiter(
delimiterName,
delimiterDescription
);
return lasWriter;
}
function dataToLASWriter(lasWriterVersion) {
const lasWriter = lasWriterVersion === "2.0" ? createLAS20Writer() : createLAS30Writer();
if (!lasWriter) {
return null;
}
let lasDataVersion;
let write30dataTo20file;
const sectionGroupsInfos = {};
for (let i = 0; i < dataTables.length; ++i) {
const dataTable = dataTables[i];
const name = dataTable.getName().trim().toUpperCase();
if (LasParser.isVersionSectionName(name)) {
const versionSection = new LasVersionSection();
tableToParameterSection(dataTable, versionSection);
lasDataVersion = versionSection.getParameter(Las30Consts.MNEMONIC_VERSION).getValue();
write30dataTo20file = lasWriterVersion === "2.0" && lasDataVersion === "3.0";
if (lasDataVersion !== lasWriterVersion) {
continue;
}
lasWriter.setVersionSection(versionSection);
} else if (LasParser.isWellSectionName(name)) {
const wellSection = new LasWellSection();
tableToParameterSection(dataTable, wellSection, [
Las30Consts.MNEMONIC_START,
Las30Consts.MNEMONIC_STOP,
Las30Consts.MNEMONIC_STEP,
Las30Consts.MNEMONIC_NULL
]);
lasWriter.setWellSection(wellSection);
} else {
const sectionGroupName = dataTable.getMetaData()["sectionGroupName"];
if (write30dataTo20file && sectionGroupName !== asciiSectionGroupName) {
continue;
}
if (name.indexOf("ASCII") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("DATA") !== -1 || name.split("|").length > 1 && name.split("|")[1].indexOf("DEFINITION") !== -1) {
const dataSection = new LasDataSection({
"name": write30dataTo20file ? "ASCII" : dataTable.getName()
});
tableToDataSection(dataTable, dataSection);
if (sectionGroupsInfos[sectionGroupName] === void 0) {
sectionGroupsInfos[sectionGroupName] = {};
}
sectionGroupsInfos[sectionGroupName]["data"] = dataSection;
if (lasWriterVersion === "2.0") {
break;
}
} else if (name.indexOf("PARAMETER") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("PARAMETER") !== -1) {
const parameterSection = new LasParameterSection({
"name": write30dataTo20file ? "PARAMETER" : dataTable.getName()
});
tableToParameterSection(dataTable, parameterSection);
if (sectionGroupsInfos[sectionGroupName] === void 0) {
sectionGroupsInfos[sectionGroupName] = {};
}
sectionGroupsInfos[sectionGroupName]["parameter"] = parameterSection;
} else if (name.indexOf("CURVE") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("DEFINITION") !== -1) {
const parameterSection = new LasParameterSection({
"name": write30dataTo20file ? "CURVE" : dataTable.getName()
});
tableToParameterSection(dataTable, parameterSection);
if (sectionGroupsInfos[sectionGroupName] === void 0) {
sectionGroupsInfos[sectionGroupName] = {};
}
sectionGroupsInfos[sectionGroupName]["definition"] = parameterSection;
} else {
log("Unrecognized Section Type: " + dataTable.getName());
}
}
}
for (const name in sectionGroupsInfos) {
if (sectionGroupsInfos.hasOwnProperty(name)) {
const info = sectionGroupsInfos[name];
const sectionGroup = new LasSectionGroup(
name,
info["parameter"],
info["definition"],
info["data"]
);
if (lasWriter instanceof Las30Writer) {
lasWriter.setDataSectionGroup(sectionGroup);
} else if (lasWriter instanceof Las20Writer) {
lasWriter.setDataSectionGroup(sectionGroup);
}
}
}
return lasWriter;
}
function onFileSave(lasWriterVersion) {
if (!dataTables || dataTables.length === 0) {
log("No data loaded to save");
return;
}
if (lasWriterVersion !== "2.0" && lasWriterVersion !== "3.0") {
log("Unsupported LAS-version: " + lasWriterVersion);
return;
}
const lasWriter = dataToLASWriter(lasWriterVersion);
if (!lasWriter) {
log("Writer NOT created for LAS-version: " + lasWriterVersion);
return;
}
const stream = new StringStream().setSaveOptions({
"type": "text/plain",
"popupblockedmessage": "Popup-blocker blocked export window."
});
lasWriter.save(stream);
stream.close().save("saved_as_" + lasWriterVersion + ".las", true);
}
function onFileDrop(evt, canvasesParent, fileInfo) {
evt.stopPropagation();
evt.preventDefault();
const files = evt.dataTransfer.files;
evt.dataTransfer.dropEffect = "copy";
return handleFileSelect(files, canvasesParent, fileInfo);
}
function loadFile(fileName, canvasesParent, fileInfo) {
http.get(fileName, {
"responsetype": "blob"
}).then((response) => {
handleFileSelect([new File([response.data], fileName)], canvasesParent, fileInfo);
});
}
function getParameterSectionByName(sections, name) {
for (let i = 0; i < sections.length; ++i) {
if (sections[i].getName().toLowerCase().indexOf(name.toLowerCase()) >= 0) {
return sections[i];
}
}
return null;
}
function loadWellOrVersionSectionTable(section) {
const name = section.getName().trim().toUpperCase();
const table = new DataTable({
"name": name
});
const parameters = section.getData();
const mnemonics = [];
const units = [];
const values = [];
const descriptions = [];
for (let i = 0; i < parameters.length; ++i) {
const parameter = parameters[i];
mnemonics.push(parameter.getMnemonic());
units.push(parameter.getUnit());
values.push(parameter.getValue());
descriptions.push(parameter.getDescription());
}
table.addColumn(new DataSeries({
"id": "mnemonic",
"name": "mnemonic",
"data": mnemonics
}));
table.addColumn(new DataSeries({
"id": "unit",
"name": "unit",
"data": units
}));
table.addColumn(new DataSeries({
"id": "value",
"name": "value",
"data": values
}));
table.addColumn(new DataSeries({
"id": "description",
"name": "description",
"data": descriptions
}));
return table;
}
function loadParameterSectionTable(parameterSection) {
const table = new DataTable({ "name": parameterSection.getName() });
const parameters = parameterSection.getData();
const mnemonics = [];
const units = [];
const values = [];
const descriptions = [];
for (let i = 0; i < parameters.length; ++i) {
const parameter = parameters[i];
mnemonics.push(parameter.getMnemonic());
units.push(parameter.getUnit());
values.push(parameter.getValue());
descriptions.push(parameter.getDescription());
}
table.addColumn(new DataSeries({
"id": "mnemonic",
"name": "mnemonic",
"data": mnemonics
}));
table.addColumn(new DataSeries({
"id": "unit",
"name": "unit",
"data": units
}));
table.addColumn(new DataSeries({
"id": "value",
"name": "value",
"data": values
}));
table.addColumn(new DataSeries({
"id": "description",
"name": "description",
"data": descriptions
}));
return table;
}
function loadDataSectionTable(sectionGroup) {
const dataSection = sectionGroup.getSections()["data"];
const table = new DataTable({ "name": dataSection.getName() });
const curveNames = sectionGroup.getCurveMnemonics();
for (let i = 0; i < curveNames.length; ++i) {
const data = sectionGroup.getCurveData(i);
const info = sectionGroup.getCurveInfo(i);
let curve;
if (sectionGroup.isCurveNumeric(i)) {
curve = new NumericalDataSeries({
"name": info.getMnemonic(),
"data": data,
"id": info.getMnemonic(),
"unit": info.getUnit()
});
} else {
const strData = [];
data.forEach((e) => {
strData.push(e.toString());
});
curve = new DataSeries({
"name": info.getMnemonic(),
"data": strData,
"id": info.getMnemonic(),
"unit": info.getUnit()
});
}
table.addColumn(curve);
}
return table;
}
function legacyParse(file, resolve, reject) {
const reader = new FileReader();
reader.onload = function(e) {
const parser = ParserFactory.getParser(e.target.result, false);
if (parser == null) {
reject("unknown file format");
return;
}
parser.parse(e.target.result);
const sections = parser.getSections();
const versionSection = getParameterSectionByName(sections, "VERSION");
if (versionSection == null) {
reject("VERSION data NOT found");
return;
}
const wellSection = getParameterSectionByName(sections, "WELL");
if (wellSection == null) {
reject("WELL data not found");
return;
}
const sectionGroups = parser.getSectionGroups();
const asciiSectionGroup = getAsciiSectionGroup(sectionGroups);
if (asciiSectionGroup == null) {
asciiSectionGroupName = null;
reject("No ASCII-section data is found");
return;
}
asciiSectionGroupName = asciiSectionGroup.getName();
for (let is = 0; is < sections.length; ++is) {
const tableS = loadWellOrVersionSectionTable(sections[is]);
tableS.setMetaData({ "comments": sections[is].getComments() });
resolve(tableS);
dataTables.push(tableS);
}
for (let isg = 0; isg < sectionGroups.length; ++isg) {
const sectionGroup = sectionGroups[isg];
const parameters = sectionGroup.getSections()["parameters"];
if (!emptyParameterSection(parameters)) {
const tablePars = loadParameterSectionTable(parameters);
tablePars.setMetaData({
"sectionGroupName": sectionGroup.getName(),
"comments": parameters.getComments()
});
resolve(tablePars);
dataTables.push(tablePars);
}
const definition = sectionGroup.getSections()["curves"];
if (!emptyParameterSection(definition)) {
const tableDefs = loadParameterSectionTable(definition);
tableDefs.setMetaData({
"sectionGroupName": sectionGroup.getName(),
"comments": definition.getComments()
});
resolve(tableDefs);
dataTables.push(tableDefs);
}
const tableData = loadDataSectionTable(sectionGroup);
tableData.setMetaData({
"sectionGroupName": sectionGroup.getName()
});
resolve(tableData);
dataTables.push(tableData);
}
const parameterDLM = versionSection.getParameter(Las30Consts.MNEMONIC_DATA_VALUES_DELIMITER);
if (parameterDLM != null) {
const v = parameterDLM.getValue();
delimiterName = v != null && v.length > 0 ? v : Las30Consts.DATA_VALUES_DELIMITER_NAME_SPACE;
delimiterDescription = parameterDLM.getDescription();
} else {
delimiterName = Las30Consts.DATA_VALUES_DELIMITER_NAME_SPACE;
}
};
reader.readAsText(file);
}
function visualizeTables(dataTables2, canvasesParent) {
for (let i = 0; i < dataTables2.length; ++i) {
const dataTable = dataTables2[i];
const tableParentDiv = document.createElement("div");
tableParentDiv.style.height = "200px";
tableParentDiv.style.color = "red";
const tableName = document.createElement("textarea");
tableName.value = dataTable.getName();
tableName.style.backgroundColor = "lightgray";
tableName.style.borderRadius = "6px";
tableName.style.borderWidth = "1px";
tableName.style.position = "absolute";
tableName.style.height = "20px";
tableName.style.width = "100%";
tableParentDiv.appendChild(tableName);
const tableCanvas = document.createElement("canvas");
tableCanvas.style.height = "180px";
tableCanvas.style.width = "100%";
tableCanvas.style.backgroundColor = "yellow";
tableParentDiv.appendChild(tableCanvas);
canvasesParent.appendChild(tableParentDiv);
const tableAdapter = new DataTableAdapter({
"datatable": dataTable
});
const tableViewWidget = new TableView({
"border": {
"color": "lightgray",
"pixelsnapmode": true
},
"fitborder": true,
"horizontalscroll": "floating",
"verticalscroll": "floating"
}).setData(tableAdapter);
plots.push(new Plot({
"canvaselement": tableCanvas,
"root": tableViewWidget
}));
tableParentDivs.push(tableParentDiv);
tableViewWidget.fitToWidth(false);
}
}
function clear(canvasesParent) {
dataTables.forEach((dataTables2) => {
dataTables2.dispose();
});
dataTables = [];
plots.forEach((plot) => {
plot.dispose(true);
});
plots = [];
if (canvasesParent != null) {
for (let i = 0; i < tableParentDivs.length; ++i) {
canvasesParent.removeChild(tableParentDivs[i]);
}
}
tableParentDivs = [];
}
function handleFileSelect(files, canvasesParent, fileInfo) {
let output = "";
if (files.length > 0) {
clear(canvasesParent);
fileInfo.text = "";
const file = files[0];
const lineReader = new LineReader({
"stream": new BrowserFileStream({
"file": file
})
});
new Promise((resolve, reject) => {
Las20Stream.isLAS20(lineReader).then((result) => {
legacyParse(file, resolve, reject);
output = file.name;
output += result["isLAS20"] ? " [LAS20]" : " [LAS30]";
fileInfo.text = output;
}).catch((result) => reject(result));
}).then(() => {
visualizeTables(dataTables, canvasesParent);
});
}
}
export { clear, loadFile, onFileDrop, onFileOpen, onFileSave };
createScene();