Coordinate

Introduction

vtkCoordinate represents position in a variety of coordinate systems, and
converts position to other coordinate systems. It also supports relative
positioning, so you can create a cascade of vtkCoordinate objects (no loops
please!) that refer to each other. The typical usage of this object is to set
the coordinate system in which to represent a position (e.g.,
SetCoordinateSystemToNormalizedDisplay()), set the value of the coordinate
(e.g., SetValue()), and then invoke the appropriate method to convert to
another coordinate system (e.g., GetComputedWorldValue()).

The coordinate systems in vtk are as follows:

  • DISPLAY - x-y pixel values in window 0, 0 is the lower left of the first
    pixel, size, size is the upper right of the last pixel
  • NORMALIZED DISPLAY - x-y (0,1) normalized values 0, 0 is the lower left of
    the first pixel, 1, 1 is the upper right of the last pixel
  • VIEWPORT - x-y pixel values in viewport 0, 0 is the lower left of the first
    pixel, size, size is the upper right of the last pixel
  • NORMALIZED VIEWPORT - x-y (0,1) normalized value in viewport 0, 0 is the
    lower left of the first pixel, 1, 1 is the upper right of the last pixel
  • VIEW - x-y-z (-1,1) values in pose coordinates. (z is depth)
  • POSE - world coords translated and rotated to the camera position and view
    direction
  • STABILIZED - used by rendering backends to deal with floating point
    resolution issues. Similar to world coordinates but with a translation to
    try to get the matricies to be well behaved.
  • WORLD - x-y-z global coordinate values
  • MODEL - x-y-z coordinate values in the data’s coordinates, the actor holds
    a matrix to go to world
  • BUFFER - x-y-x coordinates as stored int he VBO
  • DATA - x-y-z the original coordintes of the dataset
  • USERDEFINED - x-y-z in User defined space

If you cascade vtkCoordinate objects, you refer to another vtkCoordinate
object which in turn can refer to others, and so on. This allows you to
create composite groups of things like vtkActor2D that are positioned
relative to one another.

!!! note
In cascaded sequences, each vtkCoordinate object may be specified in different coordinate systems!

How the data may go from a dataset through the rendering pipeline in steps

Dataset -> GPU buffer: DCBCMatrix usually this is just a shift and/or scale
to get the GPU buffer for the points into values that will nto run into
floating point resolution issues. This is handled when creating the buffer

  • Buffer to Model: BCMCMatrix just reverses the shift/scale applied to the
    buffer above
  • Model to World: MCWCMatrix uses the Actor’s matrix to transform the points
    to World coordinates
  • World to Stabilized: WCSCMatrix Maps world to the shifted maybe scalede
    renderer’s stabilized center/matrix
  • Stabilized to View: SCVCMatrix captures the rest of the transformation to
    View coordinates
  • View to Projection: VCPCMatrix cpatures the ortho/perspective matrix
  • Projection to …: done by the GPU hardware as part of the vertex to
    fragment

Typically the process is simplified into the 4 following steps :

  • DataSet to Buffer - done when creating the buffer
  • Buffer To Stabilized - BCSCMatrix done in the vertex shader, part of the
    mapperUBO
  • Stabilized To Projection - SCPCMatrix second matrix mult done in the vertex
    shader, part of the rendererUBO
  • Projection to …: vertex to fragment shader operations

See Also

vtkActor2D

Methods

extend

Method use to decorate a given object (publicAPI+model) with vtkCoordinate
characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues ICoordinateInitialValues No (default: {})

getComputedDisplayValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedDoubleDisplayValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedDoubleViewportValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedLocalDisplayValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedViewportValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getComputedWorldValue

Argument Type Required Description
ren vtkRenderer Yes The vtkRenderer instance.

getCoordinateSystem

Get the coordinate system which this coordinate is defined in. The
options are Display, Normalized Display, Viewport, Normalized Viewport,
View, and World.

getCoordinateSystemAsString

Get the coordinate system which this coordinate is defined in as string.

