@inweb/viewer-visualize
Version:
JavaScript library for rendering CAD and BIM files in a browser using VisualizeJS
1,290 lines (1,242 loc) • 158 kB
JavaScript
import { CANVAS_EVENTS, draggersRegistry, commandsRegistry, componentsRegistry, Loader, loadersRegistry, Options } from "@inweb/viewer-core";
export * from "@inweb/viewer-core";
import { EventEmitter2 } from "@inweb/eventemitter2";
import { Markup } from "@inweb/markup";
export * from "@inweb/markup";
class OdaGeAction {
constructor(module) {
this.setViewParams = params => {
var _a;
const extView = this.m_module.getViewer().getActiveTvExtendedView();
extView.setView(params.position, params.target, params.upVector, params.viewFieldWidth, params.viewFieldHeight, params.perspective);
(_a = extView.delete) === null || _a === undefined ? undefined : _a.call(extView);
};
this.getViewParams = () => {
var _a;
const view = this.m_module.getViewer().activeView;
const obj = {
position: view.viewPosition,
target: view.viewTarget,
upVector: view.upVector,
viewFieldWidth: view.viewFieldWidth,
viewFieldHeight: view.viewFieldHeight,
perspective: view.perspective
};
(_a = view.delete) === null || _a === undefined ? undefined : _a.call(view);
return obj;
};
this.m_module = module;
}
getViewer() {
return this.m_module.getViewer();
}
getModel() {
return this.getViewer().getMarkupModel();
}
copyPoint(point) {
const p = new this.m_module.Point3d;
p.set(point.x, point.y, point.z);
return p;
}
createVector3d() {
return new this.m_module.Vector3d;
}
createPoint3d() {
return new this.m_module.Point3d;
}
createMatrix3d() {
return new this.m_module.Matrix3d;
}
createPlane() {
return new this.m_module.OdTvPlane;
}
toVector(geVector) {
return this.m_module.Vector3d.createFromArray(geVector);
}
toGeVector(v) {
return [ v.x, v.y, v.z ];
}
toGePoint(point) {
return [ point.x, point.y, point.z ];
}
toPoint(gePoint) {
return this.m_module.Point3d.createFromArray(gePoint);
}
screenToWorld(x, y) {
return this.toPoint(this.m_module.getViewer().screenToWorld(x, y));
}
toDoubleArray(points) {
const p = [];
for (let i = 0; i < points.length; i++) {
p.push(points[i].x);
p.push(points[i].y);
p.push(points[i].z);
}
return p;
}
correctCameraTarget() {
const params = this.getViewParams();
const ext = this.m_module.getViewer().getActiveExtents();
const {min: min, max: max} = ext;
const target = this.toPoint(params.target);
const contains = target.x >= min.x && target.y >= min.y && target.z >= min.z && target.x <= max.x && target.y <= max.y && target.z <= max.z;
if (!contains) {
params.target = ext.center();
this.setViewParams(params);
}
}
}
const CLICK_DELTA = 5;
const INTERACTIVITY_FPS = 24;
class OdBaseDragger extends OdaGeAction {
constructor(subject) {
super(subject.visualizeJs);
this.beginInteractivity = () => {
const viewer = this.getViewer();
const view = viewer.activeView;
if (view["beginInteractivity"]) {
view.beginInteractivity(INTERACTIVITY_FPS);
this.subject.update();
}
view.delete();
};
this.endInteractivity = () => {
const viewer = this.getViewer();
const view = viewer.activeView;
if (view["endInteractivity"]) {
view.endInteractivity();
const device = this.getViewer().getActiveDevice();
const canvas = this.m_module.canvas;
device.invalidate([ 0, 0, canvas.width, canvas.height ]);
device.delete();
this.subject.update();
}
view.delete();
};
this.subject = subject;
this.needInputText = false;
this.mouseDownPosition = {
x: 0,
y: 0
};
this.autoSelect = false;
this.onmessage = event => this.subject.emitEvent(event);
this.canvasEvents = CANVAS_EVENTS;
}
initialize() {
this.canvasEvents = this.canvasEvents.filter((x => typeof this[x] === "function"));
this.canvasEvents.forEach((x => this[x] = this[x].bind(this)));
this.canvasEvents.forEach((x => this.subject.on(x, this[x])));
this.getViewer().setEnableAutoSelect(!!this.autoSelect);
}
dispose() {
this.canvasEvents.forEach((x => this.subject.off(x, this[x])));
}
relativeCoords(event) {
return {
x: event.offsetX * window.devicePixelRatio,
y: event.offsetY * window.devicePixelRatio
};
}
pointerdown(ev) {
if (!ev.isPrimary || OdBaseDragger.isGestureActive) {
return;
}
ev.target.setPointerCapture(ev.pointerId);
const relCoord = this.relativeCoords(ev);
this.isDragging = true;
this.mouseDownPosition = {
x: relCoord.x,
y: relCoord.y
};
this.start(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
this.subject.update();
}
pointerup(ev) {
if (OdBaseDragger.needSkipPointerUp) {
return;
}
if (!ev.isPrimary) {
return;
}
ev.target.releasePointerCapture(ev.pointerId);
const relCoord = this.relativeCoords(ev);
this.end(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
this.isDragging = false;
this.subject.update();
}
pointercancel(ev) {
if (!ev.isPrimary) {
return;
}
this.m_module.canvas.dispatchEvent(new PointerEvent("pointerup", ev));
}
pointermove(ev) {
if (!ev.isPrimary || OdBaseDragger.isGestureActive) {
return;
}
const relCoord = this.relativeCoords(ev);
this.drag(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
if (this.isDragging) {
this.subject.update();
}
}
click(ev) {
const viewer = this.getViewer();
const relCoord = this.relativeCoords(ev);
const x = relCoord.x;
const y = relCoord.y;
const isNotDragging = Math.abs(x - this.mouseDownPosition.x) < CLICK_DELTA && Math.abs(y - this.mouseDownPosition.y) < CLICK_DELTA;
if (viewer && viewer.getEnableAutoSelect() && isNotDragging) {
viewer.unselect();
viewer.select(x, y, x, y);
this.subject.update();
const selectionSet = viewer.getSelected();
const handles = this.subject.getSelected();
this.onmessage({
type: "select",
data: selectionSet,
handles: handles
});
}
}
dblclick(ev) {
const viewer = this.getViewer();
const relCoord = this.relativeCoords(ev);
const x = relCoord.x;
const y = relCoord.y;
const device = viewer.getActiveDevice();
const clickView = device.viewAt([ x, y ]);
if (clickView && !clickView.active) {
viewer.activeView = clickView;
clickView.delete();
this.subject.update();
} else {
if (viewer && viewer.getEnableAutoSelect()) {
const pSelected = viewer.getSelected();
if (!pSelected.isNull() && pSelected.numItems() !== 0) {
const itr = pSelected.getIterator();
const entity = itr.getEntity();
viewer.zoomToEntity(entity);
this.onmessage({
type: "zoomtoentity",
data: entity
});
this.subject.update();
this.deleteAll([ itr, entity ]);
}
}
}
device.delete();
}
start(x, y, absoluteX = 0, absoluteY = 0) {}
drag(x, y, absoluteX = 0, absoluteY = 0) {}
end(x, y, absoluteX = 0, absoluteY = 0) {}
getActiveMarkupEntity(entityName) {
return this.subject.addMarkupEntity(entityName);
}
syncOverlayView() {
return this.subject.syncOverlay();
}
deleteAll(objects) {
var _a;
for (const obj of objects) {
(_a = obj === null || obj === undefined ? undefined : obj.delete) === null || _a === undefined ? undefined : _a.call(obj);
}
}
updatePreview() {}
static set isGestureActive(value) {
if (OdBaseDragger._isGestureActive === value) {
return;
}
OdBaseDragger._isGestureActive = value;
if (OdBaseDragger._isGestureActive) {
OdBaseDragger.needSkipPointerUp = true;
}
}
static get isGestureActive() {
return OdBaseDragger._isGestureActive;
}
static get needSkipPointerUp() {
if (OdBaseDragger._needSkipPointerUp) {
OdBaseDragger.needSkipPointerUp = false;
return true;
}
return false;
}
static set needSkipPointerUp(value) {
OdBaseDragger._needSkipPointerUp = value;
}
}
OdBaseDragger._isGestureActive = false;
OdBaseDragger._needSkipPointerUp = false;
function createHtmlElementIfNeed(element, targetElement, dataTestId) {
if (!element) {
element = document.createElement("div");
element.setAttribute("data-testid", dataTestId);
targetElement.appendChild(element);
}
return element;
}
function destroyHtmlElement(element, targetElement) {
if (element) {
targetElement.removeChild(element);
}
return null;
}
function worldToScreen(gePoint, moduleInstance, viewer) {
const worldPoint = moduleInstance.Point3d.createFromArray(gePoint);
const avp = viewer.activeView;
const mtx = avp.worldToDeviceMatrix;
const devicePoint = worldPoint.transformBy(mtx);
const res = {
x: devicePoint.x / window.devicePixelRatio,
y: devicePoint.y / window.devicePixelRatio
};
mtx.delete();
worldPoint.delete();
devicePoint.delete();
avp.delete();
return res;
}
function getDistance(gePoint1, gePoint2, moduleInstance) {
const tvPoint1 = moduleInstance.Point3d.createFromArray(gePoint1);
const tvPoint2 = moduleInstance.Point3d.createFromArray(gePoint2);
const distance = tvPoint1.distanceTo(tvPoint2).toFixed(2);
tvPoint1.delete();
tvPoint2.delete();
return distance;
}
function normalizeFloat(value) {
return value < 0 ? Math.ceil(value) : Math.floor(value);
}
const lineSegmentsIntersect = (p1, p2, p3, p4) => {
const a_dx = p2.x - p1.x;
const a_dy = p2.y - p1.y;
const b_dx = p4.x - p3.x;
const b_dy = p4.y - p3.y;
const s = (-a_dy * (p1.x - p3.x) + a_dx * (p1.y - p3.y)) / (-b_dx * a_dy + a_dx * b_dy);
const t = (+b_dx * (p1.y - p3.y) - b_dy * (p1.x - p3.x)) / (-b_dx * a_dy + a_dx * b_dy);
return s >= 0 && s <= 1 && t >= 0 && t <= 1 ? {
x: normalizeFloat(p1.x + t * a_dx),
y: normalizeFloat(p1.y + t * a_dy)
} : false;
};
function checkSegmentsIntersect(p1, p2, p3, p4, res) {
const r = lineSegmentsIntersect(p1, p2, p3, p4);
if (r) {
res.push(r);
}
}
function isInsideRect(p, width, height) {
return p.x <= width && p.x >= 0 && p.y <= height && p.y >= 0;
}
function getDataForDrawLineWithFixed(p1, p2, width, height) {
const pLU = {
x: 0,
y: 0
};
const pRU = {
x: width,
y: 0
};
const pLB = {
x: 0,
y: height
};
const pRB = {
x: width,
y: height
};
const intersects = [];
checkSegmentsIntersect(p1, p2, pLU, pRU, intersects);
checkSegmentsIntersect(p1, p2, pLU, pLB, intersects);
checkSegmentsIntersect(p1, p2, pLB, pRB, intersects);
checkSegmentsIntersect(p1, p2, pRB, pRU, intersects);
let fixedP1 = null;
let fixedP2 = null;
if (intersects.length === 0) {
fixedP1 = p1;
fixedP2 = p2;
} else if (intersects.length === 1) {
if (isInsideRect(p1, width, height)) {
fixedP1 = p1;
fixedP2 = intersects[0];
} else {
fixedP1 = intersects[0];
fixedP2 = p2;
}
} else {
fixedP1 = intersects[0];
fixedP2 = intersects[1];
}
const dx = fixedP2.x - fixedP1.x;
const dy = fixedP2.y - fixedP1.y;
let angle = 180 * Math.atan(dy / dx) / Math.PI;
if (dx < 0) {
angle -= 180;
}
const size = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
return {
angle: angle,
width: size,
p1: fixedP1,
p2: fixedP2
};
}
function onSetCallback(element, cb) {
if (element) {
element.onclick = cb ? () => cb() : () => {};
}
}
function onSetSelectivity(element, enable) {
element.style.pointerEvents = enable ? "auto" : "none";
}
class MeasureLineItem {
constructor(targetElement, viewer, moduleInstance) {
this.htmlElemStartPoint = null;
this.htmlElemEndPoint = null;
this.htmlElemLine = null;
this.htmlElemTitle = null;
this.startPoint = null;
this.endPoint = null;
this.unit = "";
this.scale = 1;
this.size = 10;
this.lineThickness = 2;
this.style = {
border: "2px solid #FFFFFF",
background: "#009bff",
color: "white",
boxShadow: "0 0 10px rgba(0,0,0,0.5)"
};
this.htmlElemStartPoint = createHtmlElementIfNeed(this.htmlElemStartPoint, targetElement, "ruler-start");
this.htmlElemEndPoint = createHtmlElementIfNeed(this.htmlElemEndPoint, targetElement, "ruler-end");
this.htmlElemLine = createHtmlElementIfNeed(this.htmlElemLine, targetElement, "ruler-line");
this.htmlElemTitle = createHtmlElementIfNeed(this.htmlElemTitle, targetElement, "ruler-value");
this.viewer = viewer;
this.moduleInstance = moduleInstance;
this.targetElement = targetElement;
this.isFinishDraw = false;
}
drawMeasureLine() {
const pointSize = this.size;
const rect = this.moduleInstance.canvas.getBoundingClientRect();
if (this.startPoint) {
this.htmlElemStartPoint = createHtmlElementIfNeed(this.htmlElemStartPoint, this.targetElement, "ruler-start");
const pScreenStart = worldToScreen(this.startPoint, this.moduleInstance, this.viewer);
if (isInsideRect(pScreenStart, rect.width, rect.height)) {
this.htmlElemStartPoint.style.display = "block";
this.htmlElemStartPoint.style.cursor = "pointer";
this.htmlElemStartPoint.style.position = "absolute";
this.htmlElemStartPoint.style.top = `${pScreenStart.y - pointSize / 2}px`;
this.htmlElemStartPoint.style.left = `${pScreenStart.x - pointSize / 2}px`;
this.htmlElemStartPoint.style.borderRadius = `${pointSize}px`;
this.htmlElemStartPoint.style.border = this.style.border;
this.htmlElemStartPoint.style.background = this.style.background;
this.htmlElemStartPoint.style.zIndex = "2";
this.htmlElemStartPoint.style.width = `${pointSize}px`;
this.htmlElemStartPoint.style.height = `${pointSize}px`;
this.htmlElemStartPoint.style.boxShadow = this.style.boxShadow;
} else {
this.htmlElemStartPoint.style.display = "none";
}
}
if (this.endPoint && this.isFinishDraw) {
this.htmlElemEndPoint = createHtmlElementIfNeed(this.htmlElemEndPoint, this.targetElement, "ruler-end");
const pScreenEnd = worldToScreen(this.endPoint, this.moduleInstance, this.viewer);
if (isInsideRect(pScreenEnd, rect.width, rect.height)) {
this.htmlElemEndPoint.style.display = "block";
this.htmlElemEndPoint.style.cursor = "pointer";
this.htmlElemEndPoint.style.position = "absolute";
this.htmlElemEndPoint.style.top = `${pScreenEnd.y - pointSize / 2}px`;
this.htmlElemEndPoint.style.left = `${pScreenEnd.x - pointSize / 2}px`;
this.htmlElemEndPoint.style.borderRadius = `${pointSize}px`;
this.htmlElemEndPoint.style.border = this.style.border;
this.htmlElemEndPoint.style.background = this.style.background;
this.htmlElemEndPoint.style.zIndex = "2";
this.htmlElemEndPoint.style.width = `${pointSize}px`;
this.htmlElemEndPoint.style.height = `${pointSize}px`;
this.htmlElemEndPoint.style.boxShadow = this.style.boxShadow;
} else {
this.htmlElemEndPoint.style.display = "none";
}
}
if (this.endPoint && this.startPoint) {
const point1 = worldToScreen(this.startPoint, this.moduleInstance, this.viewer);
const point2 = worldToScreen(this.endPoint, this.moduleInstance, this.viewer);
const {p1: p1, p2: p2, angle: angle, width: width} = getDataForDrawLineWithFixed(point1, point2, rect.width, rect.height);
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const height = this.lineThickness;
if (isInsideRect(p1, rect.width, rect.height) && isInsideRect(p2, rect.width, rect.height)) {
this.htmlElemLine = createHtmlElementIfNeed(this.htmlElemLine, this.targetElement, "ruler-line");
this.htmlElemLine.style.display = "block";
this.htmlElemLine.style.cursor = "pointer";
this.htmlElemLine.style.position = "absolute";
this.htmlElemLine.style.top = `${p1.y}px`;
this.htmlElemLine.style.left = `${p1.x}px`;
this.htmlElemLine.style.width = `${width}px`;
this.htmlElemLine.style.transform = `rotate(${angle}deg)`;
this.htmlElemLine.style.transformOrigin = `0px ${height / 2}px`;
this.htmlElemLine.style.boxShadow = this.style.boxShadow;
this.htmlElemLine.style.border = "none";
this.htmlElemLine.style.background = this.style.background;
this.htmlElemLine.style.zIndex = "1";
this.htmlElemLine.style.height = `${height}px`;
const distance = `${this.getDistance()} ${this.unit}`;
const pX = p1.x + dx / 2;
const pY = p1.y + dy / 2;
const widthTitle = distance.length * 10;
this.htmlElemTitle = createHtmlElementIfNeed(this.htmlElemTitle, this.targetElement, "ruler-value");
this.htmlElemTitle.style.display = "block";
this.htmlElemTitle.style.cursor = "pointer";
this.htmlElemTitle.style.font = "10px";
this.htmlElemTitle.style.color = "white";
this.htmlElemTitle.style.position = "Absolute";
this.htmlElemTitle.style.top = `${pY}px`;
this.htmlElemTitle.style.left = `${pX - widthTitle / 2}px`;
this.htmlElemTitle.style.width = `${widthTitle}px`;
this.htmlElemTitle.style.transformOrigin = "0px 0px";
this.htmlElemTitle.style.borderRadius = "5px";
this.htmlElemTitle.style.boxShadow = this.style.boxShadow;
this.htmlElemTitle.style.border = "none";
this.htmlElemTitle.style.background = this.style.background;
this.htmlElemTitle.style.zIndex = "3";
this.htmlElemTitle.style.padding = "2px";
this.htmlElemTitle.style.textAlign = "center";
this.htmlElemTitle.innerHTML = `${distance}`;
} else {
this.htmlElemLine.style.display = "none";
this.htmlElemTitle.style.display = "none";
}
}
}
getDistance() {
let distance = getDistance(this.startPoint, this.endPoint, this.moduleInstance);
if (Math.abs(this.scale - 1) > 1e-4) {
distance = (distance / this.scale).toFixed(2);
}
return distance;
}
setStartPoint(gePoint) {
this.startPoint = gePoint;
this.drawMeasureLine();
}
setEndPoint(gePoint, isFinish) {
this.isFinishDraw = isFinish === undefined ? true : isFinish;
this.endPoint = gePoint;
this.drawMeasureLine();
}
update() {
this.drawMeasureLine();
}
setSize(size) {
this.size = size;
this.drawMeasureLine();
}
clear() {
this.endPoint = null;
this.startPoint = null;
this.htmlElemStartPoint = destroyHtmlElement(this.htmlElemStartPoint, this.targetElement);
this.htmlElemEndPoint = destroyHtmlElement(this.htmlElemEndPoint, this.targetElement);
this.htmlElemLine = destroyHtmlElement(this.htmlElemLine, this.targetElement);
this.htmlElemTitle = destroyHtmlElement(this.htmlElemTitle, this.targetElement);
}
setUnit(unit) {
this.unit = unit;
this.drawMeasureLine();
}
setConversionFactor(scale) {
this.scale = scale;
this.drawMeasureLine();
}
setStyle(style) {
this.style = style;
this.drawMeasureLine();
}
setSelectionReactor(reactor) {
onSetCallback(this.htmlElemStartPoint, reactor ? reactor.onStartPoint : null);
onSetCallback(this.htmlElemEndPoint, reactor ? reactor.onEndPoint : null);
onSetCallback(this.htmlElemTitle, reactor ? reactor.onTitle : null);
}
setSelectability(enable) {
onSetSelectivity(this.htmlElemStartPoint, enable);
onSetSelectivity(this.htmlElemEndPoint, enable);
onSetSelectivity(this.htmlElemLine, enable);
onSetSelectivity(this.htmlElemTitle, enable);
}
}
function renameUnit(table, unit) {
return table[unit] || unit;
}
class MeasureLineDragger extends OdBaseDragger {
constructor(subject) {
var _a;
super(subject);
this.lineThickness = 2;
this.press = false;
this.gripingRadius = 5;
this.firstPoint = null;
this.secondPoint = null;
this.renameUnitTable = {
Millimeters: "mm",
Centimeters: "cm",
Meters: "m",
Feet: "ft",
Inches: "in",
Yards: "yd",
Kilometers: "km",
Miles: "mi",
Micrometers: "µm",
MicroInches: "µin",
Default: "unit"
};
this.items = [];
this.canvasEvents.push("resize");
this.oldRulerUnit = (_a = subject.options.rulerUnit) !== null && _a !== undefined ? _a : "Default";
this.optionsChange = this.optionsChange.bind(this);
}
initialize() {
super.initialize();
this.m_overlayElement = document.createElement("div");
this.m_overlayElement.style.background = "rgba(0,0,0,0)";
this.m_overlayElement.style.position = "fixed";
this.m_overlayElement.style.zIndex = "1";
this.m_overlayElement.style.pointerEvents = "none";
document.body.appendChild(this.m_overlayElement);
this.subject.addEventListener("optionschange", this.optionsChange);
this.resize();
}
dispose() {
super.dispose();
this.m_overlayElement.remove();
this.subject.removeEventListener("optionschange", this.optionsChange);
}
updatePreview() {
this.items.forEach((item => item.update()));
}
resize() {
const rect = this.m_module.canvas.getBoundingClientRect();
this.m_overlayElement.style.top = `${rect.top}px`;
this.m_overlayElement.style.left = `${rect.left}px`;
this.m_overlayElement.style.width = `${rect.width}px`;
this.m_overlayElement.style.height = `${rect.height}px`;
}
getSnapPointRadius() {
const view = this.getViewer().activeView;
const corners = view.viewDcCorners();
const pt1 = corners.lowerLeft;
const pt2 = corners.upperRight;
pt2[0] -= pt1[0];
pt2[1] -= pt1[1];
return Math.min(pt2[0], pt2[1]) / 120;
}
start(x, y) {
this.createNewMeasureIfNeed();
const point = this.getViewer().getSnapPoint(x, y, this.gripingRadius);
if (point) {
this.firstPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
}
}
drag(x, y) {
this.createNewMeasureIfNeed();
const point = this.getViewer().getSnapPoint(x, y, this.gripingRadius);
if (this.isDragging) {
if (point) {
if (this.firstPoint) {
this.secondPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
this.previewMeasureLine.setEndPoint(this.secondPoint, true);
} else {
this.firstPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
}
} else {
this.secondPoint = null;
this.previewMeasureLine.clear();
this.previewMeasureLine.setStartPoint(this.firstPoint);
this.previewMeasureLine.setEndPoint(this.getViewer().screenToWorld(x, y), false);
}
} else {
if (point) {
this.previewMeasureLine.setStartPoint(point);
} else {
this.previewMeasureLine.clear();
}
}
}
end() {
if (this.firstPoint && this.secondPoint) {
const newLineMeasure = this.createMeasureLine();
newLineMeasure.setStartPoint(this.firstPoint);
newLineMeasure.setEndPoint(this.secondPoint, true);
}
this.firstPoint = null;
this.secondPoint = null;
this.previewMeasureLine.clear();
}
createNewMeasureIfNeed() {
if (!this.previewMeasureLine) {
this.previewMeasureLine = this.createMeasureLine();
}
}
createMeasureLine() {
const viewer = this.m_module.getViewer();
const item = new MeasureLineItem(this.m_overlayElement, viewer, this.m_module);
item.lineThickness = this.lineThickness || item.lineThickness;
const isDefaultUnit = !this.subject.options.rulerUnit || this.subject.options.rulerUnit === "Default";
item.setUnit(renameUnit(this.renameUnitTable, isDefaultUnit ? viewer.getUnit() : this.subject.options.rulerUnit));
if (!isDefaultUnit) {
const fromUnit = this.getKUnitByName(viewer.getUnit());
const toUnit = this.getKUnitByName(this.subject.options.rulerUnit);
const multiplier = viewer.getUnitsConversionCoef(fromUnit, toUnit);
this.conversionFactor = 1 / multiplier;
item.setConversionFactor(this.conversionFactor);
} else {
item.setConversionFactor(1);
}
this.items.push(item);
return item;
}
optionsChange(event) {
var _a;
const options = event.data;
const toUnitName = (_a = options.rulerUnit) !== null && _a !== undefined ? _a : "Default";
if (this.oldRulerUnit === toUnitName) return;
this.oldRulerUnit = toUnitName;
const drawingUnit = this.m_module.getViewer().getUnit();
const eToUnit = this.getKUnitByName(toUnitName);
const eFromUnit = this.getKUnitByName(drawingUnit);
this.items.forEach((item => {
if (toUnitName === "Default") {
item.setUnit(renameUnit(this.renameUnitTable, drawingUnit));
item.setConversionFactor(1);
} else {
item.setUnit(renameUnit(this.renameUnitTable, toUnitName));
const multiplier = this.m_module.getViewer().getUnitsConversionCoef(eFromUnit, eToUnit);
this.conversionFactor = 1 / multiplier;
item.setConversionFactor(this.conversionFactor);
}
}));
}
getKUnitByName(unitName) {
let eUnit = this.m_module.Units.kUserDefined;
switch (unitName) {
case "Millimeters":
eUnit = this.m_module.Units.kMillimeters;
break;
case "Centimeters":
eUnit = this.m_module.Units.kCentimeters;
break;
case "Meters":
eUnit = this.m_module.Units.kMeters;
break;
case "Feet":
eUnit = this.m_module.Units.kFeet;
break;
case "Inches":
eUnit = this.m_module.Units.kInches;
break;
case "Yards":
eUnit = this.m_module.Units.kYards;
break;
case "Kilometers":
eUnit = this.m_module.Units.kKilometers;
break;
case "Miles":
eUnit = this.m_module.Units.kMiles;
break;
case "Micrometers":
eUnit = this.m_module.Units.kMicrometers;
break;
case "MicroInches":
eUnit = this.m_module.Units.kMicroInches;
break;
}
return eUnit;
}
}
const FocalLengthConst = 42;
const calcFocalLength = (lensLength, fieldWidth, fieldHeight) => lensLength / FocalLengthConst * Math.sqrt(fieldWidth * fieldWidth + fieldHeight * fieldHeight);
class OdaWalkDragger extends OdBaseDragger {
constructor(subject) {
super(subject);
this.viewer = undefined;
this.multiplier = 5;
this.speed = 1;
this.keyPressMap = new Set;
this.keydown = this.keydown.bind(this);
this.keyup = this.keyup.bind(this);
this.lastFrameTS = 0;
this.animationId = undefined;
this.processMovement = this.processMovement.bind(this);
this.deltaAngle = Math.PI / 3600;
this.autoSelect = true;
}
initialize() {
super.initialize();
this.viewer = this.getViewer();
window.addEventListener("keydown", this.keydown, false);
window.addEventListener("keyup", this.keyup, false);
this.oldWCSEnableValue = this.viewer.getEnableWCS();
this.viewer.setEnableWCS(false);
const view = this.viewer.activeView;
const maxDimension = this.getMaxDimension(view);
this.speed = maxDimension / 3e4;
this.subject.emitEvent({
type: "walkstart"
});
this.viewParams = this.getViewParams();
this.setViewParams(this.viewParams);
const model = this.viewer.getActiveModel();
this.cameraId = model.appendCamera("Camera0");
this.setupCamera(view);
model.delete();
this.cameraWalker = new this.m_module.OdTvCameraWalker;
this.cameraWalker.setCamera(this.cameraId);
this.subject.update();
this.enableZoomWheelPreviousValue = this.subject.options.enableZoomWheel;
this.subject.options.enableZoomWheel = false;
}
dispose() {
var _a;
this.oldWCSEnableValue = this.oldWCSEnableValue !== undefined ? this.oldWCSEnableValue : this.subject.options.showWCS;
this.viewer.setEnableWCS(this.oldWCSEnableValue);
super.dispose();
this.keyPressMap.clear();
window.removeEventListener("keydown", this.keydown);
window.removeEventListener("keyup", this.keyup);
if (this.animationId) {
window.cancelAnimationFrame(this.animationId);
this.animationId = undefined;
}
if (this.cameraId) {
const model = this.viewer.getActiveModel();
model.removeEntity(this.cameraId);
model.delete();
(_a = this.cameraWalker) === null || _a === undefined ? undefined : _a.delete();
}
if (this.viewParams) {
this.setViewParams(this.viewParams);
const avp = this.viewer.activeView;
avp.delete();
}
this.subject.update(true);
this.subject.options.enableZoomWheel = this.enableZoomWheelPreviousValue;
}
keydown(ev) {
switch (ev.code) {
case "NumpadSubtract":
case "Minus":
if (this.multiplier > 1) {
this.multiplier = this.multiplier - 1;
this.subject.emitEvent({
type: "walkspeedchange",
data: this.multiplier
});
}
break;
case "NumpadAdd":
case "Equal":
if (this.multiplier < 10) {
this.multiplier = this.multiplier + 1;
this.subject.emitEvent({
type: "walkspeedchange",
data: this.multiplier
});
}
break;
case "KeyW":
case "KeyA":
case "KeyS":
case "KeyD":
case "KeyQ":
case "KeyE":
this.keyPressMap.add(ev.code);
if (!this.animationId) this.processMovement(0);
break;
}
}
keyup(ev) {
this.keyPressMap.delete(ev.code);
if (this.keyPressMap.size < 1 && this.animationId) {
window.cancelAnimationFrame(this.animationId);
this.animationId = undefined;
this.lastFrameTS = 0;
}
}
processMovement(timestamp) {
this.animationId = requestAnimationFrame(this.processMovement);
if (this.lastFrameTS !== 0) {
const deltaTS = timestamp - this.lastFrameTS;
const currentDelta = this.multiplier * deltaTS * this.speed;
for (const keyCode of this.keyPressMap) {
switch (keyCode) {
case "KeyW":
this.cameraWalker.moveForward(currentDelta);
break;
case "KeyS":
this.cameraWalker.moveBackward(currentDelta);
break;
case "KeyA":
this.cameraWalker.moveLeft(currentDelta);
break;
case "KeyD":
this.cameraWalker.moveRight(currentDelta);
break;
case "KeyQ":
this.cameraWalker.moveUp(currentDelta);
break;
case "KeyE":
this.cameraWalker.moveDown(currentDelta);
break;
}
}
this.subject.update();
}
this.lastFrameTS = timestamp;
}
start(x, y) {
this.dragPosition = {
x: x,
y: y
};
}
drag(x, y) {
if (this.cameraId && this.isDragging) {
const dltX = x - this.dragPosition.x;
const dltY = y - this.dragPosition.y;
this.dragPosition = {
x: x,
y: y
};
if (dltX !== 0) this.turnLeft(-dltX * this.deltaAngle);
if (dltY !== 0) this.cameraWalker.turnDown(dltY * this.deltaAngle);
this.subject.update();
}
}
turnLeft(angle) {
const pCamera = this.cameraWalker.camera().openObjectAsCamera();
const dir = this.toVector(pCamera.direction());
const up = this.toVector(pCamera.upVector());
const pos = pCamera.position();
const rotMatrix = this.createMatrix3d();
const zAxisVector = [ 0, 0, 1 ];
rotMatrix.setToRotation(angle, zAxisVector, pos);
dir.transformBy(rotMatrix);
up.transformBy(rotMatrix);
pCamera.setupCameraByDirection(pos, dir.toArray(), up.toArray());
pCamera.delete();
}
setupCamera(view) {
const pCamera = this.cameraId.openObjectAsCamera();
const target = view.viewTarget;
pCamera.setDisplayGlyph(false);
pCamera.setDisplayTarget(false);
pCamera.setAutoAdjust(true);
pCamera.setupCamera(view.viewPosition, target, view.upVector);
pCamera.setNearClip(false, 1);
pCamera.setFarClip(false, 0);
pCamera.setViewParameters(view.viewFieldWidth, view.viewFieldHeight, true);
const focalL = calcFocalLength(view.lensLength, view.viewFieldWidth, view.viewFieldHeight);
const pTarget = this.toPoint(view.viewTarget);
const viewDir = this.toPoint(view.viewPosition);
const viewDirSub = viewDir.sub(pTarget);
const viewDirVec = viewDirSub.asVector();
const viewDirVecNormal = viewDirVec.normalize();
const geViewDir = this.toGeVector(viewDirVecNormal);
const newGeViewDir = [ geViewDir[0] * focalL, geViewDir[1] * focalL, geViewDir[2] * focalL ];
const pTarget2 = this.toPoint(view.viewTarget);
const newGeViewDirPt = this.toPoint(newGeViewDir);
const newPos = pTarget2.add(newGeViewDirPt);
pCamera.setupCamera(this.toGePoint(newPos), view.viewTarget, view.upVector);
this.deleteAll([ pTarget, viewDir, viewDirSub, viewDirVec, viewDirVecNormal, pTarget2, newGeViewDirPt, newPos ]);
pCamera.assignView(view);
pCamera.delete();
}
getMaxDimension(view) {
const [xmax, ymax, zmax] = view.sceneExtents.max();
const [xmin, ymin, zmin] = view.sceneExtents.min();
const volume = [ xmax - xmin, ymax - ymin, zmax - zmin ];
return Math.max(...volume);
}
}
class OdBaseCuttingPlaneDragger extends OdBaseDragger {
constructor(subject) {
super(subject);
this.press = false;
const ext = this.getViewer().getActiveExtents();
const min = ext.min();
const max = ext.max();
this.m_size_x = Math.abs(max[0] - min[0]) / 2;
this.m_size_y = Math.abs(max[1] - min[1]) / 2;
this.m_size_z = Math.abs(max[2] - min[2]) / 2;
this.m_center = this.toPoint(ext.center());
this.m_normal = this.createNormal();
const avp = this.getViewer().activeView;
const plane = this.createPlane();
plane.set(this.toGePoint(this.m_center), this.m_normal);
avp.addCuttingPlane(plane);
this.index = avp.numCuttingPlanes() - 1;
const {red: red, green: green, blue: blue} = this.subject.options.cuttingPlaneFillColor;
avp.setEnableCuttingPlaneFill(true, red, green, blue);
avp.setCuttingPlaneFillPatternEnabled(true, this.m_module.CuttingPlaneFillStyle.kHorizontalBars, 0, 0, 0);
this.m_model = this.getModel();
this.createPreview();
this.deleteAll([ ext, avp, plane ]);
}
dispose() {
super.dispose();
if (this.m_entity) {
this.m_model.removeEntity(this.m_entity);
this.deleteAll([ this.m_model, this.m_entity, this.planePreview, this.m_center ]);
this.m_entity = null;
this.planePreview = null;
this.subject.update();
}
}
createNormal() {
return [ 0, 0, 0 ];
}
handleDelta(delta) {
return delta;
}
getPlanePreviewCoordinate() {
return [];
}
start(x, y) {
this.press = true;
this.m_last = this.screenToWorld(x, y);
this.m_click = {
x: x,
y: y
};
}
drag(x, y) {
if (this.press) {
const point = this.screenToWorld(x, y);
const delta = this.handleDelta(point.sub(this.m_last));
const oldCenter = this.m_center;
this.m_center = oldCenter.add(delta);
const oldLast = this.m_last;
this.m_last = point;
const avp = this.getViewer().activeView;
const plane = this.createPlane();
const newPlane = plane.set(this.toGePoint(this.m_center), this.m_normal);
const newCutting = avp.updateCuttingPlane(this.index, plane);
this.drawPreview();
this.deleteAll([ avp, plane, oldCenter, delta, oldLast, newPlane, newCutting ]);
const device = this.getViewer().getActiveDevice();
device.invalidate(device.getSize());
}
}
end(x, y) {
this.press = false;
if (x === this.m_click.x && y === this.m_click.y) {
this.m_normal = [ this.m_normal[0] * -1, this.m_normal[1] * -1, this.m_normal[2] * -1 ];
const avp = this.getViewer().activeView;
const plane = this.createPlane();
plane.set(this.toGePoint(this.m_center), this.m_normal);
avp.updateCuttingPlane(this.index, plane);
this.deleteAll([ avp, plane, this.m_last ]);
const device = this.getViewer().getActiveDevice();
device.invalidate(device.getSize());
}
}
createPreview() {
this.m_entity = this.m_model.appendEntity("&CuttingPlanePreview");
const GeometryTypes = this.m_module.GeometryTypes;
const transparencyDef = new this.m_module.OdTvTransparencyDef;
const colorDef = new this.m_module.OdTvColorDef(112, 112, 112);
transparencyDef.setValue(.9);
const entityPtr = this.m_entity.openObject();
entityPtr.setColor(colorDef, GeometryTypes.kFaces.value);
colorDef.setColor(112, 112, 112);
entityPtr.setColor(colorDef, GeometryTypes.kEdges.value);
entityPtr.setLineWeight(5);
entityPtr.setTransparency(transparencyDef, GeometryTypes.kFaces);
transparencyDef.setValue(1);
entityPtr.setTransparency(transparencyDef, GeometryTypes.kEdges);
this.planePreview = entityPtr.appendPolygon(this.getPlanePreviewCoordinate());
const polygonPtr = this.planePreview.openAsPolygon();
polygonPtr.setFilled(true);
this.deleteAll([ transparencyDef, colorDef, entityPtr, polygonPtr, GeometryTypes ]);
this.subject.syncOverlay();
}
drawPreview() {
const polygonPtr = this.planePreview.openAsPolygon();
polygonPtr.setPoints(this.getPlanePreviewCoordinate());
this.deleteAll([ polygonPtr ]);
this.subject.syncOverlay();
}
}
class OdCuttingPlaneXAxisDragger extends OdBaseCuttingPlaneDragger {
createNormal() {
return [ 1, 0, 0 ];
}
handleDelta(delta) {
delta.y = 0;
delta.z = 0;
return delta;
}
getPlanePreviewCoordinate() {
return [ this.m_center.x, this.m_center.y - this.m_size_y, this.m_center.z - this.m_size_z, this.m_center.x, this.m_center.y + this.m_size_y, this.m_center.z - this.m_size_z, this.m_center.x, this.m_center.y + this.m_size_y, this.m_center.z + this.m_size_z, this.m_center.x, this.m_center.y - this.m_size_y, this.m_center.z + this.m_size_z ];
}
}
class OdCuttingPlaneYAxisDragger extends OdBaseCuttingPlaneDragger {
createNormal() {
return [ 0, 1, 0 ];
}
handleDelta(delta) {
delta.x = 0;
delta.z = 0;
return delta;
}
getPlanePreviewCoordinate() {
return [ this.m_center.x - this.m_size_x, this.m_center.y, this.m_center.z - this.m_size_z, this.m_center.x + this.m_size_x, this.m_center.y, this.m_center.z - this.m_size_z, this.m_center.x + this.m_size_x, this.m_center.y, this.m_center.z + this.m_size_z, this.m_center.x - this.m_size_x, this.m_center.y, this.m_center.z + this.m_size_z ];
}
}
class OdCuttingPlaneZAxisDragger extends OdBaseCuttingPlaneDragger {
createNormal() {
return [ 0, 0, 1 ];
}
handleDelta(delta) {
delta.x = 0;
delta.y = 0;
return delta;
}
getPlanePreviewCoordinate() {
return [ this.m_center.x - this.m_size_x, this.m_center.y - this.m_size_y, this.m_center.z, this.m_center.x + this.m_size_x, this.m_center.y - this.m_size_y, this.m_center.z, this.m_center.x + this.m_size_x, this.m_center.y + this.m_size_y, this.m_center.z, this.m_center.x - this.m_size_x, this.m_center.y + this.m_size_y, this.m_center.z ];
}
}
class OrbitAction {
constructor(m_module, subject, beginInteractivity, endInteractivity) {
this._m_module = m_module;
this._subject = subject;
this._beginInteractivity = beginInteractivity;
this._endInteractivity = endInteractivity;
}
beginAction(x, y) {
this.m_viewCenter = this.getCenter();
this.m_startPoint = {
x: x,
y: y
};
const view = this.getViewer().activeView;
view.delete();
this._beginInteractivity();
}
action(x, y) {
var _a, _b;
const view = this.getViewer().activeView;
const corners = view.vportRect;
const size = Math.max(Math.abs(corners[2] - corners[0]), Math.abs(corners[3] - corners[1]));
const distX = (this.m_startPoint.x - x) * Math.PI / size;
const distY = (this.m_startPoint.y - y) * Math.PI / size;
this.m_startPoint.x = x;
this.m_startPoint.y = y;
const xOrbit = distY;
const yOrbit = distX;
const viewParams = {
position: view.viewPosition,
target: view.viewTarget,
upVector: view.upVector,
viewFieldWidth: view.viewFieldWidth,
viewFieldHeight: view.viewFieldHeight,
perspective: view.perspective
};
view.delete();
const sideVector = this.getSideVector(viewParams);
if (xOrbit !== 0) {
this.calculateXOrbit(viewParams, -xOrbit, sideVector);
}
if (yOrbit !== 0) {
this.calculateYOrbit(viewParams, yOrbit, sideVector);
}
sideVector.delete();
const extView = this.getViewer().getActiveTvExtendedView();
extView.setView(viewParams.position, viewParams.target, viewParams.upVector, viewParams.viewFieldWidth, viewParams.viewFieldHeight, viewParams.perspective);
extView.delete();
(_b = (_a = this._subject.activeDragger()) === null || _a === undefined ? undefined : _a.updatePreview) === null || _b === undefined ? undefined : _b.call(_a);
}
endAction() {
this._endInteractivity();
}
getSideVector(viewParams) {
const pUpV = this.toVector(viewParams.upVector);
const pTarget = this.toPoint(viewParams.target);
const pPosition = this.toPoint(viewParams.position);
const direct = pTarget.sub(pPosition);
const vDirect = direct.asVector();
const vCross = pUpV.crossProduct(vDirect);
const sideVector = vCross.normalize();
this.deleteAll([ direct, pUpV, pTarget, pPosition, vDirect, vCross ]);
return sideVector;
}
calculateXOrbit(viewParams, delta, sideVector) {
{
const pPoint = this.toPoint(viewParams.position);
const pCenter = this.toPoint(this.m_viewCenter);
const rotatePoint = pPoint.rotateByBasePoint(delta, sideVector, pCenter);
viewParams.position = rotatePoint.toArray();
this.deleteAll([ pPoint, pCenter, rotatePoint ]);
}
{
const pTarget = this.toPoint(viewParams.target);
const pCenter = this.toPoint(this.m_viewCenter);
const rotatePoint = pTarget.rotateByBasePoint(delta, sideVector, pCenter);
viewParams.target = rotatePoint.toArray();
this.deleteAll([ pTarget, pCenter, rotatePoint ]);
}
{
const pPoint = this.toPoint(viewParams.position);
const pTarget = this.toPoint(viewParams.target);
const pCenter = this.toPoint(this.m_viewCenter);
const pUp = pTarget.sub(pPoint);
const vUp = pUp.asVector();
const crossProduct = vUp.crossProduct(sideVector);
const crossProductNormal = crossProduct.normalize();
viewParams.upVector = crossProductNormal.toArray();
this.deleteAll([ pPoint, pTarget, pCenter, pUp, vUp, crossProduct, crossProductNormal ]);
}
}
calculateYOrbit(viewParams, delta, sideVector) {
{
const pPoint = this.toPoint(viewParams.position);
const pCenter = this.toPoint(this.m_viewCenter);
const zAxis = this.toVector(this._m_module.Vector3d.kZAxis);
const rotatePoint = pPoint.rotateByBasePoint(delta, zAxis, pCenter);
viewParams.position = rotatePoint.toArray();
this.deleteAll([ zAxis, pPoint, pCenter, rotatePoint ]);
}
{
const pTarget = this.toPoint(viewParams.target);
const pCenter = this.toPoint(this.m_viewCenter);
const zAxis = this.toVector(this._m_module.Vector3d.kZAxis);
const rotatePoint = pTarget.rotateByBasePoint(delta, zAxis, pCenter);
viewParams.target = rotatePoint.toArray();
this.deleteAll([ zAxis, pTarget, pCenter, rotatePoint ]);
}
{
const zAxis = this.toVector(this._m_module.Vector3d.kZAxis);
const pTarget = this.toPoint(viewParams.target);
const pPoint = this.toPoint(viewParams.position);
const side = sideVector.rotateBy(delta, zAxis);
const pUp = pTarget.sub(pPoint);
const vUp = pUp.asVector();
const cross = vUp.crossProduct(side);
const crossNormal = cross.normalize();
viewParams.upVector = crossNormal.toArray();
this.deleteAll([ zAxis, pTarget, pPoint, side, pUp, vUp, cross, crossNormal ]);
}
}
getCenter() {
const viewer = this.getViewer();
let center;
const pSet = viewer.getSelected();
if (!pSet.isNull() && pSet.numItems() !== 0) {
const itr = pSet.getIterator();
let ext, entId, extSelected;
for (;!itr.done(); itr.step()