@itwin/editor-frontend 3.0.0-dev.98 → 3.0.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 (61) hide show
  1. package/CHANGELOG.md +108 -1
  2. package/LICENSE.md +1 -1
  3. package/README.md +9 -9
  4. package/lib/cjs/EditTool.d.ts.map +1 -1
  5. package/lib/cjs/EditTool.js +18 -7
  6. package/lib/cjs/EditTool.js.map +1 -1
  7. package/lib/cjs/ElementGeometryTool.d.ts +64 -80
  8. package/lib/cjs/ElementGeometryTool.d.ts.map +1 -1
  9. package/lib/cjs/ElementGeometryTool.js +333 -295
  10. package/lib/cjs/ElementGeometryTool.js.map +1 -1
  11. package/lib/cjs/ProjectLocation/ProjectGeolocation.d.ts +10 -17
  12. package/lib/cjs/ProjectLocation/ProjectGeolocation.d.ts.map +1 -1
  13. package/lib/cjs/ProjectLocation/ProjectGeolocation.js +54 -94
  14. package/lib/cjs/ProjectLocation/ProjectGeolocation.js.map +1 -1
  15. package/lib/cjs/SketchTools.d.ts +21 -9
  16. package/lib/cjs/SketchTools.d.ts.map +1 -1
  17. package/lib/cjs/SketchTools.js +197 -204
  18. package/lib/cjs/SketchTools.js.map +1 -1
  19. package/lib/cjs/SolidModelingTools.d.ts +381 -0
  20. package/lib/cjs/SolidModelingTools.d.ts.map +1 -0
  21. package/lib/cjs/SolidModelingTools.js +1460 -0
  22. package/lib/cjs/SolidModelingTools.js.map +1 -0
  23. package/lib/cjs/TransformElementsTool.d.ts.map +1 -1
  24. package/lib/cjs/TransformElementsTool.js +8 -28
  25. package/lib/cjs/TransformElementsTool.js.map +1 -1
  26. package/lib/cjs/UndoRedoTool.js +1 -1
  27. package/lib/cjs/UndoRedoTool.js.map +1 -1
  28. package/lib/cjs/editor-frontend.d.ts +1 -0
  29. package/lib/cjs/editor-frontend.d.ts.map +1 -1
  30. package/lib/cjs/editor-frontend.js +1 -0
  31. package/lib/cjs/editor-frontend.js.map +1 -1
  32. package/lib/esm/EditTool.d.ts.map +1 -1
  33. package/lib/esm/EditTool.js +14 -3
  34. package/lib/esm/EditTool.js.map +1 -1
  35. package/lib/esm/ElementGeometryTool.d.ts +64 -80
  36. package/lib/esm/ElementGeometryTool.d.ts.map +1 -1
  37. package/lib/esm/ElementGeometryTool.js +334 -290
  38. package/lib/esm/ElementGeometryTool.js.map +1 -1
  39. package/lib/esm/ProjectLocation/ProjectGeolocation.d.ts +10 -17
  40. package/lib/esm/ProjectLocation/ProjectGeolocation.d.ts.map +1 -1
  41. package/lib/esm/ProjectLocation/ProjectGeolocation.js +54 -94
  42. package/lib/esm/ProjectLocation/ProjectGeolocation.js.map +1 -1
  43. package/lib/esm/SketchTools.d.ts +21 -9
  44. package/lib/esm/SketchTools.d.ts.map +1 -1
  45. package/lib/esm/SketchTools.js +198 -205
  46. package/lib/esm/SketchTools.js.map +1 -1
  47. package/lib/esm/SolidModelingTools.d.ts +381 -0
  48. package/lib/esm/SolidModelingTools.d.ts.map +1 -0
  49. package/lib/esm/SolidModelingTools.js +1435 -0
  50. package/lib/esm/SolidModelingTools.js.map +1 -0
  51. package/lib/esm/TransformElementsTool.d.ts.map +1 -1
  52. package/lib/esm/TransformElementsTool.js +8 -28
  53. package/lib/esm/TransformElementsTool.js.map +1 -1
  54. package/lib/esm/UndoRedoTool.js +1 -1
  55. package/lib/esm/UndoRedoTool.js.map +1 -1
  56. package/lib/esm/editor-frontend.d.ts +1 -0
  57. package/lib/esm/editor-frontend.d.ts.map +1 -1
  58. package/lib/esm/editor-frontend.js +1 -0
  59. package/lib/esm/editor-frontend.js.map +1 -1
  60. package/lib/public/locales/en/Editor.json +141 -3
  61. package/package.json +17 -25