getReferenceCoordinate

getRenderer

Get mapper that was picked (if any)

getValue

Get the value of this coordinate.

newInstance

Method use to create a new instance of vtkCoordinate

Argument Type Required Description
initialValues ICoordinateInitialValues No for pre-setting some of its content

setCoordinateSystem

Set the coordinate system which this coordinate is defined in. The
options are Display, Normalized Display, Viewport, Normalized Viewport,
View, and World.

Argument Type Required Description
coordinateSystem Coordinate Yes

setCoordinateSystemToDisplay

Set the coordinate system to Coordinate.DISPLAY

setCoordinateSystemToNormalizedDisplay

Set the coordinate system to Coordinate.NORMALIZED_DISPLAY

setCoordinateSystemToNormalizedViewport

Set the coordinate system to Coordinate.NORMALIZED_VIEWPORT

setCoordinateSystemToProjection

Set the coordinate system to Coordinate.PROJECTION

setCoordinateSystemToView

Set the coordinate system to Coordinate.VIEW

setCoordinateSystemToViewport

Set the coordinate system to Coordinate.VIEWPORT

setCoordinateSystemToWorld

Set the coordinate system to Coordinate.WORLD

setProperty

Argument Type Required Description
property vtkProperty Yes

setReferenceCoordinate

Argument Type Required Description
referenceCoordinate vtkCoordinate Yes

setRenderer

Argument Type Required Description
renderer vtkRenderer Yes

setValue

Set the value of this coordinate.

Argument Type Required Description
value Yes

Source

Constants.d.ts
export declare enum Coordinate {
DISPLAY = 0,
NORMALIZED_DISPLAY = 1,
VIEWPORT = 2,
NORMALIZED_VIEWPORT = 3,
PROJECTION = 4,
VIEW = 5,
WORLD = 6,
}

declare const _default: {
Coordinate: typeof Coordinate;
};
export default _default;
Constants.js
export const Coordinate = {
DISPLAY: 0,
NORMALIZED_DISPLAY: 1,
VIEWPORT: 2,
NORMALIZED_VIEWPORT: 3,
PROJECTION: 4,
VIEW: 5,
WORLD: 6,
};

export default {
Coordinate,
};
index.d.ts
import { vtkObject, vtkProperty } from "../../../interfaces";
import vtkRenderer from '../Renderer';
import { Coordinate } from "./Constants";


/**
*
*/
export interface ICoordinateInitialValues {
coordinateSystem?: number,
value?: number[],
renderer?: vtkRenderer,
referenceCoordinate?: any,
computing?: number,
computedWorldValue?: number[],
computedDoubleDisplayValue?: number[],
}

export interface vtkCoordinate extends vtkObject {

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedWorldValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedViewportValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedDisplayValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedLocalDisplayValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedDoubleViewportValue(ren: vtkRenderer): number[];

/**
*
* @param {vtkRenderer} ren The vtkRenderer instance.
*/
getComputedDoubleDisplayValue(ren: vtkRenderer): number[];

/**
* Get the coordinate system which this coordinate is defined in. The
* options are Display, Normalized Display, Viewport, Normalized Viewport,
* View, and World.
*/
getCoordinateSystem(): Coordinate;

/**
* Get the coordinate system which this coordinate is defined in as string.
*/
getCoordinateSystemAsString(): string;

/**
* Get the value of this coordinate.
*/
getValue(): number[];

/**
*
*/
getReferenceCoordinate(): vtkCoordinate;

/**
* Get mapper that was picked (if any)
*/
getRenderer(): vtkRenderer;

/**
* Set the coordinate system which this coordinate is defined in. The
* options are Display, Normalized Display, Viewport, Normalized Viewport,
* View, and World.
* @param {Coordinate} coordinateSystem
*/
setCoordinateSystem(coordinateSystem: Coordinate): boolean

/**
* Set the coordinate system to Coordinate.DISPLAY
*/
setCoordinateSystemToDisplay(): void;

/**
* Set the coordinate system to Coordinate.NORMALIZED_DISPLAY
*/
setCoordinateSystemToNormalizedDisplay(): void;

/**
* Set the coordinate system to Coordinate.NORMALIZED_VIEWPORT
*/
setCoordinateSystemToNormalizedViewport(): void;

/**
* Set the coordinate system to Coordinate.PROJECTION
*/
setCoordinateSystemToProjection(): void;

/**
* Set the coordinate system to Coordinate.VIEW
*/
setCoordinateSystemToView(): void;

/**
* Set the coordinate system to Coordinate.VIEWPORT
*/
setCoordinateSystemToViewport(): void;

/**
* Set the coordinate system to Coordinate.WORLD
*/
setCoordinateSystemToWorld(): void;

/**
*
* @param {vtkProperty} property
*/
setProperty(property: vtkProperty): boolean;

/**
*
* @param {vtkCoordinate} referenceCoordinate
*/
setReferenceCoordinate(referenceCoordinate: vtkCoordinate): boolean;

/**
*
* @param {vtkRenderer} renderer
*/
setRenderer(renderer: vtkRenderer): boolean;

/**
* Set the value of this coordinate.
* @param value
*/
setValue(value: number[]): boolean;
}

