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 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
VIEW - x-y-z (-1,1) values in camera coordinates. (z is depth)
WORLD - x-y-z global coordinate values
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 that in cascaded sequences, each
vtkCoordinate object may be specified in different coordinate systems!

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,
VIEW: 4,
WORLD: 5,
USERDEFINED: 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.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;
}

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.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.normalizedViewportToView(
refValue[0],
refValue[1],
refValue[2]
);
break;
default:
break;
}

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

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

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.normalizedViewportToView(val[0], val[1], val[2]);
val = renderer.viewToWorld(val[0], val[1], val[2], aspect);
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.normalizedViewportToView(val[0], val[1], val[2]);
val = renderer.viewToWorld(val[0], val[1], val[2], aspect);
break;
case Coordinate.VIEWPORT:
val = view.viewportToNormalizedViewport(
val[0],
val[1],
val[2],
renderer
);
val = renderer.normalizedViewportToView(val[0], val[1], val[2]);
val = renderer.viewToWorld(val[0], val[1], val[2], aspect);
break;
case Coordinate.NORMALIZED_VIEWPORT:
val = renderer.normalizedViewportToView(val[0], val[1], val[2]);
val = renderer.viewToWorld(val[0], val[1], val[2], aspect);
break;
case Coordinate.VIEW:
val = renderer.viewToWorld(val[0], val[1], val[2], aspect);
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], aspect);

val = renderer.viewToNormalizedViewport(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.viewToNormalizedViewport(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);