@@ -236,6 +236,7 @@ class CreateOrContinuePathTool extends CreateElementTool_1.CreateElementTool {
236
236
  switch (curve.curvePrimitiveType) {
237
237
  case "arc":
238
238
  case "bsplineCurve":
239
+ case "interpolationCurve":
239
240
  break;
240
241
  default:
241
242
  return;
@@ -270,6 +271,12 @@ class CreateOrContinuePathTool extends CreateElementTool_1.CreateElementTool {
270
271
  builder.addPointString(poles);
271
272
  break;
272
273
  }
274
+ case "interpolationCurve": {
275
+ const fitCurve = curve;
276
+ builder.setSymbology(context.viewport.getContrastToBackgroundColor(), core_common_1.ColorDef.black, 5);
277
+ builder.addPointString(fitCurve.options.fitPoints); // deep copy shoulnd't be necessary...
278
+ break;
279
+ }
273
280
  default:
274
281
  break;
275
282
  }
@@ -557,11 +564,17 @@ class CreateOrContinuePathTool extends CreateElementTool_1.CreateElementTool {
557
564
  await this.updateCurveAndContinuationData(ev, false, phase);
558
565
  return true;
559
566
  }
567
+ async cancelPoint(_ev) { return true; }
560
568
  async onDataButtonDown(ev) {
561
569
  if (!await this.acceptPoint(ev))
562
570
  return core_frontend_1.EventHandled.Yes;
563
571
  return super.onDataButtonDown(ev);
564
572
  }
573
+ async onResetButtonUp(ev) {
574
+ if (!await this.cancelPoint(ev))
575
+ return core_frontend_1.EventHandled.Yes;
576
+ return super.onResetButtonUp(ev);
577
+ }
565
578
  async onUndoPreviousStep() {
566
579
  if (0 === this.accepted.length)
567
580
  return false;
@@ -621,13 +634,13 @@ class CreateLineStringTool extends CreateOrContinuePathTool {
621
634
  const pts = (isDynamics ? [...this.accepted, ev.point] : this.accepted);
622
635
  return core_geometry_1.LineString3d.create(pts);
623
636
  }
624
- async onResetButtonUp(ev) {
637
+ async cancelPoint(ev) {
625
638
  // NOTE: Starting another tool will not create element...require reset or closure...
626
639
  if (this.isComplete(ev)) {
627
640
  await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineEnd);
628
641
  await this.createElement();
629
642
  }
630
- return super.onResetButtonUp(ev);
643
+ return true;
631
644
  }
632
645
  async onRestartTool() {
633
646
  const tool = new CreateLineStringTool();
@@ -919,70 +932,28 @@ class CreateArcTool extends CreateOrContinuePathTool {
919
932
  return;
920
933
  }
921
934
  const syncData = [];
922
- if (!this.useRadius) {
923
- this.radiusProperty.displayValue = this.radiusProperty.description.format(this.radius);
924
- this.radiusProperty.isDisabled = !this.useRadius;
935
+ if (!this.useRadius)
925
936
  syncData.push(this.radiusProperty.syncItem);
926
- }
927
- if (!this.useSweep) {
928
- this.sweepProperty.displayValue = this.sweepProperty.description.format(this.sweep);
929
- this.sweepProperty.isDisabled = !this.useSweep;
937
+ if (!this.useSweep)
930
938
  syncData.push(this.sweepProperty.syncItem);
931
- }
932
939
  if (0 !== syncData.length)
933
940
  this.syncToolSettingsProperties(syncData);
934
941
  }
935
- syncRadiusState() {
936
- this.radiusProperty.displayValue = this.radiusProperty.description.format(this.radius);
937
- this.radiusProperty.isDisabled = !this.useRadius;
938
- this.syncToolSettingsProperties([this.radiusProperty.syncItem]);
939
- }
940
- syncSweepState() {
941
- this.sweepProperty.displayValue = this.sweepProperty.description.format(this.sweep);
942
- this.sweepProperty.isDisabled = !this.useSweep;
943
- this.syncToolSettingsProperties([this.sweepProperty.syncItem]);
942
+ getToolSettingPropertyLocked(property) {
943
+ if (property === this.useRadiusProperty)
944
+ return this.radiusProperty;
945
+ else if (property === this.useSweepProperty)
946
+ return this.sweepProperty;
947
+ return undefined;
944
948
  }
945
949
  async applyToolSettingPropertyChange(updatedValue) {
946
- if (this.methodProperty.name === updatedValue.propertyName) {
947
- this.methodProperty.value = updatedValue.value.value;
948
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.methodProperty.item);
950
+ if (!this.changeToolSettingPropertyValue(updatedValue))
951
+ return false;
952
+ if (this.methodProperty.name === updatedValue.propertyName)
949
953
  await this.onReinitialize();
950
- return true;
951
- }
952
- else if (updatedValue.propertyName === this.useRadiusProperty.name) {
953
- this.useRadius = updatedValue.value.value;
954
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.useRadiusProperty.item);
955
- this.syncRadiusState();
956
- return true;
957
- }
958
- else if (updatedValue.propertyName === this.useSweepProperty.name) {
959
- this.useSweep = updatedValue.value.value;
960
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.useSweepProperty.item);
961
- this.syncSweepState();
962
- return true;
963
- }
964
- else if (updatedValue.propertyName === this.radiusProperty.name) {
965
- if (!updatedValue.value.value) {
966
- this.syncRadiusState(); // force UI to redisplay last valid value
967
- return false;
968
- }
969
- this.radius = updatedValue.value.value;
970
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.radiusProperty.item);
971
- // If radius is changed when creating arc by start/center after center has been defined, back up a step to defined a new center point...
972
- if (ArcMethod.StartCenter === this.method && this.useRadius && 2 === this.accepted.length)
973
- await this.onUndoPreviousStep();
974
- return true;
975
- }
976
- else if (updatedValue.propertyName === this.sweepProperty.name) {
977
- if (!updatedValue.value.value) {
978
- this.syncSweepState(); // force UI to redisplay last valid value
979
- return false;
980
- }
981
- this.sweep = updatedValue.value.value;
982
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.sweepProperty.item);
983
- return true;
984
- }
985
- return false;
954
+ else if (updatedValue.propertyName === this.radiusProperty.name && ArcMethod.StartCenter === this.method && this.useRadius && 2 === this.accepted.length)
955
+ await this.onUndoPreviousStep(); // If radius is changed when creating arc by start/center after center has been defined, back up a step to defined a new center point...
956
+ return true;
986
957
  }
