@itwin/editor-frontend 4.5.0-dev.9 → 4.6.0-dev.0

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 (101) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/LICENSE.md +1 -1
  3. package/README.md +0 -29
  4. package/lib/cjs/CreateElementTool.d.ts +64 -2
  5. package/lib/cjs/CreateElementTool.d.ts.map +1 -1
  6. package/lib/cjs/CreateElementTool.js +65 -4
  7. package/lib/cjs/CreateElementTool.js.map +1 -1
  8. package/lib/cjs/EditTool.d.ts +5 -0
  9. package/lib/cjs/EditTool.d.ts.map +1 -1
  10. package/lib/cjs/EditTool.js +10 -14
  11. package/lib/cjs/EditTool.js.map +1 -1
  12. package/lib/cjs/EditToolIpc.d.ts +1 -5
  13. package/lib/cjs/EditToolIpc.d.ts.map +1 -1
  14. package/lib/cjs/EditToolIpc.js +1 -5
  15. package/lib/cjs/EditToolIpc.js.map +1 -1
  16. package/lib/cjs/ModifyElementTool.js.map +1 -1
  17. package/lib/cjs/ProjectLocation/ProjectExtentsDecoration.js.map +1 -1
  18. package/lib/cjs/ProjectLocation/ProjectGeolocation.js.map +1 -1
  19. package/lib/cjs/TransformElementsTool.d.ts +17 -98
  20. package/lib/cjs/TransformElementsTool.d.ts.map +1 -1
  21. package/lib/cjs/TransformElementsTool.js +15 -412
  22. package/lib/cjs/TransformElementsTool.js.map +1 -1
  23. package/lib/cjs/UndoRedoTool.js.map +1 -1
  24. package/lib/cjs/editor-frontend.d.ts +0 -6
  25. package/lib/cjs/editor-frontend.d.ts.map +1 -1
  26. package/lib/cjs/editor-frontend.js +0 -6
  27. package/lib/cjs/editor-frontend.js.map +1 -1
  28. package/lib/esm/CreateElementTool.d.ts +64 -2
  29. package/lib/esm/CreateElementTool.d.ts.map +1 -1
  30. package/lib/esm/CreateElementTool.js +65 -4
  31. package/lib/esm/CreateElementTool.js.map +1 -1
  32. package/lib/esm/EditTool.d.ts +5 -0
  33. package/lib/esm/EditTool.d.ts.map +1 -1
  34. package/lib/esm/EditTool.js +10 -14
  35. package/lib/esm/EditTool.js.map +1 -1
  36. package/lib/esm/EditToolIpc.d.ts +1 -5
  37. package/lib/esm/EditToolIpc.d.ts.map +1 -1
  38. package/lib/esm/EditToolIpc.js +0 -4
  39. package/lib/esm/EditToolIpc.js.map +1 -1
  40. package/lib/esm/ModifyElementTool.js.map +1 -1
  41. package/lib/esm/ProjectLocation/ProjectExtentsDecoration.js.map +1 -1
  42. package/lib/esm/ProjectLocation/ProjectGeolocation.js.map +1 -1
  43. package/lib/esm/TransformElementsTool.d.ts +17 -98
  44. package/lib/esm/TransformElementsTool.d.ts.map +1 -1
  45. package/lib/esm/TransformElementsTool.js +16 -413
  46. package/lib/esm/TransformElementsTool.js.map +1 -1
  47. package/lib/esm/UndoRedoTool.js.map +1 -1
  48. package/lib/esm/editor-frontend.d.ts +0 -6
  49. package/lib/esm/editor-frontend.d.ts.map +1 -1
  50. package/lib/esm/editor-frontend.js +0 -6
  51. package/lib/esm/editor-frontend.js.map +1 -1
  52. package/lib/public/locales/en/Editor.json +79 -490
  53. package/package.json +14 -14
  54. package/lib/cjs/DeleteElementsTool.d.ts +0 -14
  55. package/lib/cjs/DeleteElementsTool.d.ts.map +0 -1
  56. package/lib/cjs/DeleteElementsTool.js +0 -42
  57. package/lib/cjs/DeleteElementsTool.js.map +0 -1
  58. package/lib/cjs/ElementGeometryTool.d.ts +0 -148
  59. package/lib/cjs/ElementGeometryTool.d.ts.map +0 -1
  60. package/lib/cjs/ElementGeometryTool.js +0 -705
  61. package/lib/cjs/ElementGeometryTool.js.map +0 -1
  62. package/lib/cjs/ModifyCurveTools.d.ts +0 -140
  63. package/lib/cjs/ModifyCurveTools.d.ts.map +0 -1
  64. package/lib/cjs/ModifyCurveTools.js +0 -777
  65. package/lib/cjs/ModifyCurveTools.js.map +0 -1
  66. package/lib/cjs/SketchTools.d.ts +0 -308
  67. package/lib/cjs/SketchTools.d.ts.map +0 -1
  68. package/lib/cjs/SketchTools.js +0 -1708
  69. package/lib/cjs/SketchTools.js.map +0 -1
  70. package/lib/cjs/SolidModelingTools.d.ts +0 -381
  71. package/lib/cjs/SolidModelingTools.d.ts.map +0 -1
  72. package/lib/cjs/SolidModelingTools.js +0 -1453
  73. package/lib/cjs/SolidModelingTools.js.map +0 -1
  74. package/lib/cjs/SolidPrimitiveTools.d.ts +0 -322
  75. package/lib/cjs/SolidPrimitiveTools.d.ts.map +0 -1
  76. package/lib/cjs/SolidPrimitiveTools.js +0 -1376
  77. package/lib/cjs/SolidPrimitiveTools.js.map +0 -1
  78. package/lib/esm/DeleteElementsTool.d.ts +0 -14
  79. package/lib/esm/DeleteElementsTool.d.ts.map +0 -1
  80. package/lib/esm/DeleteElementsTool.js +0 -39
  81. package/lib/esm/DeleteElementsTool.js.map +0 -1
  82. package/lib/esm/ElementGeometryTool.d.ts +0 -148
  83. package/lib/esm/ElementGeometryTool.d.ts.map +0 -1
  84. package/lib/esm/ElementGeometryTool.js +0 -697
  85. package/lib/esm/ElementGeometryTool.js.map +0 -1
  86. package/lib/esm/ModifyCurveTools.d.ts +0 -140
  87. package/lib/esm/ModifyCurveTools.d.ts.map +0 -1
  88. package/lib/esm/ModifyCurveTools.js +0 -772
  89. package/lib/esm/ModifyCurveTools.js.map +0 -1
  90. package/lib/esm/SketchTools.d.ts +0 -308
  91. package/lib/esm/SketchTools.d.ts.map +0 -1
  92. package/lib/esm/SketchTools.js +0 -1704
  93. package/lib/esm/SketchTools.js.map +0 -1
  94. package/lib/esm/SolidModelingTools.d.ts +0 -381
  95. package/lib/esm/SolidModelingTools.d.ts.map +0 -1
  96. package/lib/esm/SolidModelingTools.js +0 -1445
  97. package/lib/esm/SolidModelingTools.js.map +0 -1
  98. package/lib/esm/SolidPrimitiveTools.d.ts +0 -322
  99. package/lib/esm/SolidPrimitiveTools.d.ts.map +0 -1
  100. package/lib/esm/SolidPrimitiveTools.js +0 -1372
  101. package/lib/esm/SolidPrimitiveTools.js.map +0 -1
