@itwin/editor-frontend 3.0.0-dev.136 → 3.0.0-dev.141

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.
@@ -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();
@@ -1195,13 +1208,13 @@ class CreateCircleTool extends CreateOrContinuePathTool {
1195
1208
  vector90.scaleToLength(radius, vector90);
1196
1209
  return core_geometry_1.Arc3d.create(center, vector0, vector90);
1197
1210
  }
1198
- async onResetButtonUp(ev) {
1211
+ async cancelPoint(_ev) {
1199
1212
  if (CircleMethod.Center === this.method && this.useRadius) {
1200
1213
  // Exit instead of restarting to avoid having circle "stuck" on cursor...
1201
1214
  await this.exitTool();
1202
- return core_frontend_1.EventHandled.Yes;
1215
+ return false;
1203
1216
  }
1204
- return super.onResetButtonUp(ev);
1217
+ return true;
1205
1218
  }
1206
1219
  syncToolSettingsRadius() {
1207
1220
  if (this.useRadius)
@@ -1574,6 +1587,13 @@ var BCurveMethod;
1574
1587
  })(BCurveMethod = exports.BCurveMethod || (exports.BCurveMethod = {}));
1575
1588
  /** @alpha Creates a bspline curve by poles or through points. Uses model and category from ToolAdmin.ActiveSettings. */
1576
1589
  class CreateBCurveTool extends CreateOrContinuePathTool {
1590
+ constructor() {
1591
+ super(...arguments);
1592
+ this._isPhysicallyClosedOrComplete = false;
1593
+ this._tangentPhase = CreateCurvePhase.DefineOther;
1594
+ }
1595
+ static get minArgs() { return 0; }
1596
+ static get maxArgs() { return 3; } // method, order, tangents...
1577
1597
  get wantPickableDynamics() { return true; } // Allow snapping to control polygon or through points...
1578
1598
  get showCurveConstructions() { return true; } // Display control polygon or through points...
1579
1599
  provideToolAssistance(_mainInstrText, _additionalInstr) {
@@ -1612,43 +1632,93 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1612
1632
  set order(value) { this.orderProperty.value = value; }
1613
1633
  get minOrder() { return 2; }
1614
1634
  get maxOrder() { return 16; }
1635
+ get tangentsProperty() {
1636
+ if (!this._tangentsProperty)
1637
+ this._tangentsProperty = new appui_abstract_1.DialogProperty(appui_abstract_1.PropertyDescriptionHelper.buildToggleDescription("bcurveTangents", EditTool_1.EditTools.translate("CreateBCurve.Label.Tangents")), false);
1638
+ return this._tangentsProperty;
1639
+ }
1640
+ get tangents() { return this.tangentsProperty.value; }
1641
+ set tangents(value) { this.tangentsProperty.value = value; }
1615
1642
  get wantClosure() {
1616
1643
  // A bcurve can support physical closure when creating a new path...
1617
1644
  return this.allowClosure;
1618
1645
  }
1646
+ get requiredPointCount() {
1647
+ if (BCurveMethod.ThroughPoints === this.method)
1648
+ return 3; // Interpolation curve is always order 4 with 3 point minimum...
1649
+ return this.order;
1650
+ }
1651
+ get createCurvePhase() {
1652
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase)
1653
+ return CreateCurvePhase.DefineOther;
1654
+ return super.createCurvePhase;
1655
+ }
1619
1656
  isComplete(ev) {
1620
1657
  // Accept on reset with sufficient points...
1621
1658
  if (core_frontend_1.BeButton.Reset === ev.button)
1622
- return (this.accepted.length >= this.order);
1659
+ return (this.accepted.length >= this.requiredPointCount);
1623
1660
  // Allow data to complete on physical closure...
1624
- return this.isClosed;
1661
+ return this.isClosed || this._isPhysicallyClosedOrComplete;
1662
+ }
1663
+ showConstructionGraphics(ev, context) {
1664
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase && this.current) {
1665
+ const fitCurve = this.current;
1666
+ const builder = context.createGraphic({ type: core_frontend_1.GraphicType.WorldOverlay });
1667
+ const color = context.viewport.getContrastToBackgroundColor();
1668
+ builder.setSymbology(color, core_common_1.ColorDef.black, 1, core_common_1.LinePixels.Code2);
1669
+ builder.addLineString([ev.point, fitCurve.options.fitPoints[CreateCurvePhase.DefineStart === this._tangentPhase ? 0 : fitCurve.options.fitPoints.length - 1]]);
1670
+ builder.setSymbology(color, core_common_1.ColorDef.black, 8);
1671
+ builder.addPointString([ev.point]);
1672
+ context.addGraphic(builder.finish());
1673
+ }
1674
+ return super.showConstructionGraphics(ev, context);
1625
1675
  }