987
958
  supplyToolSettingsProperties() {
988
959
  const toolSettings = new Array();
@@ -1007,23 +978,9 @@ class CreateArcTool extends CreateOrContinuePathTool {
1007
978
  if (!await super.onInstall())
1008
979
  return false;
1009
980
  // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
1010
- const methodValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.methodProperty.name);
1011
- if (undefined !== methodValue)
1012
- this.methodProperty.dialogItemValue = methodValue;
1013
- const radiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.radiusProperty.name);
1014
- if (undefined !== radiusValue)
1015
- this.radiusProperty.dialogItemValue = radiusValue;
1016
- const useRadiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.useRadiusProperty.name);
1017
- if (undefined !== useRadiusValue)
1018
- this.useRadiusProperty.dialogItemValue = useRadiusValue;
981
+ this.initializeToolSettingPropertyValues([this.methodProperty, this.radiusProperty, this.useRadiusProperty, this.sweepProperty, this.useSweepProperty]);
1019
982
  if (!this.radius)
1020
983
  this.useRadius = false;
1021
- const useSweepValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.useSweepProperty.name);
1022
- if (undefined !== useSweepValue)
1023
- this.useSweepProperty.dialogItemValue = useSweepValue;
1024
- const sweepValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.sweepProperty.name);
1025
- if (undefined !== sweepValue)
1026
- this.sweepProperty.dialogItemValue = sweepValue;
1027
984
  if (!this.sweep)
1028
985
  this.useSweep = false;
1029
986
  return true;
@@ -1075,16 +1032,16 @@ class CreateArcTool extends CreateOrContinuePathTool {
1075
1032
  }
1076
1033
  // Update current session values so keyin args are picked up for tool settings/restart...
1077
1034
  if (undefined !== arcMethod)
1078
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.methodProperty.name, value: { value: arcMethod } });
1035
+ this.saveToolSettingPropertyValue(this.methodProperty, { value: arcMethod });
1079
1036
  if (undefined !== arcRadius) {
1080
1037
  if (0.0 !== arcRadius)
1081
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.radiusProperty.name, value: { value: arcRadius } });
1082
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.useRadiusProperty.name, value: { value: 0.0 !== arcRadius } });
1038
+ this.saveToolSettingPropertyValue(this.radiusProperty, { value: arcRadius });
1039
+ this.saveToolSettingPropertyValue(this.useRadiusProperty, { value: 0.0 !== arcRadius });
1083
1040
  }
1084
1041
  if (undefined !== arcSweep) {
1085
1042
  if (0.0 !== arcSweep)
1086
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.sweepProperty.name, value: { value: arcSweep } });
1087
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.useSweepProperty.name, value: { value: 0.0 !== arcSweep } });
1043
+ this.saveToolSettingPropertyValue(this.sweepProperty, { value: arcSweep });
1044
+ this.saveToolSettingPropertyValue(this.useSweepProperty, { value: 0.0 !== arcSweep });
1088
1045
  }
1089
1046
  return this.run();
1090
1047
  }
@@ -1195,56 +1152,30 @@ class CreateCircleTool extends CreateOrContinuePathTool {
1195
1152
  vector90.scaleToLength(radius, vector90);
1196
1153
  return core_geometry_1.Arc3d.create(center, vector0, vector90);
1197
1154
  }