/**
* Method use to decorate a given object (publicAPI+model) with vtkCoordinate
* characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {ICoordinateInitialValues} [initialValues] (default: {})
*/
export function extend(publicAPI: object, model: object, initialValues?: ICoordinateInitialValues): void;

/**
* Method use to create a new instance of vtkCoordinate
* @param {ICoordinateInitialValues} [initialValues] for pre-setting some of its
* content
*/
export function newInstance(initialValues?: ICoordinateInitialValues): vtkCoordinate;

/**
* vtkCoordinate represents position in a variety of coordinate systems, and
* converts position to other coordinate systems. It also supports relative
* positioning, so you can create a cascade of vtkCoordinate objects (no loops
* please!) that refer to each other. The typical usage of this object is to set
* the coordinate system in which to represent a position (e.g.,
* SetCoordinateSystemToNormalizedDisplay()), set the value of the coordinate
* (e.g., SetValue()), and then invoke the appropriate method to convert to
* another coordinate system (e.g., GetComputedWorldValue()).
*
* The coordinate systems in vtk are as follows:
*
* - DISPLAY - x-y pixel values in window 0, 0 is the lower left of the first
* pixel, size, size is the upper right of the last pixel
* - NORMALIZED DISPLAY - x-y (0,1) normalized values 0, 0 is the lower left of
* the first pixel, 1, 1 is the upper right of the last pixel
* - VIEWPORT - x-y pixel values in viewport 0, 0 is the lower left of the first
* pixel, size, size is the upper right of the last pixel
* - NORMALIZED VIEWPORT - x-y (0,1) normalized value in viewport 0, 0 is the
* lower left of the first pixel, 1, 1 is the upper right of the last pixel
* - VIEW - x-y-z (-1,1) values in pose coordinates. (z is depth)
* - POSE - world coords translated and rotated to the camera position and view
* direction
* - STABILIZED - used by rendering backends to deal with floating point
* resolution issues. Similar to world coordinates but with a translation to
* try to get the matricies to be well behaved.
* - WORLD - x-y-z global coordinate values
* - MODEL - x-y-z coordinate values in the data's coordinates, the actor holds
* a matrix to go to world
* - BUFFER - x-y-x coordinates as stored int he VBO
* - DATA - x-y-z the original coordintes of the dataset
* - USERDEFINED - x-y-z in User defined space
*
* If you cascade vtkCoordinate objects, you refer to another vtkCoordinate
* object which in turn can refer to others, and so on. This allows you to
* create composite groups of things like vtkActor2D that are positioned
* relative to one another.
*
* !!! note
* In cascaded sequences, each vtkCoordinate object may be specified in different coordinate systems!
*
* How the data may go from a dataset through the rendering pipeline in steps
*
* Dataset -> GPU buffer: DCBCMatrix usually this is just a shift and/or scale
* to get the GPU buffer for the points into values that will nto run into
* floating point resolution issues. This is handled when creating the buffer
*
* - Buffer to Model: BCMCMatrix just reverses the shift/scale applied to the
* buffer above
* - Model to World: MCWCMatrix uses the Actor's matrix to transform the points
* to World coordinates
* - World to Stabilized: WCSCMatrix Maps world to the shifted maybe scalede
* renderer's stabilized center/matrix
* - Stabilized to View: SCVCMatrix captures the rest of the transformation to
* View coordinates
* - View to Projection: VCPCMatrix cpatures the ortho/perspective matrix
* - Projection to ...: done by the GPU hardware as part of the vertex to
* fragment
*
* Typically the process is simplified into the 4 following steps :
*
* - DataSet to Buffer - done when creating the buffer
* - Buffer To Stabilized - BCSCMatrix done in the vertex shader, part of the
* mapperUBO
* - Stabilized To Projection - SCPCMatrix second matrix mult done in the vertex
* shader, part of the rendererUBO
* - Projection to ...: vertex to fragment shader operations
*
* @see [vtkActor](./Rendering_Core_Actor.html)2D
*/
export declare const vtkCoordinate: {
newInstance: typeof newInstance;
extend: typeof extend;
Coordinate: typeof Coordinate;
};
export default vtkCoordinate;
index.js
import macro from 'vtk.js/Sources/macros';
import Constants from 'vtk.js/Sources/Rendering/Core/Coordinate/Constants';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';

