From 2f54e6508e7b1bb8dd177e38071e64a5db01d6ac Mon Sep 17 00:00:00 2001 From: nilscb Date: Thu, 19 Jan 2023 16:03:56 +0100 Subject: [PATCH] =?UTF-8?q?[NGRM]=20-=20Webviz=20map=20component=20-=20Z?= =?UTF-8?q?=20values=20should=20be=20defined=20geological=E2=80=A6=20(#139?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [NGRM] - Webviz map component - Z values should be defined geologicaly #1150 * Fixed spelling error. * Changed to tsdoc format * Typecheck. Forgot some properties. * Another embarrasing spelling error. * Merge conflict * Code commit fix. Do inversion before spline refine and not vice versa. --- .../SubsurfaceViewer/layers/axes/axesLayer.ts | 36 +++-- .../layers/grid3d/grid3dLayer.ts | 63 +++++--- .../layers/layersDefaultProps.ts | 5 +- .../SubsurfaceViewer/layers/map/mapLayer.ts | 144 +++++++++++------- .../layers/wells/utils/spline.ts | 29 ++++ .../layers/wells/wellsLayer.ts | 16 +- 6 files changed, 202 insertions(+), 91 deletions(-) diff --git a/react/src/lib/components/SubsurfaceViewer/layers/axes/axesLayer.ts b/react/src/lib/components/SubsurfaceViewer/layers/axes/axesLayer.ts index b4a974038..cfb936b04 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/axes/axesLayer.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/axes/axesLayer.ts @@ -11,6 +11,7 @@ import BoxLayer from "./boxLayer"; import { Position3D, ExtendedLayerProps } from "../utils/layerTools"; import { layersDefaultProps } from "../layersDefaultProps"; import { TextLayer } from "@deck.gl/layers/typed"; +import { cloneDeep } from "lodash"; export interface AxesLayerProps extends ExtendedLayerProps { bounds: [number, number, number, number, number, number]; @@ -18,6 +19,10 @@ export interface AxesLayerProps extends ExtendedLayerProps { labelFontSize?: number; fontFamily?: string; axisColor?: Color; + /** If true means that input z values are interpreted as depths. + * For example depth of z = 1000 corresponds to -1000 on the z axis. Default false. + */ + isZDepth: boolean; } type TextLayerData = { @@ -29,14 +34,20 @@ type TextLayerData = { export default class AxesLayer extends CompositeLayer> { initializeState(): void { - const box_lines = GetBoxLines(this.props.bounds); + const bounds = cloneDeep(this.props.bounds); + if (this.props.isZDepth) { + bounds[2] *= -1; + bounds[5] *= -1; + } + + const box_lines = GetBoxLines(bounds); const is_orthographic = this.context.viewport.constructor === OrthographicViewport; const [tick_lines, tick_labels] = GetTickLines( is_orthographic, - this.props.bounds, + bounds, this.context.viewport ); @@ -44,7 +55,7 @@ export default class AxesLayer extends CompositeLayer> { is_orthographic, tick_lines, tick_labels, - this.props.bounds, + bounds, this.props.labelFontSize ); @@ -71,11 +82,17 @@ export default class AxesLayer extends CompositeLayer> { const is_orthographic = this.context.viewport.constructor === OrthographicViewport; - const box_lines = GetBoxLines(this.props.bounds); + const bounds = cloneDeep(this.props.bounds); + if (this.props.isZDepth) { + bounds[2] *= -1; + bounds[5] *= -1; + } + + const box_lines = GetBoxLines(bounds); const [tick_lines, tick_labels] = GetTickLines( is_orthographic, - this.props.bounds, + bounds, this.context.viewport ); @@ -83,7 +100,7 @@ export default class AxesLayer extends CompositeLayer> { is_orthographic, tick_lines, tick_labels, - this.props.bounds, + bounds, this.props.labelFontSize ); @@ -214,11 +231,12 @@ function maketextLayerData( const z_min = bounds[2]; const z_max = bounds[5]; - const dx = x_max - x_min; - const dy = y_max - y_min; - const dz = z_max - z_min; + const dx = Math.abs(x_max - x_min); + const dy = Math.abs(y_max - y_min); + const dz = Math.abs(z_max - z_min); const offset = ((dx + dy + dz) / 3.0) * 0.1; + const data = [ { label: "X", diff --git a/react/src/lib/components/SubsurfaceViewer/layers/grid3d/grid3dLayer.ts b/react/src/lib/components/SubsurfaceViewer/layers/grid3d/grid3dLayer.ts index de9bbcf8e..51bd32a65 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/grid3d/grid3dLayer.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/grid3d/grid3dLayer.ts @@ -36,6 +36,12 @@ function GetBBox( return [xmin, ymin, zmin, xmax, ymax, zmax]; } +function FlipZ(points: number[]): void { + for (let i = 0; i < points.length / 3; i++) { + points[3 * i + 2] *= -1; + } +} + async function load_data( pointsUrl: string, polysUrl: string, @@ -57,38 +63,49 @@ export interface Grid3DLayerProps extends ExtendedLayerProps { polysUrl: string; propertiesUrl: string; - // Name of color map. E.g "PORO" + /** Name of color map. E.g "PORO" + */ colorMapName: string; - // Use color map in this range. + /** Use color map in this range. + */ colorMapRange?: [number, number]; - // Clamp colormap to this color at ends. - // Given as array of three values (r,g,b) e.g: [255, 0, 0] - // If not set or set to true, it will clamp to color map min and max values. - // If set to false the clamp color will be completely transparent. + /** Clamp colormap to this color at ends. + * Given as array of three values (r,g,b) e.g: [255, 0, 0] + * If not set or set to true, it will clamp to color map min and max values. + * If set to false the clamp color will be completely transparent. + */ colorMapClampColor: Color | undefined | boolean; - // Optional function property. - // If defined this function will override the color map. - // Takes a value in the range [0,1] and returns a color. - // E.g. (x) => [x * 255, x * 255, x * 255] + /** Optional function property. + * If defined this function will override the color map. + * Takes a value in the range [0,1] and returns a color. + * E.g. (x) => [x * 255, x * 255, x * 255] + */ colorMapFunction?: colorMapFunctionType | false; - // Surface material properties. - // material: true = default material, coloring depends on surface orientation and lighting. - // false = no material, coloring is independent on surface orientation and lighting. - // or full spec: - // material: { - // ambient: 0.35, - // diffuse: 0.6, - // shininess: 32, - // specularColor: [255, 255, 255], - // } + /** Surface material properties. + * material: true = default material, coloring depends on surface orientation and lighting. + * false = no material, coloring is independent on surface orientation and lighting. + * or full spec: + * material: { + * ambient: 0.35, + * diffuse: 0.6, + * shininess: 32, + * specularColor: [255, 255, 255], + * } + */ material: Material; - // Enable/disable depth testing when rendering layer. Default true. + /** Enable/disable depth testing when rendering layer. Default true. + */ depthTest: boolean; + + /** If true means that input z values are interpreted as depths. + * For example depth of z = 1000 corresponds to -1000 on the z axis. Default true. + */ + isZDepth: boolean; } export default class Grid3DLayer extends CompositeLayer< @@ -102,6 +119,10 @@ export default class Grid3DLayer extends CompositeLayer< ); p.then(([points, polys, properties]) => { + if (!this.props.isZDepth) { + FlipZ(points); + } + const bbox = GetBBox(points); // Using inline web worker for calculating the triangle mesh from diff --git a/react/src/lib/components/SubsurfaceViewer/layers/layersDefaultProps.ts b/react/src/lib/components/SubsurfaceViewer/layers/layersDefaultProps.ts index 5fd1ca969..fb628f560 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/layersDefaultProps.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/layersDefaultProps.ts @@ -70,7 +70,7 @@ export const layersDefaultProps: Record = { outline: true, logRadius: 10, logCurves: true, - refine: true, + refine: false, visible: true, wellNameVisible: false, wellNameAtTop: false, @@ -78,6 +78,7 @@ export const layersDefaultProps: Record = { wellNameColor: [0, 0, 0, 255], selectedWell: "@@#editedData.selectedWells", // used to get data from deckgl layer depthTest: true, + isZDepth: true, }, FaultPolygonsLayer: { "@@type": "FaultPolygonsLayer", @@ -103,6 +104,7 @@ export const layersDefaultProps: Record = { name: "Axes", id: "axes-layer", visible: true, + isZDepth: false, }, Axes2DLayer: { "@@type": "Axes2DLayer", @@ -157,5 +159,6 @@ export const layersDefaultProps: Record = { colorMapName: "", propertyValueRange: [0.0, 1.0], depthTest: true, + isZDepth: true, }, }; diff --git a/react/src/lib/components/SubsurfaceViewer/layers/map/mapLayer.ts b/react/src/lib/components/SubsurfaceViewer/layers/map/mapLayer.ts index 9ab14288a..b98686782 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/map/mapLayer.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/map/mapLayer.ts @@ -9,19 +9,24 @@ import { Matrix4 } from "math.gl"; // These two types both describes the mesh' extent in the horizontal plane. type Frame = { - // mesh origin + /** mesh origin + */ origin: [number, number]; - // cells size in each direction. + /** cells size in each direction. + */ increment: [number, number]; - // no cells in each direction. + /** no cells in each direction. + */ count: [number, number]; - // Rotates map counterclockwise in degrees around 'rotPoint' specified below. + /** Rotates map counterclockwise in degrees around 'rotPoint' specified below. + */ rotDeg?: number; - // Point to rotate around using 'rotDeg'. Defaults to mesh origin. + /** Point to rotate around using 'rotDeg'. Defaults to mesh origin. + */ rotPoint?: [number, number]; }; @@ -35,7 +40,8 @@ export type Params = { async function load_mesh_and_properties( meshUrl: string, - propertiesUrl: string + propertiesUrl: string, + isZDepth: boolean ) { // Keep //const t0 = performance.now(); @@ -128,6 +134,12 @@ async function load_mesh_and_properties( } } + if (!isZDepth) { + for (let i = 0; i < meshData.length; i++) { + meshData[i] *= -1; + } + } + //const t1 = performance.now(); // Keep this. //console.log(`Task loading took ${(t1 - t0) * 0.001} seconds.`); @@ -139,80 +151,98 @@ export interface MapLayerProps extends ExtendedLayerProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any setReportedBoundingBox?: any; - // Url to the height (z values) mesh. + /** Url to the height (z values) mesh. + */ meshUrl: string; - // Horizontal extent of the terrain mesh. Format: - // { - // origin: [number, number]; // mesh origin in x, y - // increment: [number, number]; // cell size dx, dy - // count: [number, number]; // number of cells in both directions. - // } + /** Horizontal extent of the terrain mesh. Format: + { + origin: [number, number]; // mesh origin in x, y + increment: [number, number]; // cell size dx, dy + count: [number, number]; // number of cells in both directions. + } + */ frame: Frame; - // Url to the properties (ex, poro or perm values). - // If the number of property values equals the number of depth values - // the property values will be placed at the nodes and the cell (4 neigboring nodes) - // color will be linearly interpolated over the cell. - // If the number of property values equals one less than the depth values in - // each direction then the property values will be pr cell and the cell will be constant - // colored. + /** Url to the properties (ex, poro or perm values). + * If the number of property values equals the number of depth values + * the property values will be placed at the nodes and the cell (4 neigboring nodes) + * color will be linearly interpolated over the cell. + * If the number of property values equals one less than the depth values in + * each direction then the property values will be pr cell and the cell will be constant + * colored. + */ propertiesUrl: string; - // Contourlines reference point and interval. - // A value of [-1.0, -1.0] will disable contour lines. - // Contour lines will also not be activated if cells are constant colored - // and "isContoursDepth" is set to false. I.e. constant properties within cells and contourlines - // to be calculated for properties and not depths. - // default value: [-1.0, -1.0] + /** Contourlines reference point and interval. + * A value of [-1.0, -1.0] will disable contour lines. + * Contour lines will also not be activated if cells are constant colored + * and "isContoursDepth" is set to false. I.e. constant properties within cells and contourlines + * to be calculated for properties and not depths. + * default value: [-1.0, -1.0] + */ contours: [number, number]; - // Contourlines may be calculated either on depth/z-value or on property value - // If this is set to false, lines will follow properties instead of depth. - // In 2D mode this is always the case regardless. - // default: true + /** Contourlines may be calculated either on depth/z-value or on property value + * If this is set to false, lines will follow properties instead of depth. + * In 2D mode this is always the case regardless. + * default: true + */ isContoursDepth: boolean; - // Enable gridlines. - // default: false. + /** Enable gridlines. + * default: false. + */ gridLines: boolean; - // Name of color map. E.g "PORO" + /** Name of color map. E.g "PORO" + */ colorMapName: string; - // Use color map in this range. + /** Use color map in this range. + */ colorMapRange: [number, number]; - // Clamp colormap to this color at ends. - // Given as array of three values (r,g,b) e.g: [255, 0, 0] - // If not set or set to true, it will clamp to color map min and max values. - // If set to false the clamp color will be completely transparent. + /** Clamp colormap to this color at ends. + * Given as array of three values (r,g,b) e.g: [255, 0, 0] + * If not set or set to true, it will clamp to color map min and max values. + * If set to false the clamp color will be completely transparent. + */ colorMapClampColor: Color | undefined | boolean; - // Optional function property. - // If defined this function will override the color map. - // Takes a value in the range [0,1] and returns a color. - // E.g. (x) => [x * 255, x * 255, x * 255] + /** Optional function property. + * If defined this function will override the color map. + * Takes a value in the range [0,1] and returns a color. + * E.g. (x) => [x * 255, x * 255, x * 255] + */ colorMapFunction?: colorMapFunctionType | false; - // Surface material properties. - // material: true = default material, coloring depends on surface orientation and lighting. - // false = no material, coloring is independent on surface orientation and lighting. - // or full spec: - // material: { - // ambient: 0.35, - // diffuse: 0.6, - // shininess: 32, - // specularColor: [255, 255, 255], - // } + /** Surface material properties. + * material: true = default material, coloring depends on surface orientation and lighting. + * false = no material, coloring is independent on surface orientation and lighting. + * or full spec: + * material: { + * ambient: 0.35, + * diffuse: 0.6, + * shininess: 32, + * specularColor: [255, 255, 255], + * } + */ material: Material; - // Will calculate normals for each vertex and enable phong shading. - // If not set the shader will calculate constant normal for each triangle. + /** Will calculate normals for each vertex and enable phong shading. + * If not set the shader will calculate constant normal for each triangle. + */ smoothShading: boolean; - // Enable/disable depth testing when rendering layer. Default true. + /** Enable/disable depth testing when rendering layer. Default true. + */ depthTest: boolean; + + /** If true means that input z values are interpreted as depths. + * For example depth of z = 1000 corresponds to -1000 on the z axis. Default true. + */ + isZDepth: boolean; } const defaultProps = { @@ -233,13 +263,15 @@ const defaultProps = { smoothShading: true, material: true, depthTest: true, + isZDepth: true, }; export default class MapLayer extends CompositeLayer> { rebuildData(reportBoundingBox: boolean): void { const p = load_mesh_and_properties( this.props.meshUrl, - this.props.propertiesUrl + this.props.propertiesUrl, + this.props.isZDepth ); p.then(([isMesh, meshData, propertiesData]) => { diff --git a/react/src/lib/components/SubsurfaceViewer/layers/wells/utils/spline.ts b/react/src/lib/components/SubsurfaceViewer/layers/wells/utils/spline.ts index 5e4ac2f62..142bf5de7 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/wells/utils/spline.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/wells/utils/spline.ts @@ -247,6 +247,35 @@ export function flattenPath(data_in: FeatureCollection): FeatureCollection { return data; } +export function invertPath(data_in: FeatureCollection): FeatureCollection { + const data = cloneDeep(data_in); + + const no_wells = data.features.length; + for (let well_no = 0; well_no < no_wells; well_no++) { + const geometryCollection = data.features[well_no] + .geometry as GeometryCollection; + const lineString = geometryCollection?.geometries[1] as LineString; + + if (lineString.coordinates?.length === undefined) { + continue; + } + + const coords = lineString.coordinates as Position3D[]; + + // Invert path by multiplying depth with -1. + const coords_inverted: Position3D[] = coords.map((e: Position3D) => { + return [e[0], e[1], -e[2]]; + }); + + ( + (data.features[well_no].geometry as GeometryCollection) + .geometries[1] as LineString + ).coordinates = coords_inverted; + } + + return data; +} + /** * Calculates bounding box of all wells. */ diff --git a/react/src/lib/components/SubsurfaceViewer/layers/wells/wellsLayer.ts b/react/src/lib/components/SubsurfaceViewer/layers/wells/wellsLayer.ts index 4287eb597..f02806ae6 100644 --- a/react/src/lib/components/SubsurfaceViewer/layers/wells/wellsLayer.ts +++ b/react/src/lib/components/SubsurfaceViewer/layers/wells/wellsLayer.ts @@ -31,7 +31,7 @@ import { PropertyDataType, createPropertyData, } from "../utils/layerTools"; -import { splineRefine, GetBoundingBox } from "./utils/spline"; +import { splineRefine, invertPath, GetBoundingBox } from "./utils/spline"; import { interpolateNumberArray } from "d3"; import { layersDefaultProps } from "../layersDefaultProps"; import { DeckGLLayerContext } from "../../components/Map"; @@ -100,6 +100,10 @@ export interface WellsLayerProps extends ExtendedLayerProps { wellNameColor: Color; isLog: boolean; depthTest: boolean; + /** If true means that input z values are interpreted as depths. + * For example depth of z = 1000 corresponds to -1000 on the z axis. Default true. + */ + isZDepth: boolean; } export interface LogCurveDataType { @@ -297,10 +301,14 @@ export default class WellsLayer extends CompositeLayer< return []; } + let data = this.props.data as unknown as FeatureCollection; + if (!this.props.isZDepth) { + data = invertPath(data); + } const refine = this.props.refine; - const data = refine - ? splineRefine(this.props.data as unknown as FeatureCollection) // smooth well paths. - : (this.props.data as unknown as FeatureCollection); + data = refine + ? splineRefine(data) // smooth well paths. + : data; const is3d = this.context.viewport.constructor === OrbitViewport; const positionFormat = "XYZ";