1198
- async onResetButtonUp(ev) {
1155
+ async cancelPoint(_ev) {
1199
1156
  if (CircleMethod.Center === this.method && this.useRadius) {
1200
1157
  // Exit instead of restarting to avoid having circle "stuck" on cursor...
1201
1158
  await this.exitTool();
1202
- return core_frontend_1.EventHandled.Yes;
1159
+ return false;
1203
1160
  }
1204
- return super.onResetButtonUp(ev);
1161
+ return true;
1205
1162
  }
1206
1163
  syncToolSettingsRadius() {
1207
1164
  if (this.useRadius)
1208
1165
  return;
1209
- const syncData = [];
1210
- if (!this.useRadius) {
1211
- this.radiusProperty.displayValue = this.radiusProperty.description.format(this.radius);
1212
- this.radiusProperty.isDisabled = !this.useRadius;
1213
- syncData.push(this.radiusProperty.syncItem);
1214
- }
1215
- if (0 !== syncData.length)
1216
- this.syncToolSettingsProperties(syncData);
1217
- }
1218
- syncRadiusState() {
1219
- this.radiusProperty.displayValue = this.radiusProperty.description.format(this.radius);
1220
- this.radiusProperty.isDisabled = !this.useRadius;
1221
1166
  this.syncToolSettingsProperties([this.radiusProperty.syncItem]);
1222
1167
  }
1168
+ getToolSettingPropertyLocked(property) {
1169
+ return (property === this.useRadiusProperty ? this.radiusProperty : undefined);
1170
+ }
1223
1171
  async applyToolSettingPropertyChange(updatedValue) {
1224
- if (this.methodProperty.name === updatedValue.propertyName) {
1225
- this.methodProperty.value = updatedValue.value.value;
1226
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.methodProperty.item);
1172
+ if (!this.changeToolSettingPropertyValue(updatedValue))
1173
+ return false;
1174
+ if (this.methodProperty.name === updatedValue.propertyName)
1227
1175
  await this.onReinitialize();
1228
- return true;
1229
- }
1230
- else if (updatedValue.propertyName === this.useRadiusProperty.name) {
1231
- this.useRadius = updatedValue.value.value;
1232
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.useRadiusProperty.item);
1233
- this.syncRadiusState();
1234
- if (CircleMethod.Center === this.method && this.useRadius && 0 === this.accepted.length)
1235
- await this.onReinitialize();
1236
- return true;
1237
- }
1238
- else if (updatedValue.propertyName === this.radiusProperty.name) {
1239
- if (!updatedValue.value.value) {
1240
- this.syncRadiusState(); // force UI to redisplay last valid value
1241
- return false;
1242
- }
1243
- this.radius = updatedValue.value.value;
1244
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.radiusProperty.item);
1245
- return true;
1246
- }
1247
- return false;
1176
+ else if (updatedValue.propertyName === this.useRadiusProperty.name && CircleMethod.Center === this.method && this.useRadius && 0 === this.accepted.length)
1177
+ await this.onReinitialize();
1178
+ return true;
1248
1179
  }
1249
1180
  supplyToolSettingsProperties() {
1250
1181
  const toolSettings = new Array();
@@ -1284,15 +1215,7 @@ class CreateCircleTool extends CreateOrContinuePathTool {
1284
1215
  if (!await super.onInstall())
1285
1216
  return false;
1286
1217
  // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
1287
- const methodValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.methodProperty.name);
1288
- if (undefined !== methodValue)
1289
- this.methodProperty.dialogItemValue = methodValue;
1290
- const radiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.radiusProperty.name);
1291
- if (undefined !== radiusValue)
1292
- this.radiusProperty.dialogItemValue = radiusValue;
1293
- const useRadiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.useRadiusProperty.name);
1294
- if (undefined !== useRadiusValue)
1295
- this.useRadiusProperty.dialogItemValue = useRadiusValue;
1218
+ this.initializeToolSettingPropertyValues([this.methodProperty, this.radiusProperty, this.useRadiusProperty]);
1296
1219
  if (!this.radius)
1297
1220
  this.useRadius = false;
1298
1221
  return true;
@@ -1330,11 +1253,11 @@ class CreateCircleTool extends CreateOrContinuePathTool {
1330
1253
  }
1331
1254
  // Update current session values so keyin args are picked up for tool settings/restart...
1332
1255
  if (undefined !== circleMethod)
1333
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.methodProperty.name, value: { value: circleMethod } });
1256
+ this.saveToolSettingPropertyValue(this.methodProperty, { value: circleMethod });
1334
1257
  if (undefined !== circleRadius) {
1335
1258
  if (0.0 !== circleRadius)
1336
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.radiusProperty.name, value: { value: circleRadius } });
1337
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.useRadiusProperty.name, value: { value: 0.0 !== circleRadius } });
1259
+ this.saveToolSettingPropertyValue(this.radiusProperty, { value: circleRadius });
1260
+ this.saveToolSettingPropertyValue(this.useRadiusProperty, { value: 0.0 !== circleRadius });
1338
1261
  }
1339
1262
  return this.run();
1340
1263
  }
@@ -1489,27 +1412,11 @@ class CreateRectangleTool extends CreateOrContinuePathTool {
1489
1412
  return;
1490
1413
  return { format: "flatbuffer", data: builder.entries };
1491
1414
  }
