@itwin/editor-frontend 3.7.12 → 3.7.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/lib/cjs/CreateElementTool.d.ts +100 -100
  3. package/lib/cjs/CreateElementTool.js +327 -327
  4. package/lib/cjs/CreateElementTool.js.map +1 -1
  5. package/lib/cjs/DeleteElementsTool.d.ts +13 -13
  6. package/lib/cjs/DeleteElementsTool.js +38 -38
  7. package/lib/cjs/DeleteElementsTool.js.map +1 -1
  8. package/lib/cjs/EditTool.d.ts +38 -38
  9. package/lib/cjs/EditTool.js +81 -81
  10. package/lib/cjs/EditTool.js.map +1 -1
  11. package/lib/cjs/EditToolIpc.d.ts +18 -18
  12. package/lib/cjs/EditToolIpc.js +28 -28
  13. package/lib/cjs/EditToolIpc.js.map +1 -1
  14. package/lib/cjs/ElementGeometryTool.d.ts +147 -147
  15. package/lib/cjs/ElementGeometryTool.js +709 -709
  16. package/lib/cjs/ElementGeometryTool.js.map +1 -1
  17. package/lib/cjs/ModifyCurveTools.d.ts +139 -139
  18. package/lib/cjs/ModifyCurveTools.js +784 -784
  19. package/lib/cjs/ModifyCurveTools.js.map +1 -1
  20. package/lib/cjs/ModifyElementTool.d.ts +47 -47
  21. package/lib/cjs/ModifyElementTool.js +177 -177
  22. package/lib/cjs/ModifyElementTool.js.map +1 -1
  23. package/lib/cjs/ProjectLocation/ProjectExtentsDecoration.d.ts +135 -135
  24. package/lib/cjs/ProjectLocation/ProjectExtentsDecoration.js +822 -822
  25. package/lib/cjs/ProjectLocation/ProjectExtentsDecoration.js.map +1 -1
  26. package/lib/cjs/ProjectLocation/ProjectGeolocation.d.ts +135 -135
  27. package/lib/cjs/ProjectLocation/ProjectGeolocation.js +532 -532
  28. package/lib/cjs/ProjectLocation/ProjectGeolocation.js.map +1 -1
  29. package/lib/cjs/SketchTools.d.ts +304 -304
  30. package/lib/cjs/SketchTools.js +1705 -1705
  31. package/lib/cjs/SketchTools.js.map +1 -1
  32. package/lib/cjs/SolidModelingTools.d.ts +380 -380
  33. package/lib/cjs/SolidModelingTools.js +1462 -1462
  34. package/lib/cjs/SolidModelingTools.js.map +1 -1
  35. package/lib/cjs/SolidPrimitiveTools.d.ts +318 -318
  36. package/lib/cjs/SolidPrimitiveTools.js +1378 -1378
  37. package/lib/cjs/SolidPrimitiveTools.js.map +1 -1
  38. package/lib/cjs/TransformElementsTool.d.ts +164 -164
  39. package/lib/cjs/TransformElementsTool.js +652 -652
  40. package/lib/cjs/TransformElementsTool.js.map +1 -1
  41. package/lib/cjs/UndoRedoTool.d.ts +16 -16
  42. package/lib/cjs/UndoRedoTool.js +42 -42
  43. package/lib/cjs/UndoRedoTool.js.map +1 -1
  44. package/lib/cjs/editor-frontend.d.ts +17 -17
  45. package/lib/cjs/editor-frontend.js +33 -33
  46. package/lib/cjs/editor-frontend.js.map +1 -1
  47. package/lib/esm/CreateElementTool.d.ts +100 -100
  48. package/lib/esm/CreateElementTool.js +319 -319
  49. package/lib/esm/CreateElementTool.js.map +1 -1
  50. package/lib/esm/DeleteElementsTool.d.ts +13 -13
  51. package/lib/esm/DeleteElementsTool.js +34 -34
  52. package/lib/esm/DeleteElementsTool.js.map +1 -1
  53. package/lib/esm/EditTool.d.ts +38 -38
  54. package/lib/esm/EditTool.js +77 -77
  55. package/lib/esm/EditTool.js.map +1 -1
  56. package/lib/esm/EditToolIpc.d.ts +18 -18
  57. package/lib/esm/EditToolIpc.js +24 -24
  58. package/lib/esm/EditToolIpc.js.map +1 -1
  59. package/lib/esm/ElementGeometryTool.d.ts +147 -147
  60. package/lib/esm/ElementGeometryTool.js +701 -701
  61. package/lib/esm/ElementGeometryTool.js.map +1 -1
  62. package/lib/esm/ModifyCurveTools.d.ts +139 -139
  63. package/lib/esm/ModifyCurveTools.js +775 -775
  64. package/lib/esm/ModifyCurveTools.js.map +1 -1
  65. package/lib/esm/ModifyElementTool.d.ts +47 -47
  66. package/lib/esm/ModifyElementTool.js +172 -172
  67. package/lib/esm/ModifyElementTool.js.map +1 -1
  68. package/lib/esm/ProjectLocation/ProjectExtentsDecoration.d.ts +135 -135
  69. package/lib/esm/ProjectLocation/ProjectExtentsDecoration.js +814 -814
  70. package/lib/esm/ProjectLocation/ProjectExtentsDecoration.js.map +1 -1
  71. package/lib/esm/ProjectLocation/ProjectGeolocation.d.ts +135 -135
  72. package/lib/esm/ProjectLocation/ProjectGeolocation.js +526 -526
  73. package/lib/esm/ProjectLocation/ProjectGeolocation.js.map +1 -1
  74. package/lib/esm/SketchTools.d.ts +304 -304
  75. package/lib/esm/SketchTools.js +1695 -1695
  76. package/lib/esm/SketchTools.js.map +1 -1
  77. package/lib/esm/SolidModelingTools.d.ts +380 -380
  78. package/lib/esm/SolidModelingTools.js +1437 -1437
  79. package/lib/esm/SolidModelingTools.js.map +1 -1
  80. package/lib/esm/SolidPrimitiveTools.d.ts +318 -318
  81. package/lib/esm/SolidPrimitiveTools.js +1367 -1367
  82. package/lib/esm/SolidPrimitiveTools.js.map +1 -1
  83. package/lib/esm/TransformElementsTool.d.ts +164 -164
  84. package/lib/esm/TransformElementsTool.js +644 -644
  85. package/lib/esm/TransformElementsTool.js.map +1 -1
  86. package/lib/esm/UndoRedoTool.d.ts +16 -16
  87. package/lib/esm/UndoRedoTool.js +36 -36
  88. package/lib/esm/UndoRedoTool.js.map +1 -1
  89. package/lib/esm/editor-frontend.d.ts +17 -17
  90. package/lib/esm/editor-frontend.js +21 -21
  91. package/lib/esm/editor-frontend.js.map +1 -1
  92. package/lib/public/locales/en/Editor.json +490 -490
  93. package/package.json +15 -15