const { Coordinate } = Constants;
const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkActor methods
// ----------------------------------------------------------------------------

function vtkCoordinate(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkCoordinate');

publicAPI.setValue = (...args) => {
if (model.deleted) {
vtkErrorMacro('instance deleted - cannot call any method');
return false;
}

let array = args;
// allow an array passed as a single arg.
if (array.length === 1 && Array.isArray(array[0])) {
array = array[0];
}

if (array.length === 2) {
publicAPI.setValue(array[0], array[1], 0.0);
return true;
}
if (array.length !== 3) {
throw new RangeError('Invalid number of values for array setter');
}
let changeDetected = false;
model.value.forEach((item, index) => {
if (item !== array[index]) {
if (changeDetected) {
return;
}
changeDetected = true;
}
});

if (changeDetected) {
model.value = [].concat(array);
publicAPI.modified();
}
return true;
};

publicAPI.setCoordinateSystemToDisplay = () => {
publicAPI.setCoordinateSystem(Coordinate.DISPLAY);
};

publicAPI.setCoordinateSystemToNormalizedDisplay = () => {
publicAPI.setCoordinateSystem(Coordinate.NORMALIZED_DISPLAY);
};

publicAPI.setCoordinateSystemToViewport = () => {
publicAPI.setCoordinateSystem(Coordinate.VIEWPORT);
};

publicAPI.setCoordinateSystemToNormalizedViewport = () => {
publicAPI.setCoordinateSystem(Coordinate.NORMALIZED_VIEWPORT);
};

publicAPI.setCoordinateSystemToProjection = () => {
publicAPI.setCoordinateSystem(Coordinate.PROJECTION);
};

publicAPI.setCoordinateSystemToView = () => {
publicAPI.setCoordinateSystem(Coordinate.VIEW);
};

publicAPI.setCoordinateSystemToWorld = () => {
publicAPI.setCoordinateSystem(Coordinate.WORLD);
};

publicAPI.getCoordinateSystemAsString = () =>
macro.enumToString(Coordinate, model.coordinateSystem);

publicAPI.getComputedWorldValue = (ren) => {
let val = model.computedWorldValue;

if (model.computing) {
return val;
}
model.computing = 1;
val[0] = model.value[0];
val[1] = model.value[1];
val[2] = model.value[2];

// Use our renderer if is defined
let renderer = ren;
if (model.renderer) {
renderer = model.renderer;
}
if (!renderer) {
if (model.coordinateSystem === Coordinate.WORLD) {
if (model.referenceCoordinate) {
const refValue =
model.referenceCoordinate.getComputedWorldValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
val[2] += refValue[2];
}
model.computing = 0;
} else {
vtkErrorMacro(
'Attempt to compute world coordinates from another coordinate system without a renderer'
);
}
return val;
}

// convert to current coordinate system
let view = null;
if (renderer && renderer.getRenderWindow().getViews()) {
view = renderer.getRenderWindow().getViews()[0];
} else {
return model.computedWorldValue;
}

const dims = view.getViewportSize(renderer);
const aspect = dims[0] / dims[1];

if (
model.referenceCoordinate &&
model.coordinateSystem !== Coordinate.WORLD
) {
const fval =
model.referenceCoordinate.getComputedDoubleDisplayValue(renderer);
let refValue = [fval[0], fval[1], 0.0];

switch (model.coordinateSystem) {
case Coordinate.NORMALIZED_DISPLAY:
refValue = view.displayToNormalizedDisplay(
refValue[0],
refValue[1],
refValue[2]
);
break;
case Coordinate.VIEWPORT:
refValue = view.displayToNormalizedDisplay(
refValue[0],
refValue[1],
refValue[2]
);
refValue = view.normalizedDisplayToViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
break;
case Coordinate.NORMALIZED_VIEWPORT:
refValue = view.displayToNormalizedDisplay(
refValue[0],
refValue[1],
refValue[2]
);
refValue = view.normalizedDisplayToViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
refValue = view.viewportToNormalizedViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
break;
case Coordinate.PROJECTION:
refValue = view.displayToNormalizedDisplay(
refValue[0],
refValue[1],
refValue[2]
);
refValue = view.normalizedDisplayToViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
refValue = view.viewportToNormalizedViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
refValue = renderer.normalizedViewportToProjection(
refValue[0],
refValue[1],
refValue[2]
);
break;
case Coordinate.VIEW:
refValue = view.displayToNormalizedDisplay(
refValue[0],
refValue[1],
refValue[2]
);
refValue = view.normalizedDisplayToViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
refValue = view.viewportToNormalizedViewport(
refValue[0],
refValue[1],
refValue[2],
renderer
);
refValue = renderer.normalizedViewportToProjection(
refValue[0],
refValue[1],
refValue[2]
);
refValue = renderer.projectionToView(
refValue[0],
refValue[1],
refValue[2],
aspect
);
break;
default:
break;
}

val[0] += refValue[0];
val[1] += refValue[1];
val[2] += refValue[2];
}

switch (model.coordinateSystem) {
case Coordinate.DISPLAY:
val = view.displayToNormalizedDisplay(val[0], val[1], val[2]);
val = view.normalizedDisplayToViewport(
val[0],
val[1],
val[2],
renderer
);
val = view.viewportToNormalizedViewport(
val[0],
val[1],
val[2],
renderer
);
val = renderer.normalizedViewportToProjection(val[0], val[1], val[2]);
val = renderer.projectionToView(val[0], val[1], val[2], aspect);
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
case Coordinate.NORMALIZED_DISPLAY:
val = view.normalizedDisplayToViewport(
val[0],
val[1],
val[2],
renderer
);
val = view.viewportToNormalizedViewport(
val[0],
val[1],
val[2],
renderer
);
val = renderer.normalizedViewportToProjection(val[0], val[1], val[2]);
val = renderer.projectionToView(val[0], val[1], val[2], aspect);
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
case Coordinate.VIEWPORT:
val = view.viewportToNormalizedViewport(
val[0],
val[1],
val[2],
renderer
);
val = renderer.normalizedViewportToProjection(val[0], val[1], val[2]);
val = renderer.projectionToView(val[0], val[1], val[2], aspect);
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
case Coordinate.NORMALIZED_VIEWPORT:
val = renderer.normalizedViewportToProjection(val[0], val[1], val[2]);
val = renderer.projectionToView(val[0], val[1], val[2], aspect);
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
case Coordinate.PROJECTION:
val = renderer.projectionToView(val[0], val[1], val[2], aspect);
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
case Coordinate.VIEW:
val = renderer.viewToWorld(val[0], val[1], val[2]);
break;
default:
break;
}

if (
model.referenceCoordinate &&
model.coordinateSystem === Coordinate.WORLD
) {
const refValue = publicAPI.getComputedWorldValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
val[2] += refValue[2];
}

model.computing = 0;
model.computedWorldValue = val.slice(0);
return val;
};

publicAPI.getComputedViewportValue = (ren) => {
const f = publicAPI.getComputedDoubleViewportValue(ren);
return [vtkMath.round(f[0]), vtkMath.round(f[1])];
};

publicAPI.getComputedDisplayValue = (ren) => {
const val = publicAPI.getComputedDoubleDisplayValue(ren);
return [vtkMath.floor(val[0]), vtkMath.floor(val[1])];
};

publicAPI.getComputedLocalDisplayValue = (ren) => {
// Use our renderer if it is defined
let renderer = ren;
if (model.renderer) {
renderer = model.renderer;
}
let val = publicAPI.getComputedDisplayValue(renderer);

if (!renderer) {
vtkErrorMacro(
'Attempt to convert to local display coordinates without a renderer'
);
return val;
}

let view = null;
if (renderer && renderer.getRenderWindow().getViews()) {
view = renderer.getRenderWindow().getViews()[0];
} else {
return val;
}
val = view.displayToLocalDisplay(val[0], val[1], val[2]);
return [vtkMath.round(val[0]), vtkMath.round(val[1])];
};

publicAPI.getComputedDoubleViewportValue = (ren) => {
let renderer = ren;
if (model.renderer) {
renderer = model.renderer;
}
let val = publicAPI.getComputedDoubleDisplayValue(renderer);

if (!renderer) {
return val;
}
let view = null;
if (renderer && renderer.getRenderWindow().getViews()) {
view = renderer.getRenderWindow().getViews()[0];
} else {
return val;
}

val = view.displayToNormalizedDisplay(val[0], val[1], val[2]);
val = view.normalizedDisplayToViewport(val[0], val[1], val[2], renderer);

return [val[0], val[1]];
};

publicAPI.getComputedDoubleDisplayValue = (ren) => {
if (model.computing) {
return model.computedDoubleDisplayValue;
}
model.computing = 1;

let val = model.value.slice(0);
let renderer = ren;
if (model.renderer) {
renderer = model.renderer;
}
if (!renderer) {
if (model.coordinateSystem === Coordinate.DISPLAY) {
model.computedDoubleDisplayValue[0] = val[0];
model.computedDoubleDisplayValue[1] = val[1];
if (model.referenceCoordinate) {
const refValue =
model.referenceCoordinate.getComputedDoubleDisplayValue();
model.computedDoubleDisplayValue[0] += refValue[0];
model.computedDoubleDisplayValue[1] += refValue[1];
}
} else {
model.computedDoubleDisplayValue[0] = Number.MAX_VALUE;
model.computedDoubleDisplayValue[1] = Number.MAX_VALUE;

vtkErrorMacro(
'Request for coordinate transformation without required viewport'
);
}
return model.computedDoubleDisplayValue;
}

let view = null;
if (renderer && renderer.getRenderWindow().getViews()) {
view = renderer.getRenderWindow().getViews()[0];
} else {
return val;
}

const dims = view.getViewportSize(renderer);
const aspect = dims[0] / dims[1];
switch (model.coordinateSystem) {
case Coordinate.WORLD: {
if (model.referenceCoordinate) {
const refValue =
model.referenceCoordinate.getComputedWorldValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
val[2] += refValue[2];
}
val = renderer.worldToView(val[0], val[1], val[2]);
val = renderer.viewToProjection(val[0], val[1], val[2], aspect);

val = renderer.projectionToNormalizedViewport(val[0], val[1], val[2]);
val = view.normalizedViewportToViewport(
val[0],
val[1],
val[2],
renderer
);
val = view.viewportToNormalizedDisplay(
val[0],
val[1],
val[2],
renderer
);
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;
}
case Coordinate.VIEW: {
val = renderer.viewToProjection(val[0], val[1], val[2], aspect);
val = renderer.projectionToNormalizedViewport(val[0], val[1], val[2]);
val = view.normalizedViewportToViewport(
val[0],
val[1],
val[2],
renderer
);
val = view.viewportToNormalizedDisplay(
val[0],
val[1],
val[2],
renderer
);
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;
}
case Coordinate.PROJECTION: {
val = renderer.projectionToNormalizedViewport(val[0], val[1], val[2]);
val = view.normalizedViewportToViewport(
val[0],
val[1],
val[2],
renderer
);
val = view.viewportToNormalizedDisplay(
val[0],
val[1],
val[2],
renderer
);
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;
}
case Coordinate.NORMALIZED_VIEWPORT: {
val = view.normalizedViewportToViewport(
val[0],
val[1],
val[2],
renderer
);

if (model.referenceCoordinate) {
const refValue =
model.referenceCoordinate.getComputedDoubleViewportValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
}

val = view.viewportToNormalizedDisplay(
val[0],
val[1],
val[2],
renderer
);
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;
}
case Coordinate.VIEWPORT: {
if (model.referenceCoordinate) {
const refValue =
model.referenceCoordinate.getComputedDoubleViewportValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
}
val = view.viewportToNormalizedDisplay(
val[0],
val[1],
val[2],
renderer
);
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;
}
case Coordinate.NORMALIZED_DISPLAY:
val = view.normalizedDisplayToDisplay(val[0], val[1], val[2]);
break;

case Coordinate.USERDEFINED:
val = model.value.slice(0);
break;
default:
break;
}

// if we have a reference coordinate and we haven't handled it yet
if (
model.referenceCoordinate &&
(model.coordinateSystem === Coordinate.DISPLAY ||
model.coordinateSystem === Coordinate.NORMALIZED_DISPLAY)
) {
const refValue =
model.referenceCoordinate.getComputedDoubleDisplayValue(renderer);
val[0] += refValue[0];
val[1] += refValue[1];
}

model.computedDoubleDisplayValue[0] = val[0];
model.computedDoubleDisplayValue[1] = val[1];

model.computing = 0;

return model.computedDoubleDisplayValue;
};

publicAPI.getComputedValue = (ren) => {
let renderer = ren;
if (model.renderer) {
renderer = model.renderer;
}
switch (model.coordinateSystem) {
case Coordinate.WORLD:
return publicAPI.getComputedWorldValue(renderer);
case Coordinate.VIEW:
case Coordinate.NORMALIZED_VIEWPORT:
case Coordinate.VIEWPORT: {
const val = publicAPI.getComputedViewportValue(renderer);
model.computedWorldValue[0] = val[0];
model.computedWorldValue[1] = val[1];
break;
}
case Coordinate.NORMALIZED_DISPLAY:
case Coordinate.DISPLAY: {
const val = model.getComputedDisplayValue(renderer);
model.computedWorldValue[0] = val[0];
model.computedWorldValue[1] = val[1];
break;
}
default:
break;
}
return model.computedWorldValue;
};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
coordinateSystem: Coordinate.WORLD,
value: [0.0, 0.0, 0.0],
renderer: null,
referenceCoordinate: null,
computing: 0,
computedWorldValue: [0.0, 0.0, 0.0],
computedDoubleDisplayValue: [0.0, 0.0],
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);

macro.obj(publicAPI, model);

// Build VTK API
macro.set(publicAPI, model, ['property']);
macro.get(publicAPI, model, ['value']);
macro.setGet(publicAPI, model, [
'coordinateSystem',
'referenceCoordinate',
'renderer',
]);

macro.getArray(publicAPI, model, ['value'], 3);

// Object methods
vtkCoordinate(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkCoordinate');

// ----------------------------------------------------------------------------

export default { newInstance, extend, ...Constants };