1492
- syncRadiusState() {
1493
- this.radiusProperty.displayValue = this.radiusProperty.description.format(this.radius);
1494
- this.radiusProperty.isDisabled = !this.useRadius;
1495
- this.syncToolSettingsProperties([this.radiusProperty.syncItem]);
1415
+ getToolSettingPropertyLocked(property) {
1416
+ return (property === this.useRadiusProperty ? this.radiusProperty : undefined);
1496
1417
  }
1497
1418
  async applyToolSettingPropertyChange(updatedValue) {
1498
- if (updatedValue.propertyName === this.useRadiusProperty.name) {
1499
- this.useRadius = updatedValue.value.value;
1500
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.useRadiusProperty.item);
1501
- this.syncRadiusState();
1502
- }
1503
- else if (updatedValue.propertyName === this.radiusProperty.name) {
1504
- if (!updatedValue.value.value) {
1505
- this.syncRadiusState(); // force UI to redisplay last valid value
1506
- return false;
1507
- }
1508
- this.radius = updatedValue.value.value;
1509
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.radiusProperty.item);
1510
- return true;
1511
- }
1512
- return false;
1419
+ return this.changeToolSettingPropertyValue(updatedValue);
1513
1420
  }
1514
1421
  supplyToolSettingsProperties() {
1515
1422
  const toolSettings = new Array();
@@ -1528,12 +1435,7 @@ class CreateRectangleTool extends CreateOrContinuePathTool {
1528
1435
  if (!await super.onInstall())
1529
1436
  return false;
1530
1437
  // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
1531
- const radiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.radiusProperty.name);
1532
- if (undefined !== radiusValue)
1533
- this.radiusProperty.dialogItemValue = radiusValue;
1534
- const useRadiusValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.useRadiusProperty.name);
1535
- if (undefined !== useRadiusValue)
1536
- this.useRadiusProperty.dialogItemValue = useRadiusValue;
1438
+ this.initializeToolSettingPropertyValues([this.radiusProperty, this.useRadiusProperty]);
1537
1439
  if (!this.radius)
1538
1440
  this.useRadius = false;
1539
1441
  return true;
@@ -1557,8 +1459,8 @@ class CreateRectangleTool extends CreateOrContinuePathTool {
1557
1459
  // Update current session values so keyin args are picked up for tool settings/restart...
1558
1460
  if (undefined !== cornerRadius) {
1559
1461
  if (0.0 !== cornerRadius)
1560
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.radiusProperty.name, value: { value: cornerRadius } });
1561
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.useRadiusProperty.name, value: { value: 0.0 !== cornerRadius } });
1462
+ this.saveToolSettingPropertyValue(this.radiusProperty, { value: cornerRadius });
1463
+ this.saveToolSettingPropertyValue(this.useRadiusProperty, { value: 0.0 !== cornerRadius });
1562
1464
  }
1563
1465
  return this.run();
1564
1466
  }
@@ -1574,13 +1476,24 @@ var BCurveMethod;
1574
1476
  })(BCurveMethod = exports.BCurveMethod || (exports.BCurveMethod = {}));
1575
1477
  /** @alpha Creates a bspline curve by poles or through points. Uses model and category from ToolAdmin.ActiveSettings. */