1626
1676
  createNewCurvePrimitive(ev, isDynamics) {
1677
+ if (CreateCurvePhase.DefineOther !== this._tangentPhase && this.current) {
1678
+ const fitCurve = this.current;
1679
+ if (CreateCurvePhase.DefineStart === this._tangentPhase) {
1680
+ const tangentS = core_geometry_1.Vector3d.createStartEnd(ev.point, fitCurve.options.fitPoints[0]);
1681
+ if (tangentS.magnitude() > core_geometry_1.Geometry.smallMetricDistance)
1682
+ fitCurve.options.startTangent = tangentS;
1683
+ }
1684
+ else {
1685
+ const tangentE = core_geometry_1.Vector3d.createStartEnd(ev.point, fitCurve.options.fitPoints[fitCurve.options.fitPoints.length - 1]);
1686
+ if (tangentE.magnitude() > core_geometry_1.Geometry.smallMetricDistance)
1687
+ fitCurve.options.endTangent = tangentE;
1688
+ }
1689
+ return fitCurve;
1690
+ }
1627
1691
  // 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
1692
  const includeCurrPt = (isDynamics && (0 === this.accepted.length || !ev.point.isAlmostEqual(this.accepted[this.accepted.length - 1])));
1629
1693
  const pts = (includeCurrPt ? [...this.accepted, ev.point] : this.accepted);
1630
- const numRequired = this.order;
1694
+ const numRequired = this.requiredPointCount;
1631
1695
  if (pts.length < numRequired) {
1632
1696
  // Create point/linestring construction geometry to support join...
1633
1697
  this.isConstruction = true;
1634
1698
  return core_geometry_1.LineString3d.create(1 === pts.length ? [pts[0], pts[0]] : pts);
1635
1699
  }
1636
- // TODO: Support physical closure by creating closed/rational bcurve...
1700
+ // Create periodic-looking curve on physical closure with sufficient points even when not creating a loop/surface...
1701
+ this._isPhysicallyClosedOrComplete = (undefined === this.continuationData && pts[0].isAlmostEqual(pts[pts.length - 1]));
1702
+ // TODO: Support physical closure for pole construction...
1637
1703
  if (BCurveMethod.ControlPoints === this.method)
1638
1704
  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;
1705
+ const interpProps = { fitPoints: pts, closed: this._isPhysicallyClosedOrComplete, isChordLenKnots: 1, isColinearTangents: 1 };
1706
+ // Create interpolation curve tangent to continuation curve...
1707
+ if (undefined !== this.continuationData && this.tangents) {
1708
+ const tangentS = this.continuationData.path.children[0].fractionToPointAndUnitTangent(0.0);
1709
+ const tangentE = this.continuationData.path.children[this.continuationData.path.children.length - 1].fractionToPointAndUnitTangent(1.0);
1710
+ if (pts[0].isAlmostEqual(tangentS.origin))
1711
+ interpProps.startTangent = tangentS.direction.scale(-1);
1712
+ else if (pts[0].isAlmostEqual(tangentE.origin))
1713
+ interpProps.startTangent = tangentE.direction;
1714
+ if (pts[pts.length - 1].isAlmostEqual(tangentS.origin))
1715
+ interpProps.endTangent = tangentS.direction.scale(-1);
1716
+ else if (pts[pts.length - 1].isAlmostEqual(tangentE.origin))
1717
+ interpProps.endTangent = tangentE.direction;
1718
+ this._isPhysicallyClosedOrComplete = (undefined !== interpProps.startTangent && undefined !== interpProps.endTangent);
1650
1719
  }
1651
- return super.addConstructionGraphics(curve, showCurve, context);
1720
+ const interpOpts = core_geometry_1.InterpolationCurve3dOptions.create(interpProps);
1721
+ return core_geometry_1.InterpolationCurve3d.createCapture(interpOpts);
1652
1722
  }
1653
1723
  getSnapGeometry() {
1654
1724
  // Only snap to through points...
@@ -1656,13 +1726,46 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1656
1726
  return (this.accepted.length > 1 ? core_geometry_1.PointString3d.create(this.accepted) : undefined);
1657
1727
  return super.getSnapGeometry();
1658
1728
  }
