Coordinate

Introduction

vtkCoordinate performs coordinate transformation, and represent position, in a variety of vtk coordinate systems

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 a window
NORMALIZED DISPLAY - x-y (0,1) normalized values
VIEWPORT - x-y pixel values in viewport
NORMALIZED VIEWPORT - x-y (0,1) normalized value in viewport
PROJECTION - View coordinates transformed by the ortho/perspective
equations and normalized to -1,1 cube on X and Y. The
z range is defined by the code and may be -1,1
for OpenGL or other values. This is the coordinate system
that is typically coming out of the vertex shader.
VIEW - x-y-z values in camera coordinates. The origin is
at the camera position and the orientation is such
that the -Z axis is the view direction, the X axis
is the view right, and Y axis is view up. This is
a translation and rotation from world coordinates
based on the camera settings.
WORLD - x-y-z global coordinate values
MODEL - The coordinate system specific to a dataaet or
actor. This is normally converted into WORLD coordinates
as part of the rendering process.

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 that in cascaded sequences, each
vtkCoordinate object may be specified in different coordinate systems!

In shader code coordinate system transformations will often be referenced
as matricies with common ones being.


MCWCMatrix - model to world
MCPCMatrix - model to projection
WCVCMatrix - world to view - half of the camera transform
WCPCMatrix - world to projection
VCPCMatrix - view to projection - the other part of the camera transform

See Also

vtkActor2D

referenceCoordinate

Make this coordinate relative to another coordinate instance.

viewport

The viewport to use for calculations that require it.

value

The x y z location of this point.

Source

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.js
import macro from 'vtk.js/Sources/macro';
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]);
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]);
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]);
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]);

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 Object.assign({ newInstance, extend }, Constants);