1576
1478
  class CreateBCurveTool extends CreateOrContinuePathTool {
1479
+ constructor() {
1480
+ super(...arguments);
1481
+ this._isPhysicallyClosedOrComplete = false;
1482
+ this._tangentPhase = CreateCurvePhase.DefineOther;
1483
+ }
1484
+ static get minArgs() { return 0; }
1485
+ static get maxArgs() { return 3; } // method, order, tangents...
1577
1486
  get wantPickableDynamics() { return true; } // Allow snapping to control polygon or through points...
1578
1487
  get showCurveConstructions() { return true; } // Display control polygon or through points...
1579
1488
  provideToolAssistance(_mainInstrText, _additionalInstr) {
1580
1489
  const nPts = this.accepted.length;
1581
- const mainMsg = core_frontend_1.CoreTools.translate(0 === nPts ? "ElementSet.Prompts.StartPoint" : (1 === nPts ? "ElementSet.Prompts.EndPoint" : "ElementSet.Inputs.AdditionalPoint"));
1490
+ let mainMsg;
1491
+ if (CreateCurvePhase.DefineOther === this._tangentPhase)
1492
+ mainMsg = core_frontend_1.CoreTools.translate(0 === nPts ? "ElementSet.Prompts.StartPoint" : "ElementSet.Inputs.AdditionalPoint");
1493
+ else
1494
+ mainMsg = EditTool_1.EditTools.translate(CreateCurvePhase.DefineStart === this._tangentPhase ? "CreateBCurve.Prompts.StartTangent" : "CreateBCurve.Prompts.EndTangent");
1582
1495
  const leftMsg = core_frontend_1.CoreTools.translate("ElementSet.Inputs.AcceptPoint");
1583
- const rightMsg = core_frontend_1.CoreTools.translate(nPts > 1 ? "ElementSet.Inputs.Complete" : "ElementSet.Inputs.Cancel");
1496
+ const rightMsg = core_frontend_1.CoreTools.translate(CreateCurvePhase.DefineOther === this._tangentPhase && nPts >= this.requiredPointCount ? "ElementSet.Inputs.Complete" : "ElementSet.Inputs.Cancel");
1584
1497
  const mouseInstructions = [];
1585
1498
  const touchInstructions = [];
1586
1499
  if (!core_frontend_1.ToolAssistance.createTouchCursorInstructions(touchInstructions))
@@ -1612,43 +1525,97 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1612
1525
  set order(value) { this.orderProperty.value = value; }
1613
1526
  get minOrder() { return 2; }
1614
1527
  get maxOrder() { return 16; }
1528
+ get tangentsProperty() {
1529
+ if (!this._tangentsProperty)
1530
+ this._tangentsProperty = new appui_abstract_1.DialogProperty(appui_abstract_1.PropertyDescriptionHelper.buildToggleDescription("bcurveTangents", EditTool_1.EditTools.translate("CreateBCurve.Label.Tangents")), false);
1531
+ return this._tangentsProperty;
1532
+ }
1533
+ get tangents() { return this.tangentsProperty.value; }
1534
+ set tangents(value) { this.tangentsProperty.value = value; }
1615
1535
  get wantClosure() {
1616
1536
  // A bcurve can support physical closure when creating a new path...
1617
1537
  return this.allowClosure;
1618
1538
  }
1539
+ get requiredPointCount() {
1540
+ if (BCurveMethod.ThroughPoints === this.method)
1541
+ return 3; // Interpolation curve is always order 4 with 3 point minimum...
1542
+ return this.order;
1543
+ }
1544
+ get createCurvePhase() {
1545
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase)
1546
+ return CreateCurvePhase.DefineOther;
1547
+ return super.createCurvePhase;
1548
+ }
1619
1549
  isComplete(ev) {
1620
1550
  // Accept on reset with sufficient points...
1621
1551
  if (core_frontend_1.BeButton.Reset === ev.button)
1622
- return (this.accepted.length >= this.order);
1552
+ return (this.accepted.length >= this.requiredPointCount);
1623
1553
  // Allow data to complete on physical closure...
1624
- return this.isClosed;
1554
+ return this.isClosed || this._isPhysicallyClosedOrComplete;
1555
+ }
1556
+ showConstructionGraphics(ev, context) {
1557
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase && this.current) {
1558
+ const fitCurve = this.current;
1559
+ const builder = context.createGraphic({ type: core_frontend_1.GraphicType.WorldOverlay });
1560
+ const color = context.viewport.getContrastToBackgroundColor();
1561
+ builder.setSymbology(color, core_common_1.ColorDef.black, 1, core_common_1.LinePixels.Code2);
1562
+ builder.addLineString([ev.point, fitCurve.options.fitPoints[CreateCurvePhase.DefineStart === this._tangentPhase ? 0 : fitCurve.options.fitPoints.length - 1]]);
1563
+ builder.setSymbology(color, core_common_1.ColorDef.black, 8);
1564
+ builder.addPointString([ev.point]);
1565
+ context.addGraphic(builder.finish());
1566
+ }
1567
+ return super.showConstructionGraphics(ev, context);
1625
1568
  }
1626
1569
  createNewCurvePrimitive(ev, isDynamics) {
1570
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase && this.current) {
1571
+ const fitCurve = this.current;
1572
+ if (CreateCurvePhase.DefineStart === this._tangentPhase) {
1573
+ const tangentS = core_geometry_1.Vector3d.createStartEnd(ev.point, fitCurve.options.fitPoints[0]);
1574
+ if (tangentS.magnitude() > core_geometry_1.Geometry.smallMetricDistance)
1575
+ fitCurve.options.startTangent = tangentS;
1576
+ }
1577
+ else {
1578
+ const tangentE = core_geometry_1.Vector3d.createStartEnd(ev.point, fitCurve.options.fitPoints[fitCurve.options.fitPoints.length - 1]);
1579
+ if (tangentE.magnitude() > core_geometry_1.Geometry.smallMetricDistance)
1580
+ fitCurve.options.endTangent = tangentE;
1581
+ }
1582
+ return fitCurve;
1583
+ }
1627
1584
  // Don't include current point if it's the same as the last accepted point, want dynamics to show an accurate preview of what reset will accept...
1628
1585
  const includeCurrPt = (isDynamics && (0 === this.accepted.length || !ev.point.isAlmostEqual(this.accepted[this.accepted.length - 1])));
1629
1586
  const pts = (includeCurrPt ? [...this.accepted, ev.point] : this.accepted);
1630
- const numRequired = this.order;
1587
+ const numRequired = this.requiredPointCount;
1631
1588
  if (pts.length < numRequired) {
1632
1589
  // Create point/linestring construction geometry to support join...
1633
1590
  this.isConstruction = true;
1634
1591
  return core_geometry_1.LineString3d.create(1 === pts.length ? [pts[0], pts[0]] : pts);
1635
1592
  }