@@ -1,527 +1,527 @@
1
- /*---------------------------------------------------------------------------------------------
2
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
- * See LICENSE.md in the project root for license terms and full copyright notice.
4
- *--------------------------------------------------------------------------------------------*/
5
- /** @packageDocumentation
6
- * @module Editing
7
- */
8
- import { AccuDrawHintBuilder, AccuDrawShortcuts, AngleDescription, CoreTools, EventHandled, GraphicType, IModelApp, LengthDescription, PrimitiveTool, ToolAssistance, ToolAssistanceImage, ToolAssistanceInputMethod } from "@itwin/core-frontend";
9
- import { Angle, Matrix3d, Point3d, Ray3d, Vector3d } from "@itwin/core-geometry";
10
- import { Cartographic, ColorDef, LinePixels } from "@itwin/core-common";
11
- import { ProjectExtentsClipDecoration } from "./ProjectExtentsDecoration";
12
- import { DialogProperty } from "@itwin/appui-abstract";
13
- import { EditTools } from "../EditTool";
14
- function translatePrompt(key) {
15
- return EditTools.translate(`ProjectLocation:Prompts.${key}`);
16
- }
17
- function translateMessage(key) {
18
- return EditTools.translate(`ProjectLocation:Message.${key}`);
19
- }
20
- /** @internal */
21
- class LabelDecoration {
22
- constructor(worldLocation, label) {
23
- this.worldLocation = new Point3d();
24
- this.position = new Point3d();
25
- this.worldLocation.setFrom(worldLocation);
26
- this.label = label;
27
- }
28
- drawDecoration(ctx) {
29
- ctx.font = "16px san-serif";
30
- const labelHeight = ctx.measureText("M").width; // Close enough for border padding...
31
- const labelWidth = ctx.measureText(this.label).width + labelHeight;
32
- ctx.lineWidth = 1;
33
- ctx.strokeStyle = "white";
34
- ctx.fillStyle = "rgba(0,0,0,.4)";
35
- ctx.shadowColor = "black";
36
- ctx.shadowBlur = 10;
37
- ctx.fillRect(-(labelWidth / 2), -labelHeight, labelWidth, labelHeight * 2);
38
- ctx.strokeRect(-(labelWidth / 2), -labelHeight, labelWidth, labelHeight * 2);
39
- ctx.fillStyle = "white";
40
- ctx.shadowBlur = 0;
41
- ctx.textAlign = "center";
42
- ctx.textBaseline = "middle";
43
- ctx.fillText(this.label, 0, 0);
44
- }
45
- setPosition(vp) {
46
- vp.worldToView(this.worldLocation, this.position);
47
- this.position.y -= Math.floor(vp.pixelsFromInches(0.45)) + 0.5; // Offset from world location...
48
- return vp.viewRect.containsPoint(this.position);
49
- }
50
- addDecoration(context) {
51
- if (this.setPosition(context.viewport))
52
- context.addCanvasDecoration(this);
53
- }
54
- }
55
- /** Change or update geolocation for project.
56
- * To show tool settings for specifying lat/long, make sure formatting and parsing data are cached before the tool starts
57
- * by calling QuantityFormatter.onInitialized at app startup.
58
- * @beta
59
- */
60
- export class ProjectGeolocationPointTool extends PrimitiveTool {
61
- constructor() {
62
- super(...arguments);
63
- this._haveToolSettings = false;
64
- this._cartographicFromArgs = false;
65
- this._accept = false;
66
- this._scale = 1.0;
67
- }
68
- static get minArgs() { return 0; }
69
- static get maxArgs() { return 4; } // latitude, longitude, altitude, north direction...
70
- isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
71
- isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
72
- requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
73
- async onPostInstall() {
74
- await super.onPostInstall();
75
- this.setupAndPromptForNextAction();
76
- }
77
- async onCleanup() {
78
- await super.onCleanup();
79
- this.unsuspendDecorations();
80
- }
81
- async onRestartTool() { return this.exitTool(); }
82
- async onUnsuspend() { this.provideToolAssistance(); }
83
- get latitudeProperty() {
84
- if (!this._latitudeProperty)
85
- this._latitudeProperty = new DialogProperty(new AngleDescription("latitude", translateMessage("Latitude")), 0.0);
86
- return this._latitudeProperty;
87
- }
88
- get latitude() { return this.latitudeProperty.value; }
89
- set latitude(value) { this.latitudeProperty.value = value; }
90
- get longitudeProperty() {
91
- if (!this._longitudeProperty)
92
- this._longitudeProperty = new DialogProperty(new AngleDescription("longitude", translateMessage("Longitude")), 0.0);
93
- return this._longitudeProperty;
94
- }
95
- get longitude() { return this.longitudeProperty.value; }
96
- set longitude(value) { this.longitudeProperty.value = value; }
97
- get altitudeProperty() {
98
- if (!this._altitudeProperty)
99
- this._altitudeProperty = new DialogProperty(new LengthDescription("altitude", CoreTools.translate("Measure.Labels.Altitude")), 0.0);
100
- return this._altitudeProperty;
101
- }
102
- get altitude() { return this.altitudeProperty.value; }
103
- set altitude(value) { this.altitudeProperty.value = value; }
104
- get northProperty() {
105
- if (!this._northProperty)
106
- this._northProperty = new DialogProperty(new AngleDescription("north", translateMessage("North")), 0.0);
107
- return this._northProperty;
108
- }
109
- get north() { return this.northProperty.value; }
110
- set north(value) { this.northProperty.value = value; }
111
- syncToolSettingsCoordinates() {
112
- this.syncToolSettingsProperties([this.latitudeProperty.syncItem, this.longitudeProperty.syncItem, this.altitudeProperty.syncItem, this.northProperty.syncItem]);
113
- }
114
- async applyToolSettingPropertyChange(updatedValue) {
115
- return this.changeToolSettingPropertyValue(updatedValue);
116
- }
117
- supplyToolSettingsProperties() {
118
- this._haveToolSettings = true;
119
- const toolSettings = new Array();
120
- toolSettings.push(this.latitudeProperty.toDialogItem({ rowPriority: 1, columnIndex: 2 }));
121
- toolSettings.push(this.longitudeProperty.toDialogItem({ rowPriority: 2, columnIndex: 2 }));
122
- toolSettings.push(this.altitudeProperty.toDialogItem({ rowPriority: 3, columnIndex: 2 }));
123
- toolSettings.push(this.northProperty.toDialogItem({ rowPriority: 4, columnIndex: 2 }));
124
- return toolSettings;
125
- }
126
- provideToolAssistance() {
127
- const acceptMsg = CoreTools.translate(undefined === this._origin ? "ElementSet.Inputs.AcceptPoint" : "ElementSet.Inputs.Accept");
128
- const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
129
- const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyKnownLocation" : "ConfirmCoordinates"));
130
- const sections = [];
131
- const mouseInstructions = [];
132
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
133
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
134
- sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
135
- const touchInstructions = [];
136
- if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
137
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
138
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
139
- sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
140
- const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
141
- IModelApp.notifications.setToolAssistance(instructions);
142
- }
143
- setupAndPromptForNextAction() {
144
- IModelApp.accuSnap.enableSnap(undefined === this._origin);
145
- this.provideToolAssistance();
146
- }
147
- pulseDecoration() {
148
- if (!this._accept)
149
- return;
150
- const deco = ProjectExtentsClipDecoration.get();
151
- if (undefined === deco)
152
- return;
153
- this._scale += 0.1;
154
- if (this._scale > 1.6)
155
- this._scale = 1.0;
156
- deco.viewport.invalidateDecorations();
157
- setTimeout(() => this.pulseDecoration(), 100);
158
- }
159
- unsuspendDecorations() {
160
- const deco = ProjectExtentsClipDecoration.get();
161
- if (undefined !== deco)
162
- deco.suspendGeolocationDecorations = false;
163
- }
164
- decorate(context) {
165
- if (undefined === this._origin || !context.viewport.view.isSpatialView())
166
- return;
167
- const deco = ProjectExtentsClipDecoration.get();
168
- if (undefined === deco)
169
- return;
170
- deco.suspendGeolocationDecorations = true;
171
- deco.drawMonumentPoint(context, this._origin, this._scale);
172
- if (undefined !== this._labelDeco)
173
- this._labelDeco.addDecoration(context);
174
- }
175
- async onMouseMotion(ev) {
176
- if (undefined === ev.viewport || this._accept)
177
- return;
178
- this._origin = ev.point.clone();
179
- ev.viewport.invalidateDecorations();
180
- }
181
- async onResetButtonUp(_ev) {
182
- await this.onReinitialize(); // Calls onRestartTool to exit...
183
- return EventHandled.No;
184
- }
185
- acceptDefaultLocation() {
186
- // Greenwich is better default when testing control handle w/o tool settings support...
187
- this.latitude = Angle.createDegrees(51.4934).radians;
188
- this.longitude = Angle.createDegrees(0.0098).radians;
189
- this.altitude = 50.0;
190
- this.north = 0.0;
191
- }
192
- acceptKnownLocation(ev) {
193
- const deco = ProjectExtentsClipDecoration.get();
194
- if (undefined === deco)
195
- return;
196
- this._accept = true; // Require explicit accept to give user a chance to change values...
197
- this._origin = ev.point.clone();
198
- this._labelDeco = new LabelDecoration(this._origin, translatePrompt("SpecifyCoordinates"));
199
- if (!this._cartographicFromArgs) {
200
- if (this.iModel.isGeoLocated) {
201
- const cartographic = this.iModel.spatialToCartographicFromEcef(this._origin);
202
- this.latitude = cartographic.latitude;
203
- this.longitude = cartographic.longitude;
204
- this.altitude = cartographic.height;
205
- this.north = deco.getClockwiseAngleToNorth().radians;
206
- }
207
- else if (!this._haveToolSettings) {
208
- this.acceptDefaultLocation();
209
- }
210
- }
211
- this.syncToolSettingsCoordinates();
212
- this.pulseDecoration(); // Pulse to indicate that we are waiting for user input...
213
- this.setupAndPromptForNextAction();
214
- }
215
- async acceptCoordinates() {
216
- const deco = ProjectExtentsClipDecoration.get();
217
- if (undefined === deco)
218
- return;
219
- const origin = Cartographic.fromRadians({ longitude: this.longitude, latitude: this.latitude, height: this.altitude });
220
- if (!deco.updateEcefLocation(origin, this._origin, Angle.createRadians(this.north)))
221
- return;
222
- return this.onReinitialize(); // Calls onRestartTool to exit...
223
- }
224
- async onDataButtonDown(ev) {
225
- if (undefined === ev.viewport)
226
- return EventHandled.No; // Shouldn't really happen...
227
- const haveKnownLocation = this._accept;
228
- if (!haveKnownLocation)
229
- this.acceptKnownLocation(ev);
230
- const needAcceptPoint = !haveKnownLocation && this._haveToolSettings;
231
- if (!needAcceptPoint)
232
- await this.acceptCoordinates();
233
- return EventHandled.No;
234
- }
235
- async onInstall() {
236
- if (!ProjectExtentsClipDecoration.allowEcefLocationChange(false))
237
- return false;
238
- // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
239
- this.initializeToolSettingPropertyValues([this.latitudeProperty, this.longitudeProperty, this.altitudeProperty, this.northProperty]);
240
- return true;
241
- }
242
- /** The keyin takes the following arguments, all of which are optional:
243
- * - `latitude=number` Latitude of accept point in degrees.
244
- * - `longitude=number` Longitude of accept point in degrees.
245
- * - `altitude=number` Height above ellipsoid of accept point.
246
- * - `north=number` North direction in degrees of accept point.
247
- */
248
- async parseAndRun(...inputArgs) {
249
- for (const arg of inputArgs) {
250
- const parts = arg.split("=");
251
- if (2 !== parts.length)
252
- continue;
253
- if (parts[0].toLowerCase().startsWith("la")) {
254
- const latitude = Number.parseFloat(parts[1]);
255
- if (!Number.isNaN(latitude)) {
256
- this.saveToolSettingPropertyValue(this.latitudeProperty, { value: Angle.createDegrees(latitude).radians });
257
- this._cartographicFromArgs = true;
258
- }
259
- }
260
- else if (parts[0].toLowerCase().startsWith("lo")) {
261
- const longitude = Number.parseFloat(parts[1]);
262
- if (!Number.isNaN(longitude)) {
263
- this.saveToolSettingPropertyValue(this.longitudeProperty, { value: Angle.createDegrees(longitude).radians });
264
- this._cartographicFromArgs = true;
265
- }
266
- }
267
- else if (parts[0].toLowerCase().startsWith("al")) {
268
- const altitude = Number.parseFloat(parts[1]);
269
- if (!Number.isNaN(altitude)) {
270
- this.saveToolSettingPropertyValue(this.altitudeProperty, { value: altitude });
271
- this._cartographicFromArgs = true;
272
- }
273
- }
274
- else if (parts[0].toLowerCase().startsWith("no")) {
275
- const north = Number.parseFloat(parts[1]);
276
- if (!Number.isNaN(north)) {
277
- this.saveToolSettingPropertyValue(this.northProperty, { value: Angle.createDegrees(north).radians });
278
- this._cartographicFromArgs = true;
279
- }
280
- }
281
- }
282
- return this.run();
283
- }
284
- static async startTool() { return new ProjectGeolocationPointTool().run(); }
285
- }
286
- ProjectGeolocationPointTool.toolId = "ProjectLocation.Geolocation.Point";
287
- ProjectGeolocationPointTool.iconSpec = "icon-globe"; // <== Tool button should use whatever icon you have here...
288
- /** Change or update geolocation direction to true north.
289
- * @beta
290
- */
291
- export class ProjectGeolocationNorthTool extends PrimitiveTool {
292
- isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
293
- isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
294
- requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
295
- async onPostInstall() {
296
- await super.onPostInstall();
297
- this.setupAndPromptForNextAction();
298
- }
299
- async onCleanup() {
300
- await super.onCleanup();
301
- this.unsuspendDecorations();
302
- }
303
- async onRestartTool() { return this.exitTool(); }
304
- async onUnsuspend() { this.provideToolAssistance(); }
305
- provideToolAssistance() {
306
- const acceptMsg = CoreTools.translate("ElementSet.Inputs.AcceptPoint");
307
- const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
308
- const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyRefPoint" : "DefineAngle"));
309
- const sections = [];
310
- const mouseInstructions = [];
311
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
312
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
313
- sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
314
- const touchInstructions = [];
315
- if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
316
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
317
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
318
- sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
319
- const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
320
- IModelApp.notifications.setToolAssistance(instructions);
321
- }
322
- setupAndPromptForNextAction() {
323
- IModelApp.accuSnap.enableSnap(true);
324
- this.provideToolAssistance();
325
- if (undefined === this._origin)
326
- return;
327
- const hints = new AccuDrawHintBuilder();
328
- hints.setRotation(Matrix3d.createIdentity());
329
- hints.setOrigin(this._origin);
330
- hints.setModePolar();
331
- hints.setOriginFixed = true;
332
- hints.setLockZ = true;
333
- hints.sendHints();
334
- }
335
- getAdjustedPoint(ev) {
336
- if (undefined === this._origin)
337
- return undefined;
338
- return AccuDrawHintBuilder.projectPointToPlaneInView(ev.point, this._origin, Vector3d.unitZ(), ev.viewport, true);
339
- }
340
- unsuspendDecorations() {
341
- const deco = ProjectExtentsClipDecoration.get();
342
- if (undefined !== deco)
343
- deco.suspendGeolocationDecorations = false;
344
- }
345
- updateNorthVector(ev) {
346
- if (undefined === ev.viewport)
347
- return;
348
- if (undefined === this._northDir)
349
- this._northDir = Ray3d.create(ev.point, Vector3d.unitY());
350
- else
351
- this._northDir.origin.setFrom(undefined !== this._origin ? this._origin : ev.point);
352
- const dirPt = this.getAdjustedPoint(ev);
353
- if (undefined === dirPt)
354
- return;
355
- this._northDir.direction.setStartEnd(this._northDir.origin, dirPt);
356
- if (this._northDir.direction.magnitude() < 1.0e-6)
357
- this._northDir.direction.setFrom(Vector3d.unitY());
358
- this._northDir.direction.z = 0.0;
359
- this._northDir.direction.normalizeInPlace();
360
- }
361
- decorate(context) {
362
- if (undefined === this._northDir || !context.viewport.view.isSpatialView())
363
- return;
364
- const deco = ProjectExtentsClipDecoration.get();
365
- if (undefined === deco)
366
- return;
367
- deco.suspendGeolocationDecorations = true;
368
- deco.drawNorthArrow(context, this._northDir);
369
- }
370
- async onKeyTransition(wentDown, keyEvent) {
371
- if (EventHandled.Yes === await super.onKeyTransition(wentDown, keyEvent))
372
- return EventHandled.Yes;
373
- return (wentDown && await AccuDrawShortcuts.processShortcutKey(keyEvent)) ? EventHandled.Yes : EventHandled.No;
374
- }
375
- async onMouseMotion(ev) {
376
- if (undefined === ev.viewport)
377
- return;
378
- this.updateNorthVector(ev);
379
- ev.viewport.invalidateDecorations();
380
- }
381
- async onResetButtonUp(_ev) {
382
- await this.onReinitialize(); // Calls onRestartTool to exit...
383
- return EventHandled.No;
384
- }
385
- async onDataButtonDown(ev) {
386
- if (undefined === ev.viewport)
387
- return EventHandled.No; // Shouldn't really happen...
388
- if (undefined === this._origin) {
389
- this._origin = ev.point.clone();
390
- this.setupAndPromptForNextAction();
391
- return EventHandled.No;
392
- }
393
- this.updateNorthVector(ev);
394
- if (undefined !== this._northDir) {
395
- const deco = ProjectExtentsClipDecoration.get();
396
- if (undefined !== deco)
397
- deco.updateNorthDirection(this._northDir);
398
- }
399
- await this.onReinitialize(); // Calls onRestartTool to exit...
400
- return EventHandled.No;
401
- }
402
- async onInstall() { return ProjectExtentsClipDecoration.allowEcefLocationChange(true); }
403
- static async startTool() { return new ProjectGeolocationNorthTool().run(); }
404
- }
405
- ProjectGeolocationNorthTool.toolId = "ProjectLocation.Geolocation.North";
406
- ProjectGeolocationNorthTool.iconSpec = "icon-sort-up"; // <== Tool button should use whatever icon you have here...
407
- /** Move a geolocated model by specifying two points to define the offset.
408
- * @beta
409
- */
410
- export class ProjectGeolocationMoveTool extends PrimitiveTool {
411
- isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
412
- isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
413
- requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
414
- async onPostInstall() {
415
- await super.onPostInstall();
416
- this.setupAndPromptForNextAction();
417
- }
418
- async onCleanup() {
419
- await super.onCleanup();
420
- this.unsuspendDecorations();
421
- }
422
- async onRestartTool() {
423
- const tool = new ProjectGeolocationMoveTool();
424
- if (!await tool.run())
425
- return this.exitTool();
426
- }
427
- async onUnsuspend() { this.provideToolAssistance(); }
428
- provideToolAssistance() {
429
- const acceptMsg = CoreTools.translate("ElementSet.Inputs.AcceptPoint");
430
- const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
431
- const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyRefPoint" : "DefineOffset"));
432
- const sections = [];
433
- const mouseInstructions = [];
434
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
435
- mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
436
- sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
437
- const touchInstructions = [];
438
- if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
439
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
440
- touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
441
- sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
442
- const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
443
- IModelApp.notifications.setToolAssistance(instructions);
444
- }
445
- setupAndPromptForNextAction() {
446
- IModelApp.accuSnap.enableSnap(true);
447
- this.provideToolAssistance();
448
- if (undefined === this._origin)
449
- return;
450
- const hints = new AccuDrawHintBuilder();
451
- hints.setRotation(Matrix3d.createIdentity());
452
- hints.setOrigin(this._origin);
453
- hints.setModePolar();
454
- hints.setOriginFixed = true;
455
- hints.sendHints();
456
- }
457
- unsuspendDecorations() {
458
- const deco = ProjectExtentsClipDecoration.get();
459
- if (undefined !== deco)
460
- deco.suspendGeolocationDecorations = false;
461
- }
462
- async acceptOffset(ev) {
463
- if (undefined === ev.viewport || undefined === this._origin)
464
- return;
465
- const deco = ProjectExtentsClipDecoration.get();
466
- if (undefined === deco)
467
- return;
468
- const origin = this.iModel.spatialToCartographicFromEcef(ev.point);
469
- if (!deco.updateEcefLocation(origin, this._origin))
470
- return;
471
- return this.onReinitialize(); // Calls onRestartTool to exit...
472
- }
473
- decorate(context) {
474
- if (undefined === this._origin || undefined === this._current || !context.viewport.view.isSpatialView())
475
- return;
476
- const deco = ProjectExtentsClipDecoration.get();
477
- if (undefined === deco)
478
- return;
479
- const builderAccVis = context.createGraphicBuilder(GraphicType.WorldDecoration);
480
- const builderAccHid = context.createGraphicBuilder(GraphicType.WorldOverlay);
481
- const colorAccVis = ColorDef.white.adjustedForContrast(context.viewport.view.backgroundColor);
482
- const colorAccHid = colorAccVis.withAlpha(100);
483
- builderAccVis.setSymbology(colorAccVis, ColorDef.black, 3);
484
- builderAccHid.setSymbology(colorAccHid, ColorDef.black, 1, LinePixels.Code2);
485
- const extents = this.iModel.projectExtents.cloneTranslated(Vector3d.createStartEnd(this._origin, this._current));
486
- builderAccVis.addRangeBox(extents);
487
- builderAccHid.addRangeBox(extents);
488
- builderAccHid.addLineString([this._origin, this._current]);
489
- context.addDecorationFromBuilder(builderAccVis);
490
- context.addDecorationFromBuilder(builderAccHid);
491
- deco.suspendGeolocationDecorations = true;
492
- }
493
- async onKeyTransition(wentDown, keyEvent) {
494
- if (EventHandled.Yes === await super.onKeyTransition(wentDown, keyEvent))
495
- return EventHandled.Yes;
496
- return (wentDown && await AccuDrawShortcuts.processShortcutKey(keyEvent)) ? EventHandled.Yes : EventHandled.No;
497
- }
498
- async onMouseMotion(ev) {
499
- if (undefined === ev.viewport)
500
- return;
501
- this._current = ev.point;
502
- ev.viewport.invalidateDecorations();
503
- }
504
- async onResetButtonUp(_ev) {
505
- if (undefined === this._origin)
506
- await this.exitTool(); // exit to select tool if we haven't gotten first point...
507
- else
508
- await this.onReinitialize(); // Calls onRestartTool...
509
- return EventHandled.No;
510
- }
511
- async onDataButtonDown(ev) {
512
- if (undefined === ev.viewport)
513
- return EventHandled.No; // Shouldn't really happen...
514
- if (undefined === this._origin) {
515
- this._origin = ev.point.clone();
516
- this.setupAndPromptForNextAction();
517
- return EventHandled.No;
518
- }
519
- await this.acceptOffset(ev);
520
- return EventHandled.No;
521
- }
522
- async onInstall() { return ProjectExtentsClipDecoration.allowEcefLocationChange(true); }
523
- static async startTool() { return new ProjectGeolocationMoveTool().run(); }
524
- }
525
- ProjectGeolocationMoveTool.toolId = "ProjectLocation.Geolocation.Move";
526
- ProjectGeolocationMoveTool.iconSpec = "icon-move"; // <== Tool button should use whatever icon you have here...
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ /** @packageDocumentation
6
+ * @module Editing
7
+ */
8
+ import { AccuDrawHintBuilder, AccuDrawShortcuts, AngleDescription, CoreTools, EventHandled, GraphicType, IModelApp, LengthDescription, PrimitiveTool, ToolAssistance, ToolAssistanceImage, ToolAssistanceInputMethod } from "@itwin/core-frontend";
9
+ import { Angle, Matrix3d, Point3d, Ray3d, Vector3d } from "@itwin/core-geometry";
10
+ import { Cartographic, ColorDef, LinePixels } from "@itwin/core-common";
11
+ import { ProjectExtentsClipDecoration } from "./ProjectExtentsDecoration";
12
+ import { DialogProperty } from "@itwin/appui-abstract";
13
+ import { EditTools } from "../EditTool";
14
+ function translatePrompt(key) {
15
+ return EditTools.translate(`ProjectLocation:Prompts.${key}`);
16
+ }
17
+ function translateMessage(key) {
18
+ return EditTools.translate(`ProjectLocation:Message.${key}`);
19
+ }
20
+ /** @internal */
21
+ class LabelDecoration {
22
+ constructor(worldLocation, label) {
23
+ this.worldLocation = new Point3d();
24
+ this.position = new Point3d();
25
+ this.worldLocation.setFrom(worldLocation);
26
+ this.label = label;
27
+ }
28
+ drawDecoration(ctx) {
29
+ ctx.font = "16px san-serif";
30
+ const labelHeight = ctx.measureText("M").width; // Close enough for border padding...
31
+ const labelWidth = ctx.measureText(this.label).width + labelHeight;
32
+ ctx.lineWidth = 1;
33
+ ctx.strokeStyle = "white";
34
+ ctx.fillStyle = "rgba(0,0,0,.4)";
35
+ ctx.shadowColor = "black";
36
+ ctx.shadowBlur = 10;
37
+ ctx.fillRect(-(labelWidth / 2), -labelHeight, labelWidth, labelHeight * 2);
38
+ ctx.strokeRect(-(labelWidth / 2), -labelHeight, labelWidth, labelHeight * 2);
39
+ ctx.fillStyle = "white";
40
+ ctx.shadowBlur = 0;
41
+ ctx.textAlign = "center";
42
+ ctx.textBaseline = "middle";
43
+ ctx.fillText(this.label, 0, 0);
44
+ }
45
+ setPosition(vp) {
46
+ vp.worldToView(this.worldLocation, this.position);
47
+ this.position.y -= Math.floor(vp.pixelsFromInches(0.45)) + 0.5; // Offset from world location...
48
+ return vp.viewRect.containsPoint(this.position);
49
+ }
50
+ addDecoration(context) {
51
+ if (this.setPosition(context.viewport))
52
+ context.addCanvasDecoration(this);
53
+ }
54
+ }
55
+ /** Change or update geolocation for project.
56
+ * To show tool settings for specifying lat/long, make sure formatting and parsing data are cached before the tool starts
57
+ * by calling QuantityFormatter.onInitialized at app startup.
58
+ * @beta
59
+ */
60
+ export class ProjectGeolocationPointTool extends PrimitiveTool {
61
+ constructor() {
62
+ super(...arguments);
63
+ this._haveToolSettings = false;
64
+ this._cartographicFromArgs = false;
65
+ this._accept = false;
66
+ this._scale = 1.0;
67
+ }
68
+ static get minArgs() { return 0; }
69
+ static get maxArgs() { return 4; } // latitude, longitude, altitude, north direction...
70
+ isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
71
+ isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
72
+ requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
73
+ async onPostInstall() {
74
+ await super.onPostInstall();
75
+ this.setupAndPromptForNextAction();
76
+ }
77
+ async onCleanup() {
78
+ await super.onCleanup();
79
+ this.unsuspendDecorations();
80
+ }
81
+ async onRestartTool() { return this.exitTool(); }
82
+ async onUnsuspend() { this.provideToolAssistance(); }
83
+ get latitudeProperty() {
84
+ if (!this._latitudeProperty)
85
+ this._latitudeProperty = new DialogProperty(new AngleDescription("latitude", translateMessage("Latitude")), 0.0);
86
+ return this._latitudeProperty;
87
+ }
88
+ get latitude() { return this.latitudeProperty.value; }
89
+ set latitude(value) { this.latitudeProperty.value = value; }
90
+ get longitudeProperty() {
91
+ if (!this._longitudeProperty)
92
+ this._longitudeProperty = new DialogProperty(new AngleDescription("longitude", translateMessage("Longitude")), 0.0);
93
+ return this._longitudeProperty;
94
+ }
95
+ get longitude() { return this.longitudeProperty.value; }
96
+ set longitude(value) { this.longitudeProperty.value = value; }
97
+ get altitudeProperty() {
98
+ if (!this._altitudeProperty)
99
+ this._altitudeProperty = new DialogProperty(new LengthDescription("altitude", CoreTools.translate("Measure.Labels.Altitude")), 0.0);
100
+ return this._altitudeProperty;
101
+ }
102
+ get altitude() { return this.altitudeProperty.value; }
103
+ set altitude(value) { this.altitudeProperty.value = value; }
104
+ get northProperty() {
105
+ if (!this._northProperty)
106
+ this._northProperty = new DialogProperty(new AngleDescription("north", translateMessage("North")), 0.0);
107
+ return this._northProperty;
108
+ }
109
+ get north() { return this.northProperty.value; }
110
+ set north(value) { this.northProperty.value = value; }
111
+ syncToolSettingsCoordinates() {
112
+ this.syncToolSettingsProperties([this.latitudeProperty.syncItem, this.longitudeProperty.syncItem, this.altitudeProperty.syncItem, this.northProperty.syncItem]);
113
+ }
114
+ async applyToolSettingPropertyChange(updatedValue) {
115
+ return this.changeToolSettingPropertyValue(updatedValue);
116
+ }
117
+ supplyToolSettingsProperties() {
118
+ this._haveToolSettings = true;
119
+ const toolSettings = new Array();
120
+ toolSettings.push(this.latitudeProperty.toDialogItem({ rowPriority: 1, columnIndex: 2 }));
121
+ toolSettings.push(this.longitudeProperty.toDialogItem({ rowPriority: 2, columnIndex: 2 }));
122
+ toolSettings.push(this.altitudeProperty.toDialogItem({ rowPriority: 3, columnIndex: 2 }));
123
+ toolSettings.push(this.northProperty.toDialogItem({ rowPriority: 4, columnIndex: 2 }));
124
+ return toolSettings;
125
+ }
126
+ provideToolAssistance() {
127
+ const acceptMsg = CoreTools.translate(undefined === this._origin ? "ElementSet.Inputs.AcceptPoint" : "ElementSet.Inputs.Accept");
128
+ const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
129
+ const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyKnownLocation" : "ConfirmCoordinates"));
130
+ const sections = [];
131
+ const mouseInstructions = [];
132
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
133
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
134
+ sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
135
+ const touchInstructions = [];
136
+ if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
137
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
138
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
139
+ sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
140
+ const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
141
+ IModelApp.notifications.setToolAssistance(instructions);
142
+ }
143
+ setupAndPromptForNextAction() {
144
+ IModelApp.accuSnap.enableSnap(undefined === this._origin);
145
+ this.provideToolAssistance();
146
+ }
147
+ pulseDecoration() {
148
+ if (!this._accept)
149
+ return;
150
+ const deco = ProjectExtentsClipDecoration.get();
151
+ if (undefined === deco)
152
+ return;
153
+ this._scale += 0.1;
154
+ if (this._scale > 1.6)
155
+ this._scale = 1.0;
156
+ deco.viewport.invalidateDecorations();
157
+ setTimeout(() => this.pulseDecoration(), 100);
158
+ }
159
+ unsuspendDecorations() {
160
+ const deco = ProjectExtentsClipDecoration.get();
161
+ if (undefined !== deco)
162
+ deco.suspendGeolocationDecorations = false;
163
+ }
164
+ decorate(context) {
165
+ if (undefined === this._origin || !context.viewport.view.isSpatialView())
166
+ return;
167
+ const deco = ProjectExtentsClipDecoration.get();
168
+ if (undefined === deco)
169
+ return;
170
+ deco.suspendGeolocationDecorations = true;
171
+ deco.drawMonumentPoint(context, this._origin, this._scale);
172
+ if (undefined !== this._labelDeco)
173
+ this._labelDeco.addDecoration(context);
174
+ }
175
+ async onMouseMotion(ev) {
176
+ if (undefined === ev.viewport || this._accept)
177
+ return;
178
+ this._origin = ev.point.clone();
179
+ ev.viewport.invalidateDecorations();
180
+ }
181
+ async onResetButtonUp(_ev) {
182
+ await this.onReinitialize(); // Calls onRestartTool to exit...
183
+ return EventHandled.No;
184
+ }
185
+ acceptDefaultLocation() {
186
+ // Greenwich is better default when testing control handle w/o tool settings support...
187
+ this.latitude = Angle.createDegrees(51.4934).radians;
188
+ this.longitude = Angle.createDegrees(0.0098).radians;
189
+ this.altitude = 50.0;
190
+ this.north = 0.0;
191
+ }
192
+ acceptKnownLocation(ev) {
193
+ const deco = ProjectExtentsClipDecoration.get();
194
+ if (undefined === deco)
195
+ return;
196
+ this._accept = true; // Require explicit accept to give user a chance to change values...
197
+ this._origin = ev.point.clone();
198
+ this._labelDeco = new LabelDecoration(this._origin, translatePrompt("SpecifyCoordinates"));
199
+ if (!this._cartographicFromArgs) {
200
+ if (this.iModel.isGeoLocated) {
201
+ const cartographic = this.iModel.spatialToCartographicFromEcef(this._origin);
202
+ this.latitude = cartographic.latitude;
203
+ this.longitude = cartographic.longitude;
204
+ this.altitude = cartographic.height;
205
+ this.north = deco.getClockwiseAngleToNorth().radians;
206
+ }
207
+ else if (!this._haveToolSettings) {
208
+ this.acceptDefaultLocation();
209
+ }
210
+ }
211
+ this.syncToolSettingsCoordinates();
212
+ this.pulseDecoration(); // Pulse to indicate that we are waiting for user input...
213
+ this.setupAndPromptForNextAction();
214
+ }
215
+ async acceptCoordinates() {
216
+ const deco = ProjectExtentsClipDecoration.get();
217
+ if (undefined === deco)
218
+ return;
219
+ const origin = Cartographic.fromRadians({ longitude: this.longitude, latitude: this.latitude, height: this.altitude });
220
+ if (!deco.updateEcefLocation(origin, this._origin, Angle.createRadians(this.north)))
221
+ return;
222
+ return this.onReinitialize(); // Calls onRestartTool to exit...
223
+ }
224
+ async onDataButtonDown(ev) {
225
+ if (undefined === ev.viewport)
226
+ return EventHandled.No; // Shouldn't really happen...
227
+ const haveKnownLocation = this._accept;
228
+ if (!haveKnownLocation)
229
+ this.acceptKnownLocation(ev);
230
+ const needAcceptPoint = !haveKnownLocation && this._haveToolSettings;
231
+ if (!needAcceptPoint)
232
+ await this.acceptCoordinates();
233
+ return EventHandled.No;
234
+ }
235
+ async onInstall() {
236
+ if (!ProjectExtentsClipDecoration.allowEcefLocationChange(false))
237
+ return false;
238
+ // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
239
+ this.initializeToolSettingPropertyValues([this.latitudeProperty, this.longitudeProperty, this.altitudeProperty, this.northProperty]);
240
+ return true;
241
+ }
242
+ /** The keyin takes the following arguments, all of which are optional:
243
+ * - `latitude=number` Latitude of accept point in degrees.
244
+ * - `longitude=number` Longitude of accept point in degrees.
245
+ * - `altitude=number` Height above ellipsoid of accept point.
246
+ * - `north=number` North direction in degrees of accept point.
247
+ */
248
+ async parseAndRun(...inputArgs) {
249
+ for (const arg of inputArgs) {
250
+ const parts = arg.split("=");
251
+ if (2 !== parts.length)
252
+ continue;
253
+ if (parts[0].toLowerCase().startsWith("la")) {
254
+ const latitude = Number.parseFloat(parts[1]);
255
+ if (!Number.isNaN(latitude)) {
256
+ this.saveToolSettingPropertyValue(this.latitudeProperty, { value: Angle.createDegrees(latitude).radians });
257
+ this._cartographicFromArgs = true;
258
+ }
259
+ }
260
+ else if (parts[0].toLowerCase().startsWith("lo")) {
261
+ const longitude = Number.parseFloat(parts[1]);
262
+ if (!Number.isNaN(longitude)) {
263
+ this.saveToolSettingPropertyValue(this.longitudeProperty, { value: Angle.createDegrees(longitude).radians });
264
+ this._cartographicFromArgs = true;
265
+ }
266
+ }
267
+ else if (parts[0].toLowerCase().startsWith("al")) {
268
+ const altitude = Number.parseFloat(parts[1]);
269
+ if (!Number.isNaN(altitude)) {
270
+ this.saveToolSettingPropertyValue(this.altitudeProperty, { value: altitude });
271
+ this._cartographicFromArgs = true;
272
+ }
273
+ }
274
+ else if (parts[0].toLowerCase().startsWith("no")) {
275
+ const north = Number.parseFloat(parts[1]);
276
+ if (!Number.isNaN(north)) {
277
+ this.saveToolSettingPropertyValue(this.northProperty, { value: Angle.createDegrees(north).radians });
278
+ this._cartographicFromArgs = true;
279
+ }
280
+ }
281
+ }
282
+ return this.run();
283
+ }
284
+ static async startTool() { return new ProjectGeolocationPointTool().run(); }
285
+ }
286
+ ProjectGeolocationPointTool.toolId = "ProjectLocation.Geolocation.Point";
287
+ ProjectGeolocationPointTool.iconSpec = "icon-globe"; // <== Tool button should use whatever icon you have here...
288
+ /** Change or update geolocation direction to true north.
289
+ * @beta
290
+ */
291
+ export class ProjectGeolocationNorthTool extends PrimitiveTool {
292
+ isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
293
+ isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
294
+ requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
295
+ async onPostInstall() {
296
+ await super.onPostInstall();
297
+ this.setupAndPromptForNextAction();
298
+ }
299
+ async onCleanup() {
300
+ await super.onCleanup();
301
+ this.unsuspendDecorations();
302
+ }
303
+ async onRestartTool() { return this.exitTool(); }
304
+ async onUnsuspend() { this.provideToolAssistance(); }
305
+ provideToolAssistance() {
306
+ const acceptMsg = CoreTools.translate("ElementSet.Inputs.AcceptPoint");
307
+ const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
308
+ const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyRefPoint" : "DefineAngle"));
309
+ const sections = [];
310
+ const mouseInstructions = [];
311
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
312
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
313
+ sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
314
+ const touchInstructions = [];
315
+ if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
316
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
317
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
318
+ sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
319
+ const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
320
+ IModelApp.notifications.setToolAssistance(instructions);
321
+ }
322
+ setupAndPromptForNextAction() {
323
+ IModelApp.accuSnap.enableSnap(true);
324
+ this.provideToolAssistance();
325
+ if (undefined === this._origin)
326
+ return;
327
+ const hints = new AccuDrawHintBuilder();
328
+ hints.setRotation(Matrix3d.createIdentity());
329
+ hints.setOrigin(this._origin);
330
+ hints.setModePolar();
331
+ hints.setOriginFixed = true;
332
+ hints.setLockZ = true;
333
+ hints.sendHints();
334
+ }
335
+ getAdjustedPoint(ev) {
336
+ if (undefined === this._origin)
337
+ return undefined;
338
+ return AccuDrawHintBuilder.projectPointToPlaneInView(ev.point, this._origin, Vector3d.unitZ(), ev.viewport, true);
339
+ }
340
+ unsuspendDecorations() {
341
+ const deco = ProjectExtentsClipDecoration.get();
342
+ if (undefined !== deco)
343
+ deco.suspendGeolocationDecorations = false;
344
+ }
345
+ updateNorthVector(ev) {
346
+ if (undefined === ev.viewport)
347
+ return;
348
+ if (undefined === this._northDir)
349
+ this._northDir = Ray3d.create(ev.point, Vector3d.unitY());
350
+ else
351
+ this._northDir.origin.setFrom(undefined !== this._origin ? this._origin : ev.point);
352
+ const dirPt = this.getAdjustedPoint(ev);
353
+ if (undefined === dirPt)
354
+ return;
355
+ this._northDir.direction.setStartEnd(this._northDir.origin, dirPt);
356
+ if (this._northDir.direction.magnitude() < 1.0e-6)
357
+ this._northDir.direction.setFrom(Vector3d.unitY());
358
+ this._northDir.direction.z = 0.0;
359
+ this._northDir.direction.normalizeInPlace();
360
+ }
361
+ decorate(context) {
362
+ if (undefined === this._northDir || !context.viewport.view.isSpatialView())
363
+ return;
364
+ const deco = ProjectExtentsClipDecoration.get();
365
+ if (undefined === deco)
366
+ return;
367
+ deco.suspendGeolocationDecorations = true;
368
+ deco.drawNorthArrow(context, this._northDir);
369
+ }
370
+ async onKeyTransition(wentDown, keyEvent) {
371
+ if (EventHandled.Yes === await super.onKeyTransition(wentDown, keyEvent))
372
+ return EventHandled.Yes;
373
+ return (wentDown && await AccuDrawShortcuts.processShortcutKey(keyEvent)) ? EventHandled.Yes : EventHandled.No;
374
+ }
375
+ async onMouseMotion(ev) {
376
+ if (undefined === ev.viewport)
377
+ return;
378
+ this.updateNorthVector(ev);
379
+ ev.viewport.invalidateDecorations();
380
+ }
381
+ async onResetButtonUp(_ev) {
382
+ await this.onReinitialize(); // Calls onRestartTool to exit...
383
+ return EventHandled.No;
384
+ }
385
+ async onDataButtonDown(ev) {
386
+ if (undefined === ev.viewport)
387
+ return EventHandled.No; // Shouldn't really happen...
388
+ if (undefined === this._origin) {
389
+ this._origin = ev.point.clone();
390
+ this.setupAndPromptForNextAction();
391
+ return EventHandled.No;
392
+ }
393
+ this.updateNorthVector(ev);
394
+ if (undefined !== this._northDir) {
395
+ const deco = ProjectExtentsClipDecoration.get();
396
+ if (undefined !== deco)
397
+ deco.updateNorthDirection(this._northDir);
398
+ }
399
+ await this.onReinitialize(); // Calls onRestartTool to exit...
400
+ return EventHandled.No;
401
+ }
402
+ async onInstall() { return ProjectExtentsClipDecoration.allowEcefLocationChange(true); }
403
+ static async startTool() { return new ProjectGeolocationNorthTool().run(); }
404
+ }
405
+ ProjectGeolocationNorthTool.toolId = "ProjectLocation.Geolocation.North";
406
+ ProjectGeolocationNorthTool.iconSpec = "icon-sort-up"; // <== Tool button should use whatever icon you have here...
407
+ /** Move a geolocated model by specifying two points to define the offset.
408
+ * @beta
409
+ */
410
+ export class ProjectGeolocationMoveTool extends PrimitiveTool {
411
+ isCompatibleViewport(vp, isSelectedViewChange) { return (super.isCompatibleViewport(vp, isSelectedViewChange) && undefined !== vp && vp.view.isSpatialView()); }
412
+ isValidLocation(_ev, _isButtonEvent) { return true; } // Allow snapping to terrain, etc. outside project extents...
413
+ requireWriteableTarget() { return false; } // Tool doesn't modify the imodel...
414
+ async onPostInstall() {
415
+ await super.onPostInstall();
416
+ this.setupAndPromptForNextAction();
417
+ }
418
+ async onCleanup() {
419
+ await super.onCleanup();
420
+ this.unsuspendDecorations();
421
+ }
422
+ async onRestartTool() {
423
+ const tool = new ProjectGeolocationMoveTool();
424
+ if (!await tool.run())
425
+ return this.exitTool();
426
+ }
427
+ async onUnsuspend() { this.provideToolAssistance(); }
428
+ provideToolAssistance() {
429
+ const acceptMsg = CoreTools.translate("ElementSet.Inputs.AcceptPoint");
430
+ const rejectMsg = CoreTools.translate("ElementSet.Inputs.Cancel");
431
+ const mainInstruction = ToolAssistance.createInstruction(this.iconSpec, translatePrompt(undefined === this._origin ? "IdentifyRefPoint" : "DefineOffset"));
432
+ const sections = [];
433
+ const mouseInstructions = [];
434
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.LeftClick, acceptMsg, false, ToolAssistanceInputMethod.Mouse));
435
+ mouseInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.RightClick, rejectMsg, false, ToolAssistanceInputMethod.Mouse));
436
+ sections.push(ToolAssistance.createSection(mouseInstructions, ToolAssistance.inputsLabel));
437
+ const touchInstructions = [];
438
+ if (!ToolAssistance.createTouchCursorInstructions(touchInstructions))
439
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.OneTouchTap, acceptMsg, false, ToolAssistanceInputMethod.Touch));
440
+ touchInstructions.push(ToolAssistance.createInstruction(ToolAssistanceImage.TwoTouchTap, rejectMsg, false, ToolAssistanceInputMethod.Touch));
441
+ sections.push(ToolAssistance.createSection(touchInstructions, ToolAssistance.inputsLabel));
442
+ const instructions = ToolAssistance.createInstructions(mainInstruction, sections);
443
+ IModelApp.notifications.setToolAssistance(instructions);
444
+ }
445
+ setupAndPromptForNextAction() {
446
+ IModelApp.accuSnap.enableSnap(true);
447
+ this.provideToolAssistance();
448
+ if (undefined === this._origin)
449
+ return;
450
+ const hints = new AccuDrawHintBuilder();
451
+ hints.setRotation(Matrix3d.createIdentity());
452
+ hints.setOrigin(this._origin);
453
+ hints.setModePolar();
454
+ hints.setOriginFixed = true;
455
+ hints.sendHints();
456
+ }
457
+ unsuspendDecorations() {
458
+ const deco = ProjectExtentsClipDecoration.get();
459
+ if (undefined !== deco)
460
+ deco.suspendGeolocationDecorations = false;
461
+ }
462
+ async acceptOffset(ev) {
463
+ if (undefined === ev.viewport || undefined === this._origin)
464
+ return;
465
+ const deco = ProjectExtentsClipDecoration.get();
466
+ if (undefined === deco)
467
+ return;
468
+ const origin = this.iModel.spatialToCartographicFromEcef(ev.point);
469
+ if (!deco.updateEcefLocation(origin, this._origin))
470
+ return;
471
+ return this.onReinitialize(); // Calls onRestartTool to exit...
472
+ }
473
+ decorate(context) {
474
+ if (undefined === this._origin || undefined === this._current || !context.viewport.view.isSpatialView())
475
+ return;
476
+ const deco = ProjectExtentsClipDecoration.get();
477
+ if (undefined === deco)
478
+ return;
479
+ const builderAccVis = context.createGraphicBuilder(GraphicType.WorldDecoration);
480
+ const builderAccHid = context.createGraphicBuilder(GraphicType.WorldOverlay);
481
+ const colorAccVis = ColorDef.white.adjustedForContrast(context.viewport.view.backgroundColor);
482
+ const colorAccHid = colorAccVis.withAlpha(100);
483
+ builderAccVis.setSymbology(colorAccVis, ColorDef.black, 3);
484
+ builderAccHid.setSymbology(colorAccHid, ColorDef.black, 1, LinePixels.Code2);
485
+ const extents = this.iModel.projectExtents.cloneTranslated(Vector3d.createStartEnd(this._origin, this._current));
486
+ builderAccVis.addRangeBox(extents);
487
+ builderAccHid.addRangeBox(extents);
488
+ builderAccHid.addLineString([this._origin, this._current]);
489
+ context.addDecorationFromBuilder(builderAccVis);
490
+ context.addDecorationFromBuilder(builderAccHid);
491
+ deco.suspendGeolocationDecorations = true;
492
+ }
493
+ async onKeyTransition(wentDown, keyEvent) {
494
+ if (EventHandled.Yes === await super.onKeyTransition(wentDown, keyEvent))
495
+ return EventHandled.Yes;
496
+ return (wentDown && await AccuDrawShortcuts.processShortcutKey(keyEvent)) ? EventHandled.Yes : EventHandled.No;
497
+ }
498
+ async onMouseMotion(ev) {
499
+ if (undefined === ev.viewport)
500
+ return;
501
+ this._current = ev.point;
502
+ ev.viewport.invalidateDecorations();
503
+ }
504
+ async onResetButtonUp(_ev) {
505
+ if (undefined === this._origin)
506
+ await this.exitTool(); // exit to select tool if we haven't gotten first point...
507
+ else
508
+ await this.onReinitialize(); // Calls onRestartTool...
509
+ return EventHandled.No;
510
+ }
511
+ async onDataButtonDown(ev) {
512
+ if (undefined === ev.viewport)
513
+ return EventHandled.No; // Shouldn't really happen...
514
+ if (undefined === this._origin) {
515
+ this._origin = ev.point.clone();
516
+ this.setupAndPromptForNextAction();
517
+ return EventHandled.No;
518
+ }
519
+ await this.acceptOffset(ev);
520
+ return EventHandled.No;
521
+ }
522
+ async onInstall() { return ProjectExtentsClipDecoration.allowEcefLocationChange(true); }
523
+ static async startTool() { return new ProjectGeolocationMoveTool().run(); }
524
+ }
525
+ ProjectGeolocationMoveTool.toolId = "ProjectLocation.Geolocation.Move";
526
+ ProjectGeolocationMoveTool.iconSpec = "icon-move"; // <== Tool button should use whatever icon you have here...
527
527
  //# sourceMappingURL=ProjectGeolocation.js.map