@itwin/core-frontend
Version:
iTwin.js frontend components
247 lines • 11.5 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module LocatingElements
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TentativePoint = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const AccuSnap_1 = require("./AccuSnap");
const HitDetail_1 = require("./HitDetail");
const IModelApp_1 = require("./IModelApp");
const Tool_1 = require("./tools/Tool");
const ViewTool_1 = require("./tools/ViewTool");
/**
* @public
* @extensions
*/
class TentativePoint {
isActive = false;
currSnap;
tpHits;
get _hotDistanceInches() { return 0.21; }
_point = new core_geometry_1.Point3d();
_rawPoint = new core_geometry_1.Point3d();
_viewPoint = new core_geometry_1.Point3d();
_tentativePromise;
viewport;
onInitialized() { }
setHitList(list) { this.tpHits = list; }
/** @return true if the tentative point is currently active and snapped to an element. */
get isSnapped() { return undefined !== this.currSnap; }
/** @return The current snap path when TentativePoint.isSnapped or undefined. */
getCurrSnap() { return this.currSnap; }
getPoint() {
const snap = this.currSnap;
return !snap ? this._point : snap.adjustedPoint;
}
setPoint(point) {
this.setCurrSnap(undefined);
this.tpHits = undefined;
this._point.setFrom(point);
}
clear(doErase) {
if (doErase) {
this.removeTentative();
IModelApp_1.IModelApp.accuSnap.synchSnapMode();
}
IModelApp_1.IModelApp.accuSnap.destroy();
this.isActive = false;
this.setCurrSnap(undefined);
this.tpHits = undefined;
}
removeTentative() {
this._tentativePromise = undefined;
if (!this.isActive)
return;
IModelApp_1.IModelApp.accuSnap.erase();
if (this.getCurrSnap())
IModelApp_1.IModelApp.viewManager.invalidateDecorationsAllViews();
else
this.viewport.invalidateDecorations();
this.isActive = false;
}
setCurrSnap(newSnap) {
if (newSnap)
newSnap.setSnapPoint(newSnap.snapPoint, HitDetail_1.SnapHeat.InRange); // Reset adjustedPoint from pre-located snap and set SnapHeat...
this.currSnap = newSnap;
}
showTentative() {
if (this.isSnapped) {
IModelApp_1.IModelApp.viewManager.invalidateDecorationsAllViews();
IModelApp_1.IModelApp.accuSnap.displayToolTip(this._viewPoint, this.viewport, undefined);
}
else {
this.viewport.invalidateDecorations();
}
this.isActive = true;
}
getHitAndList(holder) {
const hit = this.currSnap;
if (hit) {
holder.setHitList(this.tpHits);
this.tpHits = undefined;
}
return hit;
}
onButtonEvent(ev) {
switch (ev.button) {
case Tool_1.BeButton.Data:
if (!ev.isDown)
return; // cleared on down...
break;
case Tool_1.BeButton.Reset:
if (ev.isDown)
return; // cleared on up...
break;
case Tool_1.BeButton.Middle:
return;
}
this.removeTentative();
IModelApp_1.IModelApp.accuSnap.synchSnapMode();
this.setCurrSnap(undefined);
this.tpHits = undefined;
}
decorate(context) {
const viewport = context.viewport;
if (!this.isActive || !viewport)
return;
const tpSize = Math.floor(viewport.pixelsPerInch * 0.4) + 0.5;
const toSizeOutline = tpSize + 1;
const position = context.viewport.worldToView(this._point);
position.x = Math.floor(position.x) + 0.5;
position.y = Math.floor(position.y) + 0.5;
const drawDecoration = (ctx) => {
ctx.beginPath();
ctx.strokeStyle = "rgba(0,0,0,.5)";
ctx.lineWidth = 3;
ctx.moveTo(-toSizeOutline, 0);
ctx.lineTo(toSizeOutline, 0);
ctx.moveTo(0, -toSizeOutline);
ctx.lineTo(0, toSizeOutline);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.lineWidth = 1;
if (!this.isSnapped)
ctx.setLineDash([4, 1]);
ctx.shadowColor = "black";
ctx.shadowBlur = 5;
ctx.moveTo(-tpSize, 0);
ctx.lineTo(tpSize, 0);
ctx.moveTo(0, -tpSize);
ctx.lineTo(0, tpSize);
ctx.stroke();
};
context.addCanvasDecoration({ position, drawDecoration });
}
async getSnap(newSearch) {
// Use next hit from previous search when using tentative to cycle through hits...
let thisHit = (!newSearch && undefined !== this.tpHits ? this.tpHits.getNextHit() : undefined);
// Use existing AccuSnap hit list if one exists...
if (undefined === thisHit) {
this.tpHits = undefined;
thisHit = IModelApp_1.IModelApp.accuSnap.getHitAndList(this);
}
if (undefined === thisHit) {
// search for elements around the current raw point (search should not be affected by locks!)
const aperture = (2.0 * this.viewport.pixelsFromInches(IModelApp_1.IModelApp.locateManager.apertureInches) / 2.0) + 1.5;
const options = IModelApp_1.IModelApp.locateManager.options.clone(); // Copy to avoid changing out from under active Tool...
const picker = IModelApp_1.IModelApp.locateManager.picker;
options.hitSource = HitDetail_1.HitSource.TentativeSnap;
if (0 === picker.doPick(this.viewport, this._rawPoint, aperture, options))
return undefined;
this.tpHits = picker.getHitList(true);
thisHit = (undefined !== this.tpHits ? this.tpHits.getNextHit() : undefined);
}
else if (thisHit instanceof HitDetail_1.SnapDetail) {
// Make the current AccuSnap the TentativePoint snap...
return thisHit;
}
if (undefined === thisHit)
return undefined;
const snapModes = IModelApp_1.IModelApp.accuSnap.getActiveSnapModes(); // Get the list of point snap modes to consider
if (1 === snapModes.length && HitDetail_1.SnapMode.Intersection === snapModes[0])
snapModes.push(HitDetail_1.SnapMode.Nearest); // Add nearest when doing intersection by itself to support finding extended intersections...
const thisSnap = await AccuSnap_1.AccuSnap.requestSnap(thisHit, snapModes, this._hotDistanceInches, IModelApp_1.IModelApp.accuSnap.keypointDivisor, this.tpHits);
if (undefined !== thisSnap)
IModelApp_1.IModelApp.accuDraw.onSnap(thisSnap); // AccuDraw can adjust nearest snap to intersection of circle (polar distance lock) or line (axis lock) with snapped to curve...
return thisSnap;
}
static arePointsCloseEnough(pt1, pt2, pixelDistance) { return pt1.distance(pt2) < (pixelDistance + 1.5); }
process(ev) {
if (undefined !== this._tentativePromise)
return;
const currTool = IModelApp_1.IModelApp.toolAdmin.viewTool;
if (currTool && currTool.inDynamicUpdate)
return; // trying to tentative snap while view is changing isn't useful...
const wasActive = this.isActive;
this.removeTentative(); // remove the TP cross if it is already on the screen
const lastPtView = this._viewPoint.clone();
this.viewport = ev.viewport;
this._point.setFrom(ev.point);
this._rawPoint.setFrom(ev.rawPoint);
this._viewPoint.setFrom(ev.viewPoint);
const newSearch = (!this.isSnapped || !TentativePoint.arePointsCloseEnough(lastPtView, this._viewPoint, this.viewport.pixelsFromInches(IModelApp_1.IModelApp.locateManager.apertureInches)));
const promise = this.getSnap(newSearch);
this._tentativePromise = promise;
promise.then((newSnap) => {
// Ignore response if we're no longer interested in this tentative.
if (this._tentativePromise === promise) {
this._tentativePromise = undefined;
this.setCurrSnap(newSnap); // Adopt the snap as current
IModelApp_1.IModelApp.accuSnap.clear(); // make sure there's no AccuSnap active after a tentative point (otherwise we continually snap to it).
if (this.isSnapped)
this._point.setFrom(this.currSnap.snapPoint);
else if (wasActive && newSearch)
this._point.setFrom(ev.rawPoint);
this.showTentative(); // show the TP cross
if (this.isSnapped) {
IModelApp_1.IModelApp.toolAdmin.adjustSnapPoint();
}
else if (IModelApp_1.IModelApp.accuDraw.isActive) {
const point = this.getPoint().clone();
const vp = ev.viewport;
if (vp.isSnapAdjustmentRequired) {
IModelApp_1.IModelApp.toolAdmin.adjustPointToACS(point, vp, false);
const hit = new HitDetail_1.HitDetail({
testPoint: point,
viewport: vp,
hitSource: HitDetail_1.HitSource.TentativeSnap,
hitPoint: point,
sourceId: "",
priority: HitDetail_1.HitPriority.Unknown,
distXY: 0,
distFraction: 0,
});
const snap = new HitDetail_1.SnapDetail(hit);
this.setCurrSnap(snap);
IModelApp_1.IModelApp.toolAdmin.adjustSnapPoint();
this.setPoint(this.getPoint());
}
else {
IModelApp_1.IModelApp.accuDraw.adjustPoint(point, vp, false);
const savePoint = point.clone();
IModelApp_1.IModelApp.toolAdmin.adjustPointToGrid(point, vp);
if (!point.isExactEqual(savePoint))
IModelApp_1.IModelApp.accuDraw.adjustPoint(point, vp, false);
this.setPoint(point);
}
}
else {
IModelApp_1.IModelApp.toolAdmin.adjustPoint(this.getPoint(), ev.viewport);
}
IModelApp_1.IModelApp.accuDraw.onTentative();
if (currTool && currTool instanceof ViewTool_1.ViewManip && currTool.viewHandles.hasHandle(ViewTool_1.ViewHandleType.TargetCenter))
currTool.updateTargetCenter(); // Change target center to tentative location...
else
IModelApp_1.IModelApp.toolAdmin.updateDynamics(undefined, undefined, true); // Don't wait for motion to update dynamics...
}
});
}
}
exports.TentativePoint = TentativePoint;
//# sourceMappingURL=TentativePoint.js.map