1636
- // TODO: Support physical closure by creating closed/rational bcurve...
1637
- if (BCurveMethod.ControlPoints === this.method)
1593
+ // Create periodic-looking curve on physical closure with sufficient points even when not creating a loop/surface...
1594
+ this._isPhysicallyClosedOrComplete = (undefined === this.continuationData && pts[0].isAlmostEqual(pts[pts.length - 1]));
1595
+ if (BCurveMethod.ControlPoints === this.method) {
1596
+ if (this._isPhysicallyClosedOrComplete && this.order > 2) {
1597
+ const tmpPts = pts.slice(undefined, -1); // Don't include closure point...
1598
+ return core_geometry_1.BSplineCurve3d.createPeriodicUniformKnots(tmpPts, this.order);
1599
+ }
1638
1600
  return core_geometry_1.BSplineCurve3d.createUniformKnots(pts, this.order);
1639
- // TODO: InterpolationCurve3d, set end tangents using continuation curve...self-closure, etc.
1640
- return core_geometry_1.BSplineCurveOps.createThroughPoints(pts, this.order);
1641
- }
1642
- addConstructionGraphics(curve, showCurve, context) {
1643
- // TODO: Need proper Interpolation curve class to extract/show through points...
1644
- if (BCurveMethod.ThroughPoints === this.method && !showCurve && 0 !== this.accepted.length) {
1645
- const builder = context.createGraphic({ type: core_frontend_1.GraphicType.WorldOverlay });
1646
- builder.setSymbology(context.viewport.getContrastToBackgroundColor(), core_common_1.ColorDef.black, 5);
1647
- builder.addPointString(this.accepted);
1648
- context.addGraphic(builder.finish());
1649
- return;
1650
1601
  }
1651
- return super.addConstructionGraphics(curve, showCurve, context);
1602
+ const interpProps = { fitPoints: pts, closed: this._isPhysicallyClosedOrComplete, isChordLenKnots: 1, isColinearTangents: 1 };
1603
+ // Create interpolation curve tangent to continuation curve...
1604
+ if (undefined !== this.continuationData && this.tangents) {
1605
+ const tangentS = this.continuationData.path.children[0].fractionToPointAndUnitTangent(0.0);
1606
+ const tangentE = this.continuationData.path.children[this.continuationData.path.children.length - 1].fractionToPointAndUnitTangent(1.0);
1607
+ if (pts[0].isAlmostEqual(tangentS.origin))
1608
+ interpProps.startTangent = tangentS.direction.scale(-1);
1609
+ else if (pts[0].isAlmostEqual(tangentE.origin))
1610
+ interpProps.startTangent = tangentE.direction;
1611
+ if (pts[pts.length - 1].isAlmostEqual(tangentS.origin))
1612
+ interpProps.endTangent = tangentS.direction.scale(-1);
1613
+ else if (pts[pts.length - 1].isAlmostEqual(tangentE.origin))
1614
+ interpProps.endTangent = tangentE.direction;
1615
+ this._isPhysicallyClosedOrComplete = (undefined !== interpProps.startTangent && undefined !== interpProps.endTangent);
1616
+ }
1617
+ const interpOpts = core_geometry_1.InterpolationCurve3dOptions.create(interpProps);
1618
+ return core_geometry_1.InterpolationCurve3d.createCapture(interpOpts);
1652
1619
  }
1653
1620
  getSnapGeometry() {
1654
1621
  // Only snap to through points...
@@ -1656,40 +1623,63 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1656
1623
  return (this.accepted.length > 1 ? core_geometry_1.PointString3d.create(this.accepted) : undefined);
1657
1624
  return super.getSnapGeometry();
1658
1625
  }
1659
- async onResetButtonUp(ev) {
1626
+ async acceptPoint(ev) {
1627
+ switch (this._tangentPhase) {
1628
+ case CreateCurvePhase.DefineOther:
1629
+ return super.acceptPoint(ev);
1630
+ case CreateCurvePhase.DefineStart:
1631
+ this._tangentPhase = CreateCurvePhase.DefineEnd;
1632
+ break;
1633
+ case CreateCurvePhase.DefineEnd:
1634
+ this._isPhysicallyClosedOrComplete = true;
1635
+ break;
1636
+ }
1637
+ await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineOther);
1638
+ return true;
1639
+ }
1640
+ async cancelPoint(ev) {
1660
1641
  // NOTE: Starting another tool will not create element...require reset or closure...
1661
1642
  if (this.isComplete(ev)) {
1643
+ if (BCurveMethod.ThroughPoints === this.method && this.tangents && this.current) {
1644
+ const fitCurve = this.current;
1645
+ switch (this._tangentPhase) {
1646
+ case CreateCurvePhase.DefineOther:
1647
+ await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineEnd);
1648
+ this._tangentPhase = (undefined === fitCurve.options.startTangent ? CreateCurvePhase.DefineStart : CreateCurvePhase.DefineEnd);
1649
+ core_frontend_1.IModelApp.toolAdmin.updateDynamics();
1650
+ this.setupAndPromptForNextAction();
1651
+ return false;
1652
+ case CreateCurvePhase.DefineStart:
1653
+ fitCurve.options.startTangent = undefined; // Not accepted, compute default start tangent...
1654
+ this._tangentPhase = CreateCurvePhase.DefineEnd;
1655
+ core_frontend_1.IModelApp.toolAdmin.updateDynamics();
1656
+ this.setupAndPromptForNextAction();
1657
+ return false;
1658
+ case CreateCurvePhase.DefineEnd:
1659
+ fitCurve.options.endTangent = undefined; // Not accepted, compute default end tangent...
1660
+ await this.createElement();
1661
+ return true;
1662
+ }
1663
+ }
1662
1664
  await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineEnd);