1659
- async onResetButtonUp(ev) {
1729
+ async acceptPoint(ev) {
1730
+ switch (this._tangentPhase) {
1731
+ case CreateCurvePhase.DefineOther:
1732
+ return super.acceptPoint(ev);
1733
+ case CreateCurvePhase.DefineStart:
1734
+ this._tangentPhase = CreateCurvePhase.DefineEnd;
1735
+ break;
1736
+ case CreateCurvePhase.DefineEnd:
1737
+ this._isPhysicallyClosedOrComplete = true;
1738
+ break;
1739
+ }
1740
+ await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineOther);
1741
+ return true;
1742
+ }
1743
+ async cancelPoint(ev) {
1660
1744
  // NOTE: Starting another tool will not create element...require reset or closure...
1661
1745
  if (this.isComplete(ev)) {
1746
+ if (BCurveMethod.ThroughPoints === this.method && this.tangents && this.current) {
1747
+ const fitCurve = this.current;
1748
+ switch (this._tangentPhase) {
1749
+ case CreateCurvePhase.DefineOther:
1750
+ await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineEnd);
1751
+ this._tangentPhase = (undefined === fitCurve.options.startTangent ? CreateCurvePhase.DefineStart : CreateCurvePhase.DefineEnd);
1752
+ core_frontend_1.IModelApp.toolAdmin.updateDynamics();
1753
+ return false;
1754
+ case CreateCurvePhase.DefineStart:
1755
+ fitCurve.options.startTangent = undefined; // Not accepted, compute default start tangent...
1756
+ this._tangentPhase = CreateCurvePhase.DefineEnd;
1757
+ core_frontend_1.IModelApp.toolAdmin.updateDynamics();
1758
+ return false;
1759
+ case CreateCurvePhase.DefineEnd:
1760
+ fitCurve.options.endTangent = undefined; // Not accepted, compute default end tangent...
1761
+ await this.createElement();
1762
+ return true;
1763
+ }
1764
+ }
1662
1765
  await this.updateCurveAndContinuationData(ev, false, CreateCurvePhase.DefineEnd);
1663
1766
  await this.createElement();
1664
1767
  }
1665
- return super.onResetButtonUp(ev);
1768
+ return true;
1666
1769
  }
1667
1770
  syncOrderState() {
1668
1771
  this.orderProperty.displayValue = this.orderProperty.description.format(this.order);
@@ -1684,12 +1787,20 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1684
1787
  core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.orderProperty.item);
1685
1788
  return true;
1686
1789
  }
1790
+ else if (updatedValue.propertyName === this.tangentsProperty.name) {
1791
+ this.tangents = updatedValue.value.value;
1792
+ core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, this.tangentsProperty.item);
1793
+ return true;
1794
+ }
1687
1795
  return false;
1688
1796
  }
1689
1797
  supplyToolSettingsProperties() {
1690
1798
  const toolSettings = new Array();
1691
1799
  toolSettings.push(this.methodProperty.toDialogItem({ rowPriority: 1, columnIndex: 0 }));
1692
- toolSettings.push(this.orderProperty.toDialogItem({ rowPriority: 2, columnIndex: 1 }));
1800
+ if (BCurveMethod.ThroughPoints === this.method)
1801
+ toolSettings.push(this.tangentsProperty.toDialogItem({ rowPriority: 2, columnIndex: 0 }));
1802
+ else
1803
+ toolSettings.push(this.orderProperty.toDialogItem({ rowPriority: 2, columnIndex: 1 }));
1693
1804
  return toolSettings;
1694
1805
  }
1695
1806
  async onRestartTool() {
@@ -1707,15 +1818,20 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1707
1818
  const orderValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.orderProperty.name);
1708
1819
  if (undefined !== orderValue)
1709
1820
  this.orderProperty.dialogItemValue = orderValue;
1821
+ const tangentsValue = core_frontend_1.IModelApp.toolAdmin.toolSettingsState.getInitialToolSettingValue(this.toolId, this.tangentsProperty.name);
1822
+ if (undefined !== tangentsValue)
1823
+ this.tangentsProperty.dialogItemValue = tangentsValue;
1710
1824
  return true;
1711
1825
  }
1712
1826
  /** The keyin takes the following arguments, all of which are optional:
1713
1827
  * - `method=0|1` How bcurve will be defined. 0 for control points, 1 for through points.
1714
1828
  * - `order=number` bcurve order from 2 to 16.
1829
+ * - 'tangents=0|1 Whether to specify start/end tangents for through points construction.
1715
1830
  */
1716
1831
  async parseAndRun(...inputArgs) {
1717
1832
  let bcurveMethod;
1718
1833
  let bcurveOrder;
1834
+ let bcurveTangents;
1719
1835
  for (const arg of inputArgs) {
1720
1836
  const parts = arg.split("=");
1721
1837
  if (2 !== parts.length)
@@ -1739,12 +1855,18 @@ class CreateBCurveTool extends CreateOrContinuePathTool {
1739
1855
  bcurveOrder = order;
1740
1856
  }
1741
1857
  }
1858
+ else if (parts[0].toLowerCase().startsWith("ta")) {
1859
+ const tangents = Number.parseInt(parts[1], 10);
1860
+ bcurveTangents = (0 !== tangents);
1861
+ }
1742
1862
  }
1743
1863
  // Update current session values so keyin args are picked up for tool settings/restart...
1744
1864
  if (undefined !== bcurveMethod)
1745
1865
  core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.methodProperty.name, value: { value: bcurveMethod } });
1746
1866
  if (undefined !== bcurveOrder)
1747
1867
  core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.orderProperty.name, value: { value: bcurveOrder } });
1868
+ if (undefined !== bcurveTangents)
1869
+ core_frontend_1.IModelApp.toolAdmin.toolSettingsState.saveToolSettingProperty(this.toolId, { propertyName: this.tangentsProperty.name, value: { value: bcurveTangents } });
1748
1870
  return this.run();
1749
1871
  }
1750
1872
  }