@@ -1,1445 +0,0 @@
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 { DialogProperty, PropertyDescriptionHelper } from "@itwin/appui-abstract";
9
- import { ColorDef, ElementGeometry } from "@itwin/core-common";
10
- import { AccuDraw, AccuDrawHintBuilder, AngleDescription, EventHandled, GraphicType, IModelApp, LengthDescription, TentativeOrAccuSnap, } from "@itwin/core-frontend";
11
- import { Angle, Geometry, LineString3d, Matrix3d, Point3d, Vector3d } from "@itwin/core-geometry";
12
- import { BooleanMode, BRepEntityType, ChamferMode, CutDepthMode, CutDirectionMode, EmbossDirectionMode, ProfileClosure, SubEntityType, } from "@itwin/editor-common";
13
- import { computeChordToleranceFromPoint } from "./CreateElementTool";
14
- import { EditTools } from "./EditTool";
15
- import { ElementGeometryCacheTool, isSameSubEntity, LocateSubEntityTool, SubEntityData } from "./ElementGeometryTool";
16
- import { solidModelingIpc } from "./EditToolIpc";
17
- /** @alpha Base class for tools that perform boolean operations on a set of elements. */
18
- export class BooleanOperationTool extends ElementGeometryCacheTool {
19
- get allowSelectionSet() { return BooleanMode.Subtract !== this.mode; }
20
- get allowDragSelect() { return BooleanMode.Subtract !== this.mode; }
21
- get controlKeyContinuesSelection() { return true; }
22
- get requiredElementCount() { return 2; }
23
- get geometryCacheFilter() {
24
- return { parts: true, curves: false, surfaces: BooleanMode.Subtract === this.mode && !this.agenda.isEmpty, solids: true, other: false };
25
- }
26
- async onAgendaModified() {
27
- // Filter changes to allow surfaces as tools, invalidate cached accept status...
28
- if (BooleanMode.Subtract === this.mode && (this.agenda.isEmpty || 1 === this.agenda.length))
29
- this.onGeometryCacheFilterChanged();
30
- }
31
- async applyAgendaOperation() {
32
- if (this.agenda.length < this.requiredElementCount)
33
- return undefined;
34
- try {
35
- this._startedCmd = await this.startCommand();
36
- const target = this.agenda.elements[0];
37
- const tools = this.agenda.elements.slice(1);
38
- const params = { mode: this.mode, tools };
39
- const opts = { writeChanges: true };
40
- return await solidModelingIpc.booleanOperation(target, params, opts);
41
- }
42
- catch (err) {
43
- return undefined;
44
- }
45
- }
46
- async processAgenda(_ev) {
47
- const result = await this.applyAgendaOperation();
48
- if (result?.elementId)
49
- await this.saveChanges();
50
- }
51
- }
52
- /** @alpha Perform boolean union of solid geometry. */
53
- class UniteSolidElementsTool extends BooleanOperationTool {
54
- get mode() { return BooleanMode.Unite; }
55
- async onRestartTool() {
56
- const tool = new UniteSolidElementsTool();
57
- if (!await tool.run())
58
- return this.exitTool();
59
- }
60
- }
61
- UniteSolidElementsTool.toolId = "UniteSolids";
62
- UniteSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
63
- export { UniteSolidElementsTool };
64
- /** @alpha Perform boolean subtract of solid geometry. */
65
- class SubtractSolidElementsTool extends BooleanOperationTool {
66
- get mode() { return BooleanMode.Subtract; }
67
- async onRestartTool() {
68
- const tool = new SubtractSolidElementsTool();
69
- if (!await tool.run())
70
- return this.exitTool();
71
- }
72
- }
73
- SubtractSolidElementsTool.toolId = "SubtractSolids";
74
- SubtractSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
75
- export { SubtractSolidElementsTool };
76
- /** @alpha Perform boolean intersection of solid geometry. */
77
- class IntersectSolidElementsTool extends BooleanOperationTool {
78
- get mode() { return BooleanMode.Intersect; }
79
- async onRestartTool() {
80
- const tool = new IntersectSolidElementsTool();
81
- if (!await tool.run())
82
- return this.exitTool();
83
- }
84
- }
85
- IntersectSolidElementsTool.toolId = "IntersectSolids";
86
- IntersectSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
87
- export { IntersectSolidElementsTool };
88
- /** @alpha Perform sew operation on surface geometry. */
89
- class SewSheetElementsTool extends ElementGeometryCacheTool {
90
- get allowSelectionSet() { return true; }
91
- get allowDragSelect() { return true; }
92
- get controlKeyContinuesSelection() { return true; }
93
- get requiredElementCount() { return 2; }
94
- get geometryCacheFilter() {
95
- return { parts: true, curves: false, surfaces: true, solids: false, other: false };
96
- }
97
- async applyAgendaOperation() {
98
- if (this.agenda.length < this.requiredElementCount)
99
- return undefined;
100
- try {
101
- this._startedCmd = await this.startCommand();
102
- const target = this.agenda.elements[0];
103
- const tools = this.agenda.elements.slice(1);
104
- const params = { tools };
105
- const opts = { writeChanges: true };
106
- return await solidModelingIpc.sewSheets(target, params, opts);
107
- }
108
- catch (err) {
109
- return undefined;
110
- }
111
- }
112
- async processAgenda(_ev) {
113
- const result = await this.applyAgendaOperation();
114
- if (result?.elementId)
115
- await this.saveChanges();
116
- }
117
- async onRestartTool() {
118
- const tool = new SewSheetElementsTool();
119
- if (!await tool.run())
120
- return this.exitTool();
121
- }
122
- }
123
- SewSheetElementsTool.toolId = "SewSheets";
124
- SewSheetElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
125
- export { SewSheetElementsTool };
126
- /** @alpha Perform thicken operation on surface geometry. */
127
- class ThickenSheetElementsTool extends ElementGeometryCacheTool {
128
- get frontDistanceProperty() {
129
- if (!this._frontDistanceProperty)
130
- this._frontDistanceProperty = new DialogProperty(new LengthDescription("thickenFront", EditTools.translate("ThickenSheets.Label.FrontDistance")), 0.1, undefined);
131
- return this._frontDistanceProperty;
132
- }
133
- get frontDistance() { return this.frontDistanceProperty.value; }
134
- set frontDistance(value) { this.frontDistanceProperty.value = value; }
135
- get backDistanceProperty() {
136
- if (!this._backDistanceProperty)
137
- this._backDistanceProperty = new DialogProperty(new LengthDescription("thickenBack", EditTools.translate("ThickenSheets.Label.BackDistance")), 0.0, undefined);
138
- return this._backDistanceProperty;
139
- }
140
- get backDistance() { return this.backDistanceProperty.value; }
141
- set backDistance(value) { this.backDistanceProperty.value = value; }
142
- get geometryCacheFilter() {
143
- return { parts: true, curves: false, surfaces: true, solids: false, other: false };
144
- }
145
- async applyAgendaOperation() {
146
- if (this.agenda.length < this.requiredElementCount)
147
- return undefined;
148
- try {
149
- this._startedCmd = await this.startCommand();
150
- const target = this.agenda.elements[0];
151
- const params = { front: this.frontDistance, back: this.backDistance };
152
- const opts = { writeChanges: true };
153
- return await solidModelingIpc.thickenSheets(target, params, opts);
154
- }
155
- catch (err) {
156
- return undefined;
157
- }
158
- }
159
- async processAgenda(_ev) {
160
- const result = await this.applyAgendaOperation();
161
- if (result?.elementId)
162
- await this.saveChanges();
163
- }
164
- async applyToolSettingPropertyChange(updatedValue) {
165
- return this.changeToolSettingPropertyValue(updatedValue);
166
- }
167
- supplyToolSettingsProperties() {
168
- this.initializeToolSettingPropertyValues([this.frontDistanceProperty, this.backDistanceProperty]);
169
- const toolSettings = new Array();
170
- toolSettings.push(this.frontDistanceProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
171
- toolSettings.push(this.backDistanceProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
172
- return toolSettings;
173
- }
174
- async onRestartTool() {
175
- const tool = new ThickenSheetElementsTool();
176
- if (!await tool.run())
177
- return this.exitTool();
178
- }
179
- }
180
- ThickenSheetElementsTool.toolId = "ThickenSheets";
181
- ThickenSheetElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
182
- export { ThickenSheetElementsTool };
183
- /** @alpha Perform cut operation on solid using region or path profile. */
184
- class CutSolidElementsTool extends ElementGeometryCacheTool {
185
- get bothDirectionsProperty() {
186
- if (!this._bothDirectionsProperty)
187
- this._bothDirectionsProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("cutBothDirections", EditTools.translate("CutSolids.Label.BothDirections")), false);
188
- return this._bothDirectionsProperty;
189
- }
190
- get bothDirections() { return this.bothDirectionsProperty.value; }
191
- set bothDirections(value) { this.bothDirectionsProperty.value = value; }
192
- get outsideProperty() {
193
- if (!this._outsideProperty)
194
- this._outsideProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("cutOutside", EditTools.translate("CutSolids.Label.Outside")), false);
195
- return this._outsideProperty;
196
- }
197
- get outside() { return this.outsideProperty.value; }
198
- set outside(value) { this.outsideProperty.value = value; }
199
- get useDepthProperty() {
200
- if (!this._useDepthProperty)
201
- this._useDepthProperty = new DialogProperty(PropertyDescriptionHelper.buildLockPropertyDescription("useCutDepth"), false);
202
- return this._useDepthProperty;
203
- }
204
- get useDepth() { return this.useDepthProperty.value; }
205
- set useDepth(value) { this.useDepthProperty.value = value; }
206
- get depthProperty() {
207
- if (!this._depthProperty)
208
- this._depthProperty = new DialogProperty(new LengthDescription("cutDepth", EditTools.translate("CutSolids.Label.Depth")), 0.1, undefined, !this.useDepth);
209
- return this._depthProperty;
210
- }
211
- get depth() { return this.depthProperty.value; }
212
- set depth(value) { this.depthProperty.value = value; }
213
- get requiredElementCount() { return 2; }
214
- get isProfilePhase() { return !this.agenda.isEmpty; }
215
- get geometryCacheFilter() {
216
- const profilePhase = this.isProfilePhase;
217
- return { minGeom: 1, maxGeom: profilePhase ? 1 : undefined, parts: true, curves: profilePhase, surfaces: profilePhase, solids: !profilePhase, other: false };
218
- }
219
- async createElementGeometryCache(id) {
220
- if (!await super.createElementGeometryCache(id))
221
- return false;
222
- if (!this.isProfilePhase)
223
- return true;
224
- try {
225
- this._startedCmd = await this.startCommand();
226
- return await solidModelingIpc.isPlanarBody(id, 0);
227
- }
228
- catch (err) {
229
- return false;
230
- }
231
- }
232
- async onAgendaModified() {
233
- // Filter changes to allow sheets and wires as profiles, invalidate cached accept status...
234
- if (this.agenda.isEmpty || 1 === this.agenda.length)
235
- this.onGeometryCacheFilterChanged();
236
- }
237
- async applyAgendaOperation() {
238
- if (this.agenda.length < this.requiredElementCount)
239
- return undefined;
240
- const direction = (this.bothDirections ? CutDirectionMode.Both : CutDirectionMode.Auto);
241
- const depth = (this.useDepth ? CutDepthMode.Blind : CutDepthMode.All);
242
- try {
243
- this._startedCmd = await this.startCommand();
244
- const target = this.agenda.elements[0];
245
- const profile = this.agenda.elements[1];
246
- const params = { profile, direction, depth, distance: this.depth, outside: this.outside ? true : undefined, closeOpen: ProfileClosure.Auto, targetPoint: this.targetPoint, toolPoint: this.toolPoint };
247
- const opts = { writeChanges: true };
248
- return await solidModelingIpc.cutSolid(target, params, opts);
249
- }
250
- catch (err) {
251
- return undefined;
252
- }
253
- }
254
- async processAgenda(_ev) {
255
- const result = await this.applyAgendaOperation();
256
- if (result?.elementId)
257
- await this.saveChanges();
258
- }
259
- async buildLocateAgenda(hit) {
260
- if (this.isProfilePhase)
261
- this.toolPoint = hit.hitPoint;
262
- else
263
- this.targetPoint = hit.hitPoint;
264
- return super.buildLocateAgenda(hit);
265
- }
266
- getToolSettingPropertyLocked(property) {
267
- return (property === this.useDepthProperty ? this.depthProperty : undefined);
268
- }
269
- async applyToolSettingPropertyChange(updatedValue) {
270
- return this.changeToolSettingPropertyValue(updatedValue);
271
- }
272
- supplyToolSettingsProperties() {
273
- this.initializeToolSettingPropertyValues([this.bothDirectionsProperty, this.outsideProperty, this.useDepthProperty, this.depthProperty]);
274
- const toolSettings = new Array();
275
- toolSettings.push(this.bothDirectionsProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
276
- toolSettings.push(this.outsideProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
277
- // ensure controls are enabled/disabled based on current lock property state
278
- this.depthProperty.isDisabled = !this.useDepth;
279
- const useDepthLock = this.useDepthProperty.toDialogItem({ rowPriority: 3, columnIndex: 0 });
280
- toolSettings.push(this.depthProperty.toDialogItem({ rowPriority: 3, columnIndex: 1 }, useDepthLock));
281
- return toolSettings;
282
- }
283
- async onRestartTool() {
284
- const tool = new CutSolidElementsTool();
285
- if (!await tool.run())
286
- return this.exitTool();
287
- }
288
- }
289
- CutSolidElementsTool.toolId = "CutSolids";
290
- CutSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
291
- export { CutSolidElementsTool };
292
- /** @alpha Perform emboss operation on solid or sheet using sheet profile. */
293
- class EmbossSolidElementsTool extends ElementGeometryCacheTool {
294
- get requiredElementCount() { return 2; }
295
- get isProfilePhase() { return !this.agenda.isEmpty; }
296
- get geometryCacheFilter() {
297
- const profilePhase = this.isProfilePhase;
298
- return { minGeom: 1, maxGeom: 1, parts: true, curves: false, surfaces: true, solids: !profilePhase, other: false };
299
- }
300
- async onAgendaModified() {
301
- // Filter changes to disallow solids as profiles, invalidate cached accept status...
302
- if (this.agenda.isEmpty || 1 === this.agenda.length)
303
- this.onGeometryCacheFilterChanged();
304
- }
305
- async applyAgendaOperation() {
306
- if (this.agenda.length < this.requiredElementCount)
307
- return undefined;
308
- try {
309
- this._startedCmd = await this.startCommand();
310
- const target = this.agenda.elements[0];
311
- const profile = this.agenda.elements[1];
312
- const params = { profile, direction: EmbossDirectionMode.Auto, targetPoint: this.targetPoint };
313
- const opts = { writeChanges: true };
314
- return await solidModelingIpc.embossBody(target, params, opts);
315
- }
316
- catch (err) {
317
- return undefined;
318
- }
319
- }
320
- async processAgenda(_ev) {
321
- const result = await this.applyAgendaOperation();
322
- if (result?.elementId)
323
- await this.saveChanges();
324
- }
325
- async buildLocateAgenda(hit) {
326
- if (!this.isProfilePhase)
327
- this.targetPoint = hit.hitPoint;
328
- return super.buildLocateAgenda(hit);
329
- }
330
- async onRestartTool() {
331
- const tool = new EmbossSolidElementsTool();
332
- if (!await tool.run())
333
- return this.exitTool();
334
- }
335
- }
336
- EmbossSolidElementsTool.toolId = "EmbossSolids";
337
- EmbossSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
338
- export { EmbossSolidElementsTool };
339
- /** @alpha Create a solid for sheet by sweeping a profile along a path. */
340
- class SweepAlongPathTool extends ElementGeometryCacheTool {
341
- get requiredElementCount() { return 2; }
342
- get geometryCacheFilter() {
343
- return { minGeom: 1, maxGeom: 1, parts: true, curves: true, surfaces: true, solids: false, other: false };
344
- }
345
- async applyAgendaOperation() {
346
- if (this.agenda.length < this.requiredElementCount)
347
- return undefined;
348
- try {
349
- this._startedCmd = await this.startCommand();
350
- const target = this.agenda.elements[0];
351
- const path = this.agenda.elements[1];
352
- const params = { path };
353
- const opts = { writeChanges: true };
354
- return await solidModelingIpc.sweepAlongPath(target, params, opts);
355
- }
356
- catch (err) {
357
- return undefined;
358
- }
359
- }
360
- async processAgenda(_ev) {
361
- const result = await this.applyAgendaOperation();
362
- if (result?.elementId)
363
- await this.saveChanges();
364
- }
365
- async onRestartTool() {
366
- const tool = new SweepAlongPathTool();
367
- if (!await tool.run())
368
- return this.exitTool();
369
- }
370
- }
371
- SweepAlongPathTool.toolId = "SweepAlongPath";
372
- SweepAlongPathTool.iconSpec = "icon-move"; // TODO: Need better icon...
373
- export { SweepAlongPathTool };
374
- /** @alpha Create a new sheet or solid body by lofting through a set of profiles. */
375
- class LoftProfilesTool extends ElementGeometryCacheTool {
376
- get requiredElementCount() { return 2; }
377
- get controlKeyContinuesSelection() { return true; }
378
- get geometryCacheFilter() {
379
- return { minGeom: 1, maxGeom: 1, parts: true, curves: true, surfaces: true, solids: false, other: false };
380
- }
381
- async applyAgendaOperation() {
382
- if (this.agenda.length < this.requiredElementCount)
383
- return undefined;
384
- try {
385
- this._startedCmd = await this.startCommand();
386
- const target = this.agenda.elements[0];
387
- const tools = this.agenda.elements.slice(1);
388
- const params = { tools, orderCurves: this.isSelectionSetModify ? true : undefined, orientCurves: true };
389
- const opts = { writeChanges: true };
390
- return await solidModelingIpc.loftProfiles(target, params, opts);
391
- }
392
- catch (err) {
393
- return undefined;
394
- }
395
- }
396
- async processAgenda(_ev) {
397
- const result = await this.applyAgendaOperation();
398
- if (result?.elementId)
399
- await this.saveChanges();
400
- }
401
- async onRestartTool() {
402
- const tool = new LoftProfilesTool();
403
- if (!await tool.run())
404
- return this.exitTool();
405
- }
406
- }
407
- LoftProfilesTool.toolId = "LoftProfiles";
408
- LoftProfilesTool.iconSpec = "icon-move"; // TODO: Need better icon...
409
- export { LoftProfilesTool };
410
- /** @alpha */
411
- export class FaceLocationData {
412
- constructor(point, normal) {
413
- this.point = point;
414
- this.normal = normal;
415
- }
416
- static create(pointProps, normalProps) {
417
- const point = Point3d.fromJSON(pointProps);
418
- const normal = Vector3d.fromJSON(normalProps);
419
- return new FaceLocationData(point, normal);
420
- }
421
- }
422
- /** @alpha Identify faces of solids and surfaces to offset. */
423
- class OffsetFacesTool extends LocateSubEntityTool {
424
- get addSmoothProperty() {
425
- if (!this._addSmoothProperty)
426
- this._addSmoothProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("offsetSmooth", EditTools.translate("OffsetFaces.Label.AddSmooth")), false);
427
- return this._addSmoothProperty;
428
- }
429
- get addSmooth() { return this.addSmoothProperty.value; }
430
- set addSmooth(value) { this.addSmoothProperty.value = value; }
431
- get useDistanceProperty() {
432
- if (!this._useDistanceProperty)
433
- this._useDistanceProperty = new DialogProperty(PropertyDescriptionHelper.buildLockPropertyDescription("useOffsetDistance"), false);
434
- return this._useDistanceProperty;
435
- }
436
- get useDistance() { return this.useDistanceProperty.value; }
437
- set useDistance(value) { this.useDistanceProperty.value = value; }
438
- get distanceProperty() {
439
- if (!this._distanceProperty)
440
- this._distanceProperty = new DialogProperty(new LengthDescription("offsetDistance", EditTools.translate("OffsetFaces.Label.Distance")), 0.1, undefined, !this.useDistance);
441
- return this._distanceProperty;
442
- }
443
- get distance() { return this.distanceProperty.value; }
444
- set distance(value) { this.distanceProperty.value = value; }
445
- get wantDynamics() { return true; }
446
- get wantAccuSnap() { return this.isDynamicsStarted; }
447
- get geometryCacheFilter() {
448
- return { parts: true, curves: false, surfaces: true, solids: true, other: false };
449
- }
450
- async createSubEntityData(id, hit) {
451
- const data = await super.createSubEntityData(id, hit);
452
- if (undefined !== hit.point && undefined !== hit.normal)
453
- data.toolData = FaceLocationData.create(hit.point, hit.normal);
454
- return data;
455
- }
456
- drawAcceptedSubEntities(context) {
457
- super.drawAcceptedSubEntities(context);
458
- // Show pick point on last identified face, offset direction/distance will be computed from this location...
459
- const faceData = this.getAcceptedSubEntityData()?.toolData;
460
- if (undefined === faceData)
461
- return;
462
- const builder = context.createGraphic({ type: GraphicType.WorldOverlay });
463
- builder.setSymbology(context.viewport.getContrastToBackgroundColor(), ColorDef.black, 10);
464
- builder.addPointString([faceData.point]);
465
- context.addDecorationFromBuilder(builder);
466
- }
467
- async getSmoothFaces(id, face) {
468
- try {
469
- // NOTE: For offset, include all smoothly connected faces, not just adjacent...
470
- return await solidModelingIpc.getConnectedSubEntities(id, face, SubEntityType.Face, { smoothFaces: true });
471
- }
472
- catch (err) {
473
- return undefined;
474
- }
475
- }
476
- async applyAgendaOperation(ev, isAccept) {
477
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
478
- return undefined;
479
- const faceData = this.getAcceptedSubEntityData()?.toolData;
480
- if (undefined === faceData)
481
- return undefined;
482
- const projPt = AccuDrawHintBuilder.projectPointToLineInView(ev.point, faceData.point, faceData.normal, ev.viewport);
483
- if (undefined === projPt)
484
- return undefined;
485
- const offsetDir = Vector3d.createStartEnd(faceData.point, projPt);
486
- if (this.useDistance && undefined === offsetDir.scaleToLength(this.distance, offsetDir))
487
- return undefined;
488
- let offset = offsetDir.magnitude();
489
- if (offset < Geometry.smallMetricDistance)
490
- return undefined;
491
- if (offsetDir.dotProduct(faceData.normal) < 0.0)
492
- offset = -offset;
493
- if (!this.useDistance) {
494
- this.distance = offset;
495
- this.syncToolSettingPropertyValue(this.distanceProperty);
496
- if (isAccept)
497
- this.saveToolSettingPropertyValue(this.distanceProperty, this.distanceProperty.dialogItemValue);
498
- }
499
- try {
500
- this._startedCmd = await this.startCommand();
501
- const id = this.agenda.elements[0];
502
- const faces = this.getAcceptedSubEntities();
503
- if (this.addSmooth) {
504
- const allSmoothFaces = [];
505
- for (const face of faces) {
506
- const smoothFaces = await this.getSmoothFaces(id, face);
507
- if (undefined !== smoothFaces)
508
- allSmoothFaces.push(...smoothFaces);
509
- }
510
- for (const smooth of allSmoothFaces) {
511
- if (undefined === faces.find((selected) => isSameSubEntity(selected, smooth)))
512
- faces.unshift(smooth); // Preserve last selected entry as reference face...
513
- }
514
- }
515
- const params = { faces, distances: offset };
516
- const opts = {
517
- wantGraphic: isAccept ? undefined : true,
518
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
519
- requestId: `${this.toolId}:${id}`,
520
- writeChanges: isAccept ? true : undefined,
521
- };
522
- return await solidModelingIpc.offsetFaces(id, params, opts);
523
- }
524
- catch (err) {
525
- return undefined;
526
- }
527
- }
528
- setupAccuDraw() {
529
- if (!this.haveAcceptedSubEntities)
530
- return;
531
- const faceData = this.getAcceptedSubEntityData()?.toolData;
532
- if (undefined === faceData)
533
- return;
534
- const hints = new AccuDrawHintBuilder();
535
- hints.setOriginFixed = true;
536
- hints.setLockY = true;
537
- hints.setLockZ = true;
538
- hints.setModeRectangular();
539
- hints.setOrigin(faceData.point);
540
- hints.setXAxis2(faceData.normal);
541
- hints.sendHints(false);
542
- }
543
- getToolSettingPropertyLocked(property) {
544
- return (property === this.useDistanceProperty ? this.distanceProperty : undefined);
545
- }
546
- async applyToolSettingPropertyChange(updatedValue) {
547
- return this.changeToolSettingPropertyValue(updatedValue);
548
- }
549
- supplyToolSettingsProperties() {
550
- this.initializeToolSettingPropertyValues([this.addSmoothProperty, this.useDistanceProperty, this.distanceProperty]);
551
- const toolSettings = new Array();
552
- // ensure controls are enabled/disabled based on current lock property state
553
- this.distanceProperty.isDisabled = !this.useDistance;
554
- const useDistanceLock = this.useDistanceProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 });
555
- toolSettings.push(this.distanceProperty.toDialogItem({ rowPriority: 1, columnIndex: 1 }, useDistanceLock));
556
- toolSettings.push(this.addSmoothProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
557
- return toolSettings;
558
- }
559
- async onRestartTool() {
560
- const tool = new OffsetFacesTool();
561
- if (!await tool.run())
562
- return this.exitTool();
563
- }
564
- }
565
- OffsetFacesTool.toolId = "OffsetFaces";
566
- OffsetFacesTool.iconSpec = "icon-move"; // TODO: Need better icon...
567
- export { OffsetFacesTool };
568
- /** @alpha Identify faces to offset to hollow solids. */
569
- class HollowFacesTool extends LocateSubEntityTool {
570
- get shellThicknessProperty() {
571
- if (!this._shellThicknessProperty)
572
- this._shellThicknessProperty = new DialogProperty(new LengthDescription("hollowShellThickness", EditTools.translate("HollowFaces.Label.ShellThickness")), 0.1, undefined);
573
- return this._shellThicknessProperty;
574
- }
575
- get shellThickness() { return this.shellThicknessProperty.value; }
576
- set shellThickness(value) { this.shellThicknessProperty.value = value; }
577
- get faceThicknessProperty() {
578
- if (!this._faceThicknessProperty)
579
- this._faceThicknessProperty = new DialogProperty(new LengthDescription("hollowFaceThickness", EditTools.translate("HollowFaces.Label.FaceThickness")), 0.0, undefined);
580
- return this._faceThicknessProperty;
581
- }
582
- get faceThickness() { return this.faceThicknessProperty.value; }
583
- set faceThickness(value) { this.faceThicknessProperty.value = value; }
584
- get geometryCacheFilter() {
585
- return { parts: true, curves: false, surfaces: false, solids: true, other: false };
586
- }
587
- async applyAgendaOperation(ev, isAccept) {
588
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
589
- return undefined;
590
- try {
591
- this._startedCmd = await this.startCommand();
592
- const params = { faces: this.getAcceptedSubEntities(), distances: this.faceThickness, defaultDistance: this.shellThickness };
593
- const opts = {
594
- wantGraphic: isAccept ? undefined : true,
595
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
596
- requestId: `${this.toolId}:${this.agenda.elements[0]}`,
597
- writeChanges: isAccept ? true : undefined,
598
- };
599
- return await solidModelingIpc.hollowFaces(this.agenda.elements[0], params, opts);
600
- }
601
- catch (err) {
602
- return undefined;
603
- }
604
- }
605
- async applyToolSettingPropertyChange(updatedValue) {
606
- return this.changeToolSettingPropertyValue(updatedValue);
607
- }
608
- supplyToolSettingsProperties() {
609
- this.initializeToolSettingPropertyValues([this.shellThicknessProperty, this.faceThicknessProperty]);
610
- const toolSettings = new Array();
611
- toolSettings.push(this.shellThicknessProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
612
- toolSettings.push(this.faceThicknessProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
613
- return toolSettings;
614
- }
615
- async onRestartTool() {
616
- const tool = new HollowFacesTool();
617
- if (!await tool.run())
618
- return this.exitTool();
619
- }
620
- }
621
- HollowFacesTool.toolId = "HollowFaces";
622
- HollowFacesTool.iconSpec = "icon-move"; // TODO: Need better icon...
623
- export { HollowFacesTool };
624
- /** @alpha Identify faces or edges for removal by growing surrounding faces. */
625
- class DeleteSubEntitiesTool extends LocateSubEntityTool {
626
- wantSubEntityType(type) {
627
- switch (type) {
628
- case SubEntityType.Face:
629
- case SubEntityType.Edge:
630
- // Choose all faces or all edges...
631
- return (0 === this._acceptedSubEntities.length || this._acceptedSubEntities[0].props.type === type);
632
- default:
633
- return false;
634
- }
635
- }
636
- getMaximumSubEntityHits(type) {
637
- if (!this.wantSubEntityType(type))
638
- return 0;
639
- // Only return single closest edge, avoids having to test for redundant edges on reset...
640
- return (SubEntityType.Edge === type ? 1 : 25);
641
- }
642
- get geometryCacheFilter() {
643
- return { parts: true, curves: false, surfaces: true, solids: true, other: false };
644
- }
645
- async doPickSubEntities(id, ev) {
646
- const hits = await super.doPickSubEntities(id, ev);
647
- if (undefined === hits)
648
- return hits;
649
- // Don't allow reset to select a back edge...
650
- if (SubEntityType.Face === hits[0].subEntity.type)
651
- return hits.filter((hit) => { return SubEntityType.Face === hit.subEntity.type; });
652
- try {
653
- const accept = await solidModelingIpc.isRedundantEdge(id, hits[0].subEntity);
654
- if (accept)
655
- return hits;
656
- if (hits.length > 1 && SubEntityType.Face === hits[1].subEntity.type)
657
- return hits.slice(1); // Accept face of rejected edge...
658
- return undefined;
659
- }
660
- catch (err) {
661
- return undefined;
662
- }
663
- }
664
- async applyAgendaOperation(ev, isAccept) {
665
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
666
- return undefined;
667
- try {
668
- this._startedCmd = await this.startCommand();
669
- const params = { subEntities: this.getAcceptedSubEntities() };
670
- const opts = {
671
- wantGraphic: isAccept ? undefined : true,
672
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
673
- requestId: `${this.toolId}:${this.agenda.elements[0]}`,
674
- writeChanges: isAccept ? true : undefined,
675
- };
676
- return await solidModelingIpc.deleteSubEntities(this.agenda.elements[0], params, opts);
677
- }
678
- catch (err) {
679
- return undefined;
680
- }
681
- }
682
- async onRestartTool() {
683
- const tool = new DeleteSubEntitiesTool();
684
- if (!await tool.run())
685
- return this.exitTool();
686
- }
687
- }
688
- DeleteSubEntitiesTool.toolId = "DeleteSubEntities";
689
- DeleteSubEntitiesTool.iconSpec = "icon-move"; // TODO: Need better icon...
690
- export { DeleteSubEntitiesTool };
691
- /** @alpha */
692
- export var ImprintSolidMethod;
693
- (function (ImprintSolidMethod) {
694
- /** Imprint intersection with another element */
695
- ImprintSolidMethod[ImprintSolidMethod["Element"] = 0] = "Element";
696
- /** Imprint offset edges onto face */
697
- ImprintSolidMethod[ImprintSolidMethod["Edges"] = 1] = "Edges";
698
- /** Imprint line string defined by points onto face */
699
- ImprintSolidMethod[ImprintSolidMethod["Points"] = 2] = "Points";
700
- })(ImprintSolidMethod || (ImprintSolidMethod = {}));
701
- /** @alpha Identify edges or elements to imprint on solid or surface. */
702
- class ImprintSolidElementsTool extends LocateSubEntityTool {
703
- constructor() {
704
- super(...arguments);
705
- this.points = [];
706
- }
707
- static methodMessage(str) { return EditTools.translate(`ImprintSolids.Method.${str}`); }
708
- get methodProperty() {
709
- if (!this._methodProperty)
710
- this._methodProperty = new DialogProperty(PropertyDescriptionHelper.buildEnumPicklistEditorDescription("imprintMethod", EditTools.translate("ImprintSolids.Label.Method"), ImprintSolidElementsTool.getMethodChoices()), ImprintSolidMethod.Element);
711
- return this._methodProperty;
712
- }
713
- get method() { return this.methodProperty.value; }
714
- set method(method) { this.methodProperty.value = method; }
715
- get distanceProperty() {
716
- if (!this._distanceProperty)
717
- this._distanceProperty = new DialogProperty(new LengthDescription("imprintDistance", EditTools.translate("ImprintSolids.Label.Distance")), 0.1, undefined);
718
- return this._distanceProperty;
719
- }
720
- get distance() { return this.distanceProperty.value; }
721
- set distance(value) { this.distanceProperty.value = value; }
722
- get extendProperty() {
723
- if (!this._extendProperty)
724
- this._extendProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("imprintExtend", EditTools.translate("ImprintSolids.Label.Extend")), false);
725
- return this._extendProperty;
726
- }
727
- get extend() { return this.extendProperty.value; }
728
- set extend(value) { this.extendProperty.value = value; }
729
- get requiredSubEntityCount() { return ImprintSolidMethod.Element === this.method ? 0 : 1; }
730
- get requiredElementCount() { return ImprintSolidMethod.Element === this.method ? 2 : 1; }
731
- get allowSubEntityControlSelect() { return ImprintSolidMethod.Edges === this.method; }
732
- get inhibitSubEntityDisplay() { return ImprintSolidMethod.Points === this.method ? false : super.inhibitSubEntityDisplay; }
733
- wantSubEntityType(type) {
734
- switch (type) {
735
- case SubEntityType.Face:
736
- return ImprintSolidMethod.Points === this.method;
737
- case SubEntityType.Edge:
738
- return ImprintSolidMethod.Edges === this.method;
739
- default:
740
- return false;
741
- }
742
- }
743
- get wantDynamics() { return ImprintSolidMethod.Points === this.method; }
744
- get wantAccuSnap() { return ImprintSolidMethod.Points === this.method && this.isDynamicsStarted; }
745
- get geometryCacheFilter() {
746
- return { parts: true, curves: !this.agenda.isEmpty, surfaces: true, solids: true, other: false };
747
- }
748
- async onAgendaModified() {
749
- // Filter changes to allow imprinting an open path, invalidate cached accept status...
750
- if (ImprintSolidMethod.Element === this.method && (this.agenda.isEmpty || 1 === this.agenda.length))
751
- this.onGeometryCacheFilterChanged();
752
- }
753
- async createSubEntityData(id, hit) {
754
- const data = await super.createSubEntityData(id, hit);
755
- if (undefined !== hit.point && undefined !== hit.normal)
756
- data.toolData = FaceLocationData.create(hit.point, hit.normal);
757
- return data;
758
- }
759
- async applyAgendaOperation(_ev, isAccept) {
760
- if (!isAccept || this.agenda.length < this.requiredElementCount)
761
- return undefined;
762
- const id = this.agenda.elements[0];
763
- try {
764
- this._startedCmd = await this.startCommand();
765
- let params;
766
- if (ImprintSolidMethod.Points === this.method) {
767
- if (!this.haveAcceptedSubEntities)
768
- return undefined;
769
- const geom = ElementGeometry.fromGeometryQuery(LineString3d.create(this.points));
770
- if (undefined === geom)
771
- return undefined;
772
- params = { imprint: geom, face: this.getAcceptedSubEntityData(0)?.props, extend: this.extend ? true : undefined };
773
- }
774
- else if (ImprintSolidMethod.Edges === this.method) {
775
- if (!this.haveAcceptedSubEntities)
776
- return undefined;
777
- // TODO: Include all accepted edges...
778
- const edge = this.getAcceptedSubEntityData(0)?.props;
779
- if (undefined === edge)
780
- return undefined;
781
- const edgeFaces = await solidModelingIpc.getConnectedSubEntities(id, edge, SubEntityType.Face);
782
- if (undefined === edgeFaces || 0 === edgeFaces.length)
783
- return undefined;
784
- // TODO: Check planar face...get preferred face from cursor location in dynamics, etc.
785
- const edgeLoop = await solidModelingIpc.getConnectedSubEntities(id, edge, SubEntityType.Edge, { loopFace: edgeFaces[0] });
786
- if (undefined === edgeLoop || 0 === edgeLoop.length)
787
- return undefined;
788
- params = { imprint: edgeLoop, face: edgeFaces[0], distance: this.distance, extend: this.extend ? true : undefined };
789
- }
790
- else {
791
- params = { imprint: this.agenda.elements[1], extend: this.extend ? true : undefined };
792
- }
793
- const opts = { writeChanges: true };
794
- return await solidModelingIpc.imprintBody(id, params, opts);
795
- }
796
- catch (err) {
797
- return undefined;
798
- }
799
- }
800
- onDynamicFrame(ev, context) {
801
- if (ImprintSolidMethod.Points !== this.method || 0 === this.points.length)
802
- return;
803
- const pts = this.points.slice();
804
- pts.push(ev.point.clone());
805
- const builder = context.createGraphic({ type: GraphicType.WorldOverlay });
806
- builder.setSymbology(context.viewport.getContrastToBackgroundColor(), ColorDef.black, 3);
807
- builder.addLineString(pts);
808
- context.addGraphic(builder.finish());
809
- }
810
- async gatherInput(ev) {
811
- switch (this.method) {
812
- case ImprintSolidMethod.Points: {
813
- if (!this.haveAcceptedSubEntities)
814
- break;
815
- this.points.push(ev.point.clone());
816
- if (!ev.isControlKey)
817
- break;
818
- this.setupAndPromptForNextAction();
819
- return EventHandled.No;
820
- }
821
- default:
822
- break;
823
- }
824
- return super.gatherInput(ev);
825
- }
826
- get wantAdditionalInput() {
827
- switch (this.method) {
828
- case ImprintSolidMethod.Element:
829
- return false;
830
- case ImprintSolidMethod.Edges:
831
- return super.wantAdditionalInput;
832
- case ImprintSolidMethod.Points:
833
- return super.wantAdditionalInput || this.points.length < 2;
834
- }
835
- }
836
- setupAccuDraw() {
837
- if (ImprintSolidMethod.Points !== this.method || 0 !== this.points.length)
838
- return;
839
- if (!this.haveAcceptedSubEntities)
840
- return;
841
- const faceData = this.getAcceptedSubEntityData()?.toolData;
842
- if (undefined === faceData)
843
- return;
844
- const hints = new AccuDrawHintBuilder();
845
- hints.setModeRectangular();
846
- hints.setOrigin(faceData.point);
847
- hints.setNormal(faceData.normal);
848
- hints.sendHints(false);
849
- }
850
- async applyToolSettingPropertyChange(updatedValue) {
851
- if (!this.changeToolSettingPropertyValue(updatedValue))
852
- return false;
853
- if (updatedValue.propertyName === this.methodProperty.name)
854
- await this.onReinitialize();
855
- return true;
856
- }
857
- supplyToolSettingsProperties() {
858
- this.initializeToolSettingPropertyValues([this.methodProperty, this.extendProperty, this.distanceProperty]);
859
- const toolSettings = new Array();
860
- toolSettings.push(this.methodProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
861
- switch (this.method) {
862
- case ImprintSolidMethod.Element:
863
- toolSettings.push(this.extendProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
864
- break;
865
- case ImprintSolidMethod.Edges:
866
- toolSettings.push(this.distanceProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
867
- break;
868
- case ImprintSolidMethod.Points:
869
- toolSettings.push(this.extendProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
870
- break;
871
- }
872
- return toolSettings;
873
- }
874
- async onRestartTool() {
875
- const tool = new ImprintSolidElementsTool();
876
- if (!await tool.run())
877
- return this.exitTool();
878
- }
879
- }
880
- ImprintSolidElementsTool.toolId = "ImprintSolids";
881
- ImprintSolidElementsTool.iconSpec = "icon-move"; // TODO: Need better icon...
882
- ImprintSolidElementsTool.getMethodChoices = () => {
883
- return [
884
- { label: ImprintSolidElementsTool.methodMessage("Element"), value: ImprintSolidMethod.Element },
885
- { label: ImprintSolidElementsTool.methodMessage("Edges"), value: ImprintSolidMethod.Edges },
886
- { label: ImprintSolidElementsTool.methodMessage("Points"), value: ImprintSolidMethod.Points },
887
- ];
888
- };
889
- export { ImprintSolidElementsTool };
890
- /** @alpha Base class for tools to identify edges of solids and surfaces and apply blends. */
891
- export class BlendEdgesTool extends LocateSubEntityTool {
892
- get addSmoothProperty() {
893
- if (!this._addSmoothProperty)
894
- this._addSmoothProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("blendSmooth", EditTools.translate("RoundEdges.Label.AddSmooth")), false);
895
- return this._addSmoothProperty;
896
- }
897
- get addSmooth() { return this.addSmoothProperty.value; }
898
- set addSmooth(value) { this.addSmoothProperty.value = value; }
899
- wantSubEntityType(type) { return SubEntityType.Edge === type; }
900
- getSubEntityFilter() {
901
- return { laminarEdges: true, smoothEdges: true };
902
- }
903
- get geometryCacheFilter() {
904
- return { parts: true, curves: false, surfaces: true, solids: true, other: false };
905
- }
906
- async getTangentEdges(id, edge) {
907
- try {
908
- return await solidModelingIpc.getConnectedSubEntities(id, edge, SubEntityType.Edge, { smoothEdges: true });
909
- }
910
- catch (err) {
911
- return undefined;
912
- }
913
- }
914
- async addTangentEdges(id, edge, chordTolerance) {
915
- if (undefined === edge) {
916
- this._acceptedSubEntities.forEach(async (accepted) => {
917
- if (undefined === accepted.toolData)
918
- await this.addTangentEdges(id, accepted.props, accepted.chordTolerance);
919
- });
920
- return;
921
- }
922
- const tangentEdges = await this.getTangentEdges(id, edge);
923
- if (undefined === tangentEdges)
924
- return;
925
- tangentEdges.forEach(async (entry) => {
926
- if (!isSameSubEntity(entry, edge)) {
927
- const data = new SubEntityData(entry);
928
- data.toolData = edge; // Mark edge so we know it was added as tangent edge...
929
- await this.createSubEntityGraphic(id, data, chordTolerance);
930
- this._acceptedSubEntities.push(data);
931
- }
932
- });
933
- }
934
- async removeTangentEdges(_id, edge) {
935
- if (undefined === edge) {
936
- this._acceptedSubEntities = this._acceptedSubEntities.filter((entry) => undefined === entry.toolData);
937
- return;
938
- }
939
- const edgeData = this._acceptedSubEntities.find((entry) => isSameSubEntity(entry.props, edge));
940
- if (undefined === edgeData)
941
- return undefined;
942
- const isTangentEdge = (other) => {
943
- const primaryOther = (undefined !== other.toolData ? other.toolData : other.props);
944
- return isSameSubEntity(primaryEdge, primaryOther);
945
- };
946
- const primaryEdge = (undefined !== edgeData.toolData ? edgeData.toolData : edgeData.props);
947
- this._acceptedSubEntities = this._acceptedSubEntities.filter((entry) => !isTangentEdge(entry));
948
- }
949
- async syncTangentEdges() {
950
- const id = this.getCurrentElement();
951
- if (undefined === id)
952
- return;
953
- if (this.addSmooth)
954
- await this.addTangentEdges(id);
955
- else
956
- await this.removeTangentEdges(id);
957
- IModelApp.viewManager.invalidateDecorationsAllViews();
958
- }
959
- async addSubEntity(id, props) {
960
- await super.addSubEntity(id, props);
961
- if (!this.addSmooth)
962
- return;
963
- const chordTolerance = (this.targetView ? computeChordToleranceFromPoint(this.targetView, Point3d.fromJSON(props.point)) : undefined);
964
- return this.addTangentEdges(id, props.subEntity, chordTolerance);
965
- }
966
- async removeSubEntity(id, props) {
967
- if (!this.addSmooth)
968
- return super.removeSubEntity(id, props);
969
- const edge = (undefined !== props) ? props.subEntity : this.getAcceptedSubEntityData()?.props;
970
- if (undefined === edge)
971
- return;
972
- return this.removeTangentEdges(id, edge);
973
- }
974
- getAcceptedSubEntities() {
975
- const edges = [];
976
- this._acceptedSubEntities.forEach((entry) => {
977
- if (undefined === entry.toolData)
978
- edges.push(entry.props);
979
- });
980
- return edges;
981
- }
982
- }
983
- /** @alpha Identify edges of solids and surfaces to apply a rolling ball blend to. */
984
- class RoundEdgesTool extends BlendEdgesTool {
985
- get radiusProperty() {
986
- if (!this._radiusProperty)
987
- this._radiusProperty = new DialogProperty(new LengthDescription("roundRadius", EditTools.translate("RoundEdges.Label.Radius")), 0.1, undefined);
988
- return this._radiusProperty;
989
- }
990
- get radius() { return this.radiusProperty.value; }
991
- set radius(value) { this.radiusProperty.value = value; }
992
- async applyAgendaOperation(ev, isAccept) {
993
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
994
- return undefined;
995
- try {
996
- this._startedCmd = await this.startCommand();
997
- const params = { edges: this.getAcceptedSubEntities(), radii: this.radius, propagateSmooth: this.addSmooth };
998
- const opts = {
999
- wantGraphic: isAccept ? undefined : true,
1000
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
1001
- requestId: `${this.toolId}:${this.agenda.elements[0]}`,
1002
- writeChanges: isAccept ? true : undefined,
1003
- };
1004
- return await solidModelingIpc.blendEdges(this.agenda.elements[0], params, opts);
1005
- }
1006
- catch (err) {
1007
- return undefined;
1008
- }
1009
- }
1010
- async applyToolSettingPropertyChange(updatedValue) {
1011
- if (!this.changeToolSettingPropertyValue(updatedValue))
1012
- return false;
1013
- if (updatedValue.propertyName === this.addSmoothProperty.name)
1014
- await this.syncTangentEdges();
1015
- return true;
1016
- }
1017
- supplyToolSettingsProperties() {
1018
- this.initializeToolSettingPropertyValues([this.radiusProperty, this.addSmoothProperty]);
1019
- const toolSettings = new Array();
1020
- toolSettings.push(this.radiusProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
1021
- toolSettings.push(this.addSmoothProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1022
- return toolSettings;
1023
- }
1024
- async onRestartTool() {
1025
- const tool = new RoundEdgesTool();
1026
- if (!await tool.run())
1027
- return this.exitTool();
1028
- }
1029
- }
1030
- RoundEdgesTool.toolId = "RoundEdges";
1031
- RoundEdgesTool.iconSpec = "icon-move"; // TODO: Need better icon...
1032
- export { RoundEdgesTool };
1033
- /** @alpha Identify edges of solids and surfaces to apply a rolling ball blend to. */
1034
- class ChamferEdgesTool extends BlendEdgesTool {
1035
- static methodMessage(str) { return EditTools.translate(`ChamferEdges.Method.${str}`); }
1036
- get methodProperty() {
1037
- if (!this._methodProperty)
1038
- this._methodProperty = new DialogProperty(PropertyDescriptionHelper.buildEnumPicklistEditorDescription("chamferMethod", EditTools.translate("ChamferEdges.Label.Method"), ChamferEdgesTool.getMethodChoices()), ChamferMode.Length);
1039
- return this._methodProperty;
1040
- }
1041
- get method() { return this.methodProperty.value; }
1042
- set method(method) { this.methodProperty.value = method; }
1043
- get lengthProperty() {
1044
- if (!this._lengthProperty)
1045
- this._lengthProperty = new DialogProperty(new LengthDescription("chamferLength", EditTools.translate("ChamferEdges.Label.Length")), 0.1, undefined);
1046
- return this._lengthProperty;
1047
- }
1048
- get length() { return this.lengthProperty.value; }
1049
- set length(value) { this.lengthProperty.value = value; }
1050
- get distanceLeftProperty() {
1051
- if (!this._distanceLeftProperty)
1052
- this._distanceLeftProperty = new DialogProperty(new LengthDescription("chamferLeftDist", EditTools.translate("ChamferEdges.Label.LeftDistance")), 0.1, undefined);
1053
- return this._distanceLeftProperty;
1054
- }
1055
- get distanceLeft() { return this.distanceLeftProperty.value; }
1056
- set distanceLeft(value) { this.distanceLeftProperty.value = value; }
1057
- get distanceRightProperty() {
1058
- if (!this._distanceRightProperty)
1059
- this._distanceRightProperty = new DialogProperty(new LengthDescription("chamferRightDist", EditTools.translate("ChamferEdges.Label.RightDistance")), 0.1, undefined);
1060
- return this._distanceRightProperty;
1061
- }
1062
- get distanceRight() { return this.distanceRightProperty.value; }
1063
- set distanceRight(value) { this.distanceRightProperty.value = value; }
1064
- get angleProperty() {
1065
- if (!this._angleProperty)
1066
- this._angleProperty = new DialogProperty(new AngleDescription("chamferAngle", EditTools.translate("ChamferEdges.Label.Angle")), Angle.piOver4Radians, undefined, false);
1067
- return this._angleProperty;
1068
- }
1069
- get angle() { return this.angleProperty.value; }
1070
- set angle(value) { this.angleProperty.value = value; }
1071
- async applyAgendaOperation(ev, isAccept) {
1072
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
1073
- return undefined;
1074
- try {
1075
- this._startedCmd = await this.startCommand();
1076
- let values1;
1077
- let values2;
1078
- switch (this.method) {
1079
- case ChamferMode.Length:
1080
- values1 = this.length;
1081
- break;
1082
- case ChamferMode.Distances:
1083
- values1 = this.distanceLeft;
1084
- values2 = this.distanceRight;
1085
- break;
1086
- case ChamferMode.DistanceAngle:
1087
- values1 = this.distanceLeft;
1088
- values2 = this.angle;
1089
- break;
1090
- case ChamferMode.AngleDistance:
1091
- values1 = this.angle;
1092
- values2 = this.distanceRight;
1093
- break;
1094
- default:
1095
- return undefined;
1096
- }
1097
- const params = { edges: this.getAcceptedSubEntities(), mode: this.method, values1, values2, propagateSmooth: this.addSmooth };
1098
- const opts = {
1099
- wantGraphic: isAccept ? undefined : true,
1100
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
1101
- requestId: `${this.toolId}:${this.agenda.elements[0]}`,
1102
- writeChanges: isAccept ? true : undefined,
1103
- };
1104
- return await solidModelingIpc.chamferEdges(this.agenda.elements[0], params, opts);
1105
- }
1106
- catch (err) {
1107
- return undefined;
1108
- }
1109
- }
1110
- async applyToolSettingPropertyChange(updatedValue) {
1111
- if (!this.changeToolSettingPropertyValue(updatedValue))
1112
- return false;
1113
- if (updatedValue.propertyName === this.methodProperty.name)
1114
- await this.onReinitialize();
1115
- return true;
1116
- }
1117
- supplyToolSettingsProperties() {
1118
- this.initializeToolSettingPropertyValues([this.methodProperty, this.addSmoothProperty, this.lengthProperty, this.distanceLeftProperty, this.distanceRightProperty, this.angleProperty]);
1119
- const toolSettings = new Array();
1120
- toolSettings.push(this.methodProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
1121
- toolSettings.push(this.addSmoothProperty.toDialogItem({ rowPriority: ChamferMode.Length === this.method ? 3 : 4, columnIndex: 0 }));
1122
- switch (this.method) {
1123
- case ChamferMode.Length:
1124
- toolSettings.push(this.lengthProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1125
- break;
1126
- case ChamferMode.Distances:
1127
- toolSettings.push(this.distanceLeftProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1128
- toolSettings.push(this.distanceRightProperty.toDialogItem({ rowPriority: 3, columnIndex: 0 }));
1129
- break;
1130
- case ChamferMode.DistanceAngle:
1131
- toolSettings.push(this.distanceLeftProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1132
- toolSettings.push(this.angleProperty.toDialogItem({ rowPriority: 3, columnIndex: 0 }));
1133
- break;
1134
- case ChamferMode.AngleDistance:
1135
- toolSettings.push(this.distanceRightProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1136
- toolSettings.push(this.angleProperty.toDialogItem({ rowPriority: 3, columnIndex: 0 }));
1137
- break;
1138
- }
1139
- return toolSettings;
1140
- }
1141
- async onRestartTool() {
1142
- const tool = new ChamferEdgesTool();
1143
- if (!await tool.run())
1144
- return this.exitTool();
1145
- }
1146
- }
1147
- ChamferEdgesTool.toolId = "ChamferEdges";
1148
- ChamferEdgesTool.iconSpec = "icon-move"; // TODO: Need better icon...
1149
- ChamferEdgesTool.getMethodChoices = () => {
1150
- return [
1151
- { label: ChamferEdgesTool.methodMessage("Length"), value: ChamferMode.Length },
1152
- { label: ChamferEdgesTool.methodMessage("Distances"), value: ChamferMode.Distances },
1153
- { label: ChamferEdgesTool.methodMessage("DistanceAngle"), value: ChamferMode.DistanceAngle },
1154
- { label: ChamferEdgesTool.methodMessage("AngleDistance"), value: ChamferMode.AngleDistance },
1155
- ];
1156
- };
1157
- export { ChamferEdgesTool };
1158
- /** @alpha */
1159
- export class ProfileLocationData {
1160
- constructor(point, orientation) {
1161
- this.point = point;
1162
- this.orientation = orientation;
1163
- }
1164
- }
1165
- /** @alpha Base class for picking profiles (open paths and regions) or faces of solids. */
1166
- export class LocateFaceOrProfileTool extends LocateSubEntityTool {
1167
- get wantGeometrySummary() { return true; }
1168
- wantSubEntityType(type) {
1169
- switch (type) {
1170
- case SubEntityType.Face:
1171
- case SubEntityType.Edge:
1172
- // Choose all faces or all edges...
1173
- return (0 === this._acceptedSubEntities.length || this._acceptedSubEntities[0].props.type === type);
1174
- default:
1175
- return false;
1176
- }
1177
- }
1178
- get geometryCacheFilter() {
1179
- return { parts: true, curves: true, surfaces: true, solids: true, other: false };
1180
- }
1181
- async doPickSubEntities(id, ev) {
1182
- const hits = await super.doPickSubEntities(id, ev);
1183
- if (undefined === hits)
1184
- return hits;
1185
- // Only want edges from wire bodies...
1186
- const accept = (BRepEntityType.Wire === this.getBRepEntityTypeForSubEntity(id, hits[0].subEntity) ? SubEntityType.Edge : SubEntityType.Face);
1187
- return hits.filter((hit) => accept === hit.subEntity.type);
1188
- }
1189
- async createSubEntityData(id, hit) {
1190
- const data = await super.createSubEntityData(id, hit);
1191
- // Prefer orientation from snap to take entire path curve as well as placement z into account...
1192
- const snap = TentativeOrAccuSnap.getCurrentSnap(false);
1193
- const point = (id === snap?.sourceId && snap.isHot ? snap.snapPoint : Point3d.fromJSON(hit.point));
1194
- const matrix = (id === snap?.sourceId ? AccuDraw.getSnapRotation(snap, undefined) : undefined);
1195
- const invMatrix = matrix?.inverse(); // getSnapRotation returns row matrix...
1196
- if (undefined !== invMatrix)
1197
- data.toolData = new ProfileLocationData(point, invMatrix);
1198
- else
1199
- data.toolData = new ProfileLocationData(point, undefined !== hit.normal ? Vector3d.fromJSON(hit.normal) : Vector3d.unitZ());
1200
- return data;
1201
- }
1202
- drawSubEntity(context, subEntity, accepted) {
1203
- const id = this.getCurrentElement();
1204
- if (undefined !== id && BRepEntityType.Solid !== this.getBRepEntityTypeForSubEntity(id, subEntity.props))
1205
- return; // Operation will be applied to wire or sheet body, don't display sub-entity...
1206
- super.drawSubEntity(context, subEntity, accepted);
1207
- }
1208
- drawAcceptedSubEntities(context) {
1209
- super.drawAcceptedSubEntities(context);
1210
- // Show pick point on last identified face...
1211
- const profileData = this.getAcceptedSubEntityData()?.toolData;
1212
- if (undefined === profileData)
1213
- return;
1214
- const builder = context.createGraphic({ type: GraphicType.WorldOverlay });
1215
- builder.setSymbology(context.viewport.getContrastToBackgroundColor(), ColorDef.black, 10);
1216
- builder.addPointString([profileData.point]);
1217
- context.addDecorationFromBuilder(builder);
1218
- }
1219
- }
1220
- /** @alpha Identify faces of solids and surfaces to translate. */
1221
- class SweepFacesTool extends LocateFaceOrProfileTool {
1222
- get wantDynamics() { return true; }
1223
- get wantAccuSnap() { return true; }
1224
- get wantSubEntitySnap() { return true; }
1225
- get addSmoothProperty() {
1226
- if (!this._addSmoothProperty)
1227
- this._addSmoothProperty = new DialogProperty(PropertyDescriptionHelper.buildToggleDescription("sweepSmooth", EditTools.translate("SweepFaces.Label.AddSmooth")), false);
1228
- return this._addSmoothProperty;
1229
- }
1230
- get addSmooth() { return this.addSmoothProperty.value; }
1231
- set addSmooth(value) { this.addSmoothProperty.value = value; }
1232
- get useDistanceProperty() {
1233
- if (!this._useDistanceProperty)
1234
- this._useDistanceProperty = new DialogProperty(PropertyDescriptionHelper.buildLockPropertyDescription("useOffsetDistance"), false);
1235
- return this._useDistanceProperty;
1236
- }
1237
- get useDistance() { return this.useDistanceProperty.value; }
1238
- set useDistance(value) { this.useDistanceProperty.value = value; }
1239
- get distanceProperty() {
1240
- if (!this._distanceProperty)
1241
- this._distanceProperty = new DialogProperty(new LengthDescription("sweepDistance", EditTools.translate("SweepFaces.Label.Distance")), 0.1, undefined, !this.useDistance);
1242
- return this._distanceProperty;
1243
- }
1244
- get distance() { return this.distanceProperty.value; }
1245
- set distance(value) { this.distanceProperty.value = value; }
1246
- async getSmoothFaces(id, face) {
1247
- try {
1248
- // NOTE: For sweep/translation, it makes sense to limit smooth to immediately adjacent...
1249
- return await solidModelingIpc.getConnectedSubEntities(id, face, SubEntityType.Face, { smoothFaces: true, adjacentFaces: true });
1250
- }
1251
- catch (err) {
1252
- return undefined;
1253
- }
1254
- }
1255
- async applyAgendaOperation(ev, isAccept) {
1256
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities)
1257
- return undefined;
1258
- const profileData = this.getAcceptedSubEntityData()?.toolData;
1259
- if (undefined === profileData)
1260
- return undefined;
1261
- const path = Vector3d.createStartEnd(profileData.point, ev.point);
1262
- if (this.useDistance && undefined === path.scaleToLength(this.distance, path))
1263
- return undefined;
1264
- if (path.magnitude() < Geometry.smallMetricDistance)
1265
- return undefined;
1266
- if (!this.useDistance) {
1267
- this.distance = path.magnitude();
1268
- this.syncToolSettingPropertyValue(this.distanceProperty);
1269
- if (isAccept)
1270
- this.saveToolSettingPropertyValue(this.distanceProperty, this.distanceProperty.dialogItemValue);
1271
- }
1272
- try {
1273
- this._startedCmd = await this.startCommand();
1274
- const id = this.agenda.elements[0];
1275
- const opts = {
1276
- wantGraphic: isAccept ? undefined : true,
1277
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
1278
- requestId: `${this.toolId}:${id}`,
1279
- writeChanges: isAccept ? true : undefined,
1280
- };
1281
- const subEntities = this.getAcceptedSubEntities();
1282
- const params = { path };
1283
- if (SubEntityType.Edge === subEntities[0].type || BRepEntityType.Solid !== this.getBRepEntityTypeForSubEntity(id, subEntities[0])) {
1284
- return await solidModelingIpc.sweepFaces(id, params, opts);
1285
- }
1286
- if (this.addSmooth) {
1287
- const allSmoothFaces = [];
1288
- for (const face of subEntities) {
1289
- const smoothFaces = await this.getSmoothFaces(id, face);
1290
- if (undefined !== smoothFaces)
1291
- allSmoothFaces.push(...smoothFaces);
1292
- }
1293
- for (const smooth of allSmoothFaces) {
1294
- if (undefined === subEntities.find((selected) => isSameSubEntity(selected, smooth)))
1295
- subEntities.unshift(smooth); // Preserve last selected entry as reference face...
1296
- }
1297
- }
1298
- params.faces = subEntities;
1299
- return await solidModelingIpc.sweepFaces(id, params, opts);
1300
- }
1301
- catch (err) {
1302
- return undefined;
1303
- }
1304
- }
1305
- setupAccuDraw() {
1306
- if (!this.haveAcceptedSubEntities)
1307
- return;
1308
- const profileData = this.getAcceptedSubEntityData()?.toolData;
1309
- if (undefined === profileData)
1310
- return;
1311
- const hints = new AccuDrawHintBuilder();
1312
- hints.setOriginFixed = true;
1313
- hints.setLockY = true;
1314
- hints.setLockZ = true;
1315
- hints.setModeRectangular();
1316
- hints.setOrigin(profileData.point);
1317
- hints.setXAxis2(profileData.orientation instanceof Matrix3d ? profileData.orientation.getColumn(2) : profileData.orientation);
1318
- hints.sendHints(false);
1319
- }
1320
- async applyToolSettingPropertyChange(updatedValue) {
1321
- return this.changeToolSettingPropertyValue(updatedValue);
1322
- }
1323
- supplyToolSettingsProperties() {
1324
- this.initializeToolSettingPropertyValues([this.addSmoothProperty, this.useDistanceProperty, this.distanceProperty]);
1325
- const toolSettings = new Array();
1326
- // ensure controls are enabled/disabled based on current lock property state
1327
- this.distanceProperty.isDisabled = !this.useDistance;
1328
- const useDistanceLock = this.useDistanceProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 });
1329
- toolSettings.push(this.distanceProperty.toDialogItem({ rowPriority: 1, columnIndex: 1 }, useDistanceLock));
1330
- toolSettings.push(this.addSmoothProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1331
- return toolSettings;
1332
- }
1333
- async onRestartTool() {
1334
- const tool = new SweepFacesTool();
1335
- if (!await tool.run())
1336
- return this.exitTool();
1337
- }
1338
- }
1339
- SweepFacesTool.toolId = "SweepFaces";
1340
- SweepFacesTool.iconSpec = "icon-move"; // TODO: Need better icon...
1341
- export { SweepFacesTool };
1342
- /** @alpha Identify faces of solids and surfaces to revolve. */
1343
- class SpinFacesTool extends LocateFaceOrProfileTool {
1344
- constructor() {
1345
- super(...arguments);
1346
- this.points = [];
1347
- }
1348
- get angleProperty() {
1349
- if (!this._angleProperty)
1350
- this._angleProperty = new DialogProperty(new AngleDescription("spinAngle", EditTools.translate("SpinFaces.Label.Angle")), Angle.piOver2Radians, undefined, false);
1351
- return this._angleProperty;
1352
- }
1353
- get angle() { return this.angleProperty.value; }
1354
- set angle(value) { this.angleProperty.value = value; }
1355
- get wantDynamics() { return true; }
1356
- get wantAccuSnap() { return true; }
1357
- get wantSubEntitySnap() { return true; }
1358
- async applyAgendaOperation(ev, isAccept) {
1359
- if (undefined === ev.viewport || this.agenda.isEmpty || !this.haveAcceptedSubEntities || this.points.length < (isAccept ? 2 : 1))
1360
- return undefined;
1361
- const direction = Vector3d.createStartEnd(this.points[0], isAccept ? this.points[1] : ev.point);
1362
- if (direction.magnitude() < Geometry.smallMetricDistance)
1363
- return undefined;
1364
- const origin = this.points[0];
1365
- const angle = Angle.createRadians(this.angle);
1366
- try {
1367
- this._startedCmd = await this.startCommand();
1368
- const id = this.agenda.elements[0];
1369
- const opts = {
1370
- wantGraphic: isAccept ? undefined : true,
1371
- chordTolerance: computeChordToleranceFromPoint(ev.viewport, ev.point),
1372
- requestId: `${this.toolId}:${id}`,
1373
- writeChanges: isAccept ? true : undefined,
1374
- };
1375
- const subEntities = this.getAcceptedSubEntities();
1376
- const params = { origin, direction, angle };
1377
- if (SubEntityType.Edge === subEntities[0].type || BRepEntityType.Solid !== this.getBRepEntityTypeForSubEntity(id, subEntities[0])) {
1378
- return await solidModelingIpc.spinFaces(id, params, opts);
1379
- }
1380
- params.faces = subEntities;
1381
- let result = await solidModelingIpc.spinFaces(id, params, opts);
1382
- // Spun face can be used to create a pocket...retry with negative sweep...
1383
- if (undefined === result) {
1384
- angle.setRadians(-angle.radians);
1385
- result = await solidModelingIpc.spinFaces(id, params, opts);
1386
- }
1387
- return result;
1388
- }
1389
- catch (err) {
1390
- return undefined;
1391
- }
1392
- }
1393
- onDynamicFrame(ev, context) {
1394
- if (0 === this.points.length)
1395
- return;
1396
- const pts = this.points.slice();
1397
- pts.push(ev.point.clone());
1398
- const builder = context.createGraphic({ type: GraphicType.WorldOverlay });
1399
- builder.setSymbology(context.viewport.getContrastToBackgroundColor(), ColorDef.black, 3);
1400
- builder.addLineString(pts);
1401
- context.addGraphic(builder.finish());
1402
- super.onDynamicFrame(ev, context);
1403
- }
1404
- async gatherInput(ev) {
1405
- if (!this.wantAdditionalSubEntities)
1406
- this.points.push(ev.point.clone());
1407
- return super.gatherInput(ev);
1408
- }
1409
- get wantAdditionalInput() {
1410
- return super.wantAdditionalInput || this.points.length < 2;
1411
- }
1412
- setupAccuDraw() {
1413
- if (!this.haveAcceptedSubEntities || 0 !== this.points.length)
1414
- return;
1415
- const profileData = this.getAcceptedSubEntityData()?.toolData;
1416
- if (undefined === profileData)
1417
- return;
1418
- const hints = new AccuDrawHintBuilder();
1419
- hints.setModeRectangular();
1420
- hints.setOrigin(profileData.point);
1421
- if (profileData.orientation instanceof Matrix3d)
1422
- hints.setMatrix(profileData.orientation);
1423
- else
1424
- hints.setNormal(profileData.orientation);
1425
- hints.sendHints(false);
1426
- }
1427
- async applyToolSettingPropertyChange(updatedValue) {
1428
- return this.changeToolSettingPropertyValue(updatedValue);
1429
- }
1430
- supplyToolSettingsProperties() {
1431
- this.initializeToolSettingPropertyValues([this.angleProperty]);
1432
- const toolSettings = new Array();
1433
- toolSettings.push(this.angleProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
1434
- return toolSettings;
1435
- }
1436
- async onRestartTool() {
1437
- const tool = new SpinFacesTool();
1438
- if (!await tool.run())
1439
- return this.exitTool();
1440
- }
1441
- }
1442
- SpinFacesTool.toolId = "SpinFaces";
1443
- SpinFacesTool.iconSpec = "icon-move"; // TODO: Need better icon...
1444
- export { SpinFacesTool };
1445
- //# sourceMappingURL=SolidModelingTools.js.map