1663
1665
  await this.createElement();
1664
1666
  }
1665
- return super.onResetButtonUp(ev);
1666
- }
1667
- syncOrderState() {
1668
- this.orderProperty.displayValue = this.orderProperty.description.format(this.order);
1669
- this.syncToolSettingsProperties([this.orderProperty.syncItem]);
1667
+ return true;
1670
1668
  }
1671
1669
  async applyToolSettingPropertyChange(updatedValue) {
1672
- if (this.methodProperty.name === updatedValue.propertyName) {
1673
- this.methodProperty.value = updatedValue.value.value;
1674
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.methodProperty.item);
1670
+ if (!this.changeToolSettingPropertyValue(updatedValue))
1671
+ return false;
1672
+ if (this.methodProperty.name === updatedValue.propertyName)
1675
1673
  await this.onReinitialize();
1676
- return true;
1677
- }
1678
- else if (updatedValue.propertyName === this.orderProperty.name) {
1679
- if (!updatedValue.value.value) {
1680
- this.syncOrderState(); // force UI to redisplay last valid value
1681
- return false;
1682
- }
1683
- this.order = updatedValue.value.value;
1684
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.orderProperty.item);
1685
- return true;
1686
- }
1687
- return false;
1674
+ return true;
1688
1675
  }
1689
1676
  supplyToolSettingsProperties() {
1690
1677
  const toolSettings = new Array();
1691
1678
  toolSettings.push(this.methodProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
1692
- toolSettings.push(this.orderProperty.toDialogItem({ rowPriority: 2, columnIndex: 1 }));
1679
+ if (BCurveMethod.ThroughPoints === this.method)
1680
+ toolSettings.push(this.tangentsProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1681
+ else
1682
+ toolSettings.push(this.orderProperty.toDialogItem({ rowPriority: 2, columnIndex: 1 }));
1693
1683
  return toolSettings;
1694
1684
  }
1695
1685
  async onRestartTool() {
@@ -1701,21 +1691,18 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1701
1691
  if (!await super.onInstall())
1702
1692
  return false;
1703
1693
  // Setup initial values here instead of supplyToolSettingsProperties to support keyin args w/o appui-react...
1704
- const methodValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.methodProperty.name);
1705
- if (undefined !== methodValue)
1706
- this.methodProperty.dialogItemValue = methodValue;
1707
- const orderValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.orderProperty.name);
1708
- if (undefined !== orderValue)
1709
- this.orderProperty.dialogItemValue = orderValue;
1694
+ this.initializeToolSettingPropertyValues([this.methodProperty, this.orderProperty, this.tangentsProperty]);
1710
1695
  return true;
1711
1696
  }
1712
1697
  /** The keyin takes the following arguments, all of which are optional:
1713
1698
  * - `method=0|1` How bcurve will be defined. 0 for control points, 1 for through points.
1714
1699
  * - `order=number` bcurve order from 2 to 16.
1700
+ * - 'tangents=0|1 Whether to specify start/end tangents for through points construction.
1715
1701
  */
1716
1702
  async parseAndRun(...inputArgs) {
1717
1703
  let bcurveMethod;
1718
1704
  let bcurveOrder;
1705
+ let bcurveTangents;
1719
1706
  for (const arg of inputArgs) {
1720
1707
  const parts = arg.split("=");
1721
1708
  if (2 !== parts.length)
@@ -1739,12 +1726,18 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1739
1726
  bcurveOrder = order;
1740
1727
  }
1741
1728
  }
1729
+ else if (parts[0].toLowerCase().startsWith("ta")) {
1730
+ const tangents = Number.parseInt(parts[1], 10);
1731
+ bcurveTangents = (0 !== tangents);
1732
+ }
1742
1733
  }
1743
1734
  // Update current session values so keyin args are picked up for tool settings/restart...
1744
1735
  if (undefined !== bcurveMethod)
1745
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.methodProperty.name, value: { value: bcurveMethod } });
1736
+ this.saveToolSettingPropertyValue(this.methodProperty, { value: bcurveMethod });
1746
1737
  if (undefined !== bcurveOrder)
1747
- core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.orderProperty.name, value: { value: bcurveOrder } });
1738
+ this.saveToolSettingPropertyValue(this.orderProperty, { value: bcurveOrder });
1739
+ if (undefined !== bcurveTangents)
1740
+ this.saveToolSettingPropertyValue(this.tangentsProperty, { value: bcurveTangents });
1748
1741
  return this.run();
1749
1742
  }
1750
1743
  }