@itwin/ecschema-rpcinterface-tests 4.7.0-dev.8 → 4.8.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.
@@ -28230,6 +28230,8 @@ var ChangesetType;
28230
28230
  ChangesetType[ChangesetType["Regular"] = 0] = "Regular";
28231
28231
  /** changeset *does* contain schema changes. */
28232
28232
  ChangesetType[ChangesetType["Schema"] = 1] = "Schema";
28233
+ /** Schema changeset pushed by iModel with SchemaSync enabled */
28234
+ ChangesetType[ChangesetType["SchemaSync"] = 65] = "SchemaSync";
28233
28235
  })(ChangesetType || (ChangesetType = {}));
28234
28236
 
28235
28237
 
@@ -57054,6 +57056,8 @@ class RpcRequest {
57054
57056
  return this.reject(new _IModelError__WEBPACK_IMPORTED_MODULE_1__.NoContentError());
57055
57057
  }
57056
57058
  handleNotFound(status, value) {
57059
+ if (RpcRequest.notFoundHandlers.numberOfListeners === 0)
57060
+ this.handleRejected(value);
57057
57061
  const response = _RpcMarshaling__WEBPACK_IMPORTED_MODULE_4__.RpcMarshaling.deserialize(this.protocol, value);
57058
57062
  this.setStatus(status);
57059
57063
  let resubmitted = false;
@@ -57061,8 +57065,8 @@ class RpcRequest {
57061
57065
  if (resubmitted)
57062
57066
  throw new _IModelError__WEBPACK_IMPORTED_MODULE_1__.IModelError(_itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.BentleyStatus.ERROR, `Already resubmitted using this handler.`);
57063
57067
  resubmitted = true;
57064
- this.submit(); // eslint-disable-line @typescript-eslint/no-floating-promises
57065
- }, (reason) => this.reject(reason));
57068
+ void this.submit();
57069
+ }, (reason) => reason ? this.reject(reason) : this.handleRejected(value));
57066
57070
  return;
57067
57071
  }
57068
57072
  resolve(result) {
@@ -68317,7 +68321,8 @@ class SchemaJsonLocater {
68317
68321
  * @throws [ECObjectsError]($ecschema-metadata) if the schema exists, but cannot be loaded.
68318
68322
  */
68319
68323
  async getSchema(schemaKey, matchType, context) {
68320
- return this.getSchemaSync(schemaKey, matchType, context);
68324
+ await this.getSchemaInfo(schemaKey, matchType, context);
68325
+ return await context.getCachedSchema(schemaKey, matchType);
68321
68326
  }
68322
68327
  /**
68323
68328
  * Gets the schema info which matches the provided SchemaKey. The schema info may be returned before the schema is fully loaded.
@@ -68325,7 +68330,13 @@ class SchemaJsonLocater {
68325
68330
  * @param matchType The match type to use when locating the schema
68326
68331
  */
68327
68332
  async getSchemaInfo(schemaKey, matchType, context) {
68328
- return this.getSchema(schemaKey, matchType, context);
68333
+ const schemaProps = this._getSchema(schemaKey.name);
68334
+ if (!schemaProps)
68335
+ return undefined;
68336
+ const schemaInfo = await Schema_1.Schema.startLoadingFromJson(schemaProps, context);
68337
+ if (schemaInfo !== undefined && schemaInfo.schemaKey.matches(schemaKey, matchType))
68338
+ return schemaInfo;
68339
+ return undefined;
68329
68340
  }
68330
68341
  /** Get a schema by [SchemaKey] synchronously.
68331
68342
  * @param schemaKey The [SchemaKey] that identifies the schema.
@@ -76067,10 +76078,10 @@ class CheckpointConnection extends _IModelConnection__WEBPACK_IMPORTED_MODULE_4_
76067
76078
  super(props);
76068
76079
  this._reopenConnectionHandler = async (request, response, resubmit, reject) => {
76069
76080
  if (!response.hasOwnProperty("isIModelNotFoundResponse"))
76070
- return;
76081
+ reject();
76071
76082
  const iModelRpcProps = request.parameters[0];
76072
76083
  if (this._fileKey !== iModelRpcProps.key)
76073
- return; // The handler is called for a different connection than this
76084
+ reject(); // The handler is called for a different connection than this
76074
76085
  _itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.Logger.logTrace(loggerCategory, "Attempting to reopen connection", () => iModelRpcProps);
76075
76086
  try {
76076
76087
  const openResponse = await CheckpointConnection.callOpen(iModelRpcProps, this.routingContext);
@@ -87507,7 +87518,7 @@ class SubCategoriesCache {
87507
87518
  (function (SubCategoriesCache) {
87508
87519
  class Request {
87509
87520
  get wasCanceled() { return this._canceled || this._imodel.isClosed; }
87510
- constructor(categoryIds, imodel, maxCategoriesPerQuery = 200) {
87521
+ constructor(categoryIds, imodel, maxCategoriesPerQuery = 2500) {
87511
87522
  this._categoryIds = [];
87512
87523
  this._result = [];
87513
87524
  this._canceled = false;
@@ -166239,7 +166250,9 @@ class ToolAdmin {
166239
166250
  */
166240
166251
  this.manipulatorToolEvent = new _itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.BeEvent();
166241
166252
  }
166242
- /** The name of the [[PrimitiveTool]] to use as the default tool. Defaults to "Select", referring to [[SelectionTool]].
166253
+ /** The name of the [[PrimitiveTool]] to use as the default tool.
166254
+ * Defaults to "Select", referring to [[SelectionTool]].
166255
+ * @note An empty string signifies no default tool allowing more events to be handled by [[idleTool]].
166243
166256
  * @see [[startDefaultTool]] to activate the default tool.
166244
166257
  * @see [[defaultToolArgs]] to supply arguments when starting the tool.
166245
166258
  */
@@ -167205,9 +167218,15 @@ class ToolAdmin {
167205
167218
  this.onActiveToolChanged(newTool, StartOrResume.Start);
167206
167219
  }
167207
167220
  /** @internal */
167221
+ setEditCommandHandler(handler) {
167222
+ this._editCommandHandler = handler;
167223
+ }
167224
+ /** @internal */
167208
167225
  async setPrimitiveTool(newTool) {
167209
167226
  if (undefined !== this._primitiveTool) {
167210
167227
  await this._primitiveTool.onCleanup();
167228
+ if (undefined !== this._editCommandHandler)
167229
+ await this._editCommandHandler.finishCommand();
167211
167230
  this._primitiveTool = undefined;
167212
167231
  }
167213
167232
  this._primitiveTool = newTool;
@@ -167291,15 +167310,25 @@ class ToolAdmin {
167291
167310
  }
167292
167311
  }
167293
167312
  /**
167294
- * Starts the default [[Tool]], if any. Generally invoked automatically when other tools exit, so shouldn't be called directly.
167295
- * @note The default tool is expected to be a subclass of [[PrimitiveTool]]. A call to startDefaultTool is required to terminate
167296
- * an active [[ViewTool]] or [[InputCollector]] and replace or clear the current [[PrimitiveTool]].
167313
+ * Starts the default [[PrimitiveTool]], if any. Generally invoked automatically when other tools exit, so shouldn't be called directly.
167314
+ * @note The default tool, when specified, must be a subclass of [[PrimitiveTool]]. A call to startDefaultTool is required to terminate
167315
+ * an active [[ViewTool]] or [[InputCollector]] and replace or clear the current [[PrimitiveTool]]. The default tool can not be
167316
+ * a subclass of [[ViewTool]] as view tools replace each other and aren't suspended. This means [[ViewTool.exitTool]] would
167317
+ * result in the active tool being undefined instead of making the default tool active.
167297
167318
  * The tool's [[Tool.run]] method is invoked with arguments specified by [[defaultToolArgs]].
167298
167319
  * @see [[defaultToolId]] to configure the default tool.
167299
167320
  */
167300
167321
  async startDefaultTool() {
167301
- if (!await _IModelApp__WEBPACK_IMPORTED_MODULE_5__.IModelApp.tools.run(this.defaultToolId, this.defaultToolArgs))
167302
- return this.startPrimitiveTool(undefined);
167322
+ const tool = _IModelApp__WEBPACK_IMPORTED_MODULE_5__.IModelApp.tools.create(this.defaultToolId, this.defaultToolArgs);
167323
+ if (tool instanceof _PrimitiveTool__WEBPACK_IMPORTED_MODULE_12__.PrimitiveTool) {
167324
+ if (!await tool.run(this.defaultToolArgs))
167325
+ return this.startPrimitiveTool(undefined);
167326
+ }
167327
+ else {
167328
+ await this.startPrimitiveTool(undefined); // Ensure active primitive tool is terminated...
167329
+ if (undefined !== tool)
167330
+ throw new Error("Default tool must be a subclass of PrimitiveTool");
167331
+ }
167303
167332
  }
167304
167333
  /**
167305
167334
  * Call from external events or immediate tools that may have invalidated the current primitive tool's state.
@@ -203532,11 +203561,12 @@ class Angle {
203532
203561
  && dotUV * dotUV <= _Geometry__WEBPACK_IMPORTED_MODULE_0__.Geometry.smallAngleRadiansSquared * dotUU * dotVV;
203533
203562
  }
203534
203563
  /**
203535
- * Return cosine, sine, and radians for the half angle of a "cosine,sine" pair.
203536
- * * This function assumes the input arguments are related to an angle between -PI and PI
203537
- * * This function returns an angle between -PI and PI
203538
- * @param rCos2A cosine value (scaled by radius) for initial angle.
203539
- * @param rSin2A sine value (scaled by radius) for final angle.
203564
+ * Compute the angle A given r*cos(2A) and r*sin(2A) for some nonnegative scalar r.
203565
+ * * This function assumes the input arguments are related to an angle between -PI and PI.
203566
+ * * This function returns an angle between -PI and PI.
203567
+ * @param rCos2A scaled cosine value of twice the angle A.
203568
+ * @param rSin2A scaled sine value of twice the angle A.
203569
+ * @return cos(A), sin(A) and A in radians
203540
203570
  */
203541
203571
  static trigValuesToHalfAngleTrigValues(rCos2A, rSin2A) {
203542
203572
  const r = _Geometry__WEBPACK_IMPORTED_MODULE_0__.Geometry.hypotenuseXY(rCos2A, rSin2A);
@@ -203546,41 +203576,25 @@ class Angle {
203546
203576
  else {
203547
203577
  /* If the caller really gave you sine and cosine values, r should be 1. However,
203548
203578
  * to allow scaled values -- e.g. the x and y components of any vector -- we normalize
203549
- * right here. This adds an extra sqrt and 2 divides to the whole process, but improves
203579
+ * right here. This adds an extra sqrt and two divisions, but improves
203550
203580
  * both the usefulness and robustness of the computation.
203551
203581
  */
203552
203582
  let cosA;
203553
203583
  let sinA = 0.0;
203554
203584
  const cos2A = rCos2A / r;
203555
203585
  const sin2A = rSin2A / r;
203556
- // Original angle in NE and SE quadrants. Half angle in same quadrant
203557
- if (cos2A >= 0.0) {
203558
- /*
203559
- * We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2
203560
- * so 1 + cos2A = 2(cosA)^2 and therefore, cosA = sqrt((1+cos2A)/2)
203561
- * cosine is positive in NE and SE quadrants so we use +sqrt
203562
- */
203563
- cosA = Math.sqrt(0.5 * (1.0 + cos2A));
203564
- // We know sin2A = 2 sinA cosA so sinA = sin2A/(2*cosA)
203565
- sinA = sin2A / (2.0 * cosA);
203586
+ if (cos2A >= 0.0) { // 2A is in NE and SE quadrants, A in same quadrant
203587
+ cosA = Math.sqrt(0.5 * (1.0 + cos2A)); // half angle formula. Use +root since cosA >= 0
203588
+ sinA = sin2A / (2.0 * cosA); // double angle formula
203566
203589
  }
203567
203590
  else {
203568
- // Original angle in NW quadrant. Half angle in NE quadrant
203569
- if (sin2A > 0.0) {
203570
- /*
203571
- * We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2
203572
- * so 1 - cos2A = 2(sinA)^2 and therefore, sinA = sqrt((1-cos2A)/2)
203573
- * sine is positive in NE quadrant so we use +sqrt
203574
- */
203575
- sinA = Math.sqrt(0.5 * (1.0 - cos2A));
203576
- // Original angle in SW quadrant. Half angle in SE quadrant
203591
+ if (sin2A > 0.0) { // 2A in NW quadrant. A in NE quadrant
203592
+ sinA = Math.sqrt(0.5 * (1.0 - cos2A)); // half angle formula. Use +root since sinA > 0
203577
203593
  }
203578
- else {
203579
- // sine is negative in SE quadrant so we use -sqrt
203580
- sinA = -Math.sqrt(0.5 * (1.0 - cos2A));
203594
+ else { // 2A in SW quadrant. A in SE quadrant
203595
+ sinA = -Math.sqrt(0.5 * (1.0 - cos2A)); // half angle formula. Use -root since sinA <= 0
203581
203596
  }
203582
- // We know sin2A = 2 sinA cosA so cosA = sin2A/(2*sinA)
203583
- cosA = sin2A / (2.0 * sinA); // always positive
203597
+ cosA = sin2A / (2.0 * sinA); // double angle formula
203584
203598
  }
203585
203599
  return { c: cosA, s: sinA, radians: Math.atan2(sinA, cosA) };
203586
203600
  }
@@ -203599,18 +203613,19 @@ class Angle {
203599
203613
  return value;
203600
203614
  }
203601
203615
  /**
203602
- * Return the half angle cosine, sine, and radians for given dot products between vectors. The vectors define
203603
- * an ellipse using x(t) = c + U cos(t) + V sin(t) so U and V are at angle t=0 degree and t=90 degree. The
203604
- * half angle t0 is an angle such that x(t0) is one of the ellipse semi-axis.
203605
- * * This construction arises e.g. in `Arc3d.toScaledMatrix3d`.
203606
- * * Given ellipse x(t) = c + U cos(t) + V sin(t), find t0 such that radial vector W(t0) = x(t0) - c is
203607
- * perpendicular to the ellipse.
203616
+ * Return the half angle cosine, sine, and radians for the given vector dot products.
203617
+ * * These values arise e.g. in the computation performed in `Arc3d.toScaledMatrix3d`.
203618
+ * * Let vectors U and V define the ellipse x(t) = c + U cos(t) + V sin(t). We seek an angle t0
203619
+ * such that the radial vector W(t0) := x(t0) - c is perpendicular to the ellipse.
203608
203620
  * * Then 0 = W(t0).x'(t0) = (U cos(t0) + V sin(t0)).(V cos(t0) - U sin(t0)) = U.V cos(2t0) + 0.5 (V.V - U.U) sin(2t0)
203609
- * implies sin(2t0) / cos(2t0) = 2 U.V / (U.U - V.V), i.e., t0 can be computed given the three dot products on the RHS.
203610
- * math details can be found at docs/learning/geometry/Angle.md
203621
+ * implies tan(2t0) = sin(2t0) / cos(2t0) = 2 U.V / (U.U - V.V), i.e., t0 can be computed given the input dot products.
203622
+ * Math details can be found at docs/learning/geometry/Angle.md
203611
203623
  * @param dotUU dot product of vectorU with itself
203612
203624
  * @param dotVV dot product of vectorV with itself
203613
203625
  * @param dotUV dot product of vectorU with vectorV
203626
+ * @param favorZero whether to allow a tight tolerance for returning t0 = 0 (default true).
203627
+ * When dotUV is near zero, U and V are nearly perpendicular, and the returned angle is near zero.
203628
+ * @return the angle t0 and its cosine and sine.
203614
203629
  */
203615
203630
  static dotProductsToHalfAngleTrigValues(dotUU, dotVV, dotUV, favorZero = true) {
203616
203631
  const cos2t0 = dotUU - dotVV;
@@ -233789,6 +233804,10 @@ __webpack_require__.r(__webpack_exports__);
233789
233804
  /* harmony export */ "IndexedPolyfaceVisitor": () => (/* binding */ IndexedPolyfaceVisitor)
233790
233805
  /* harmony export */ });
233791
233806
  /* harmony import */ var _Geometry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Geometry */ "../../core/geometry/lib/esm/Geometry.js");
233807
+ /* harmony import */ var _geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../geometry3d/Angle */ "../../core/geometry/lib/esm/geometry3d/Angle.js");
233808
+ /* harmony import */ var _geometry3d_Point3dVector3d__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../geometry3d/Point3dVector3d */ "../../core/geometry/lib/esm/geometry3d/Point3dVector3d.js");
233809
+ /* harmony import */ var _geometry3d_PolygonOps__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../geometry3d/PolygonOps */ "../../core/geometry/lib/esm/geometry3d/PolygonOps.js");
233810
+ /* harmony import */ var _Polyface__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Polyface */ "../../core/geometry/lib/esm/polyface/Polyface.js");
233792
233811
  /* harmony import */ var _PolyfaceData__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./PolyfaceData */ "../../core/geometry/lib/esm/polyface/PolyfaceData.js");
233793
233812
  /*---------------------------------------------------------------------------------------------
233794
233813
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
@@ -233799,6 +233818,10 @@ __webpack_require__.r(__webpack_exports__);
233799
233818
  */
233800
233819
 
233801
233820
 
233821
+
233822
+
233823
+
233824
+
233802
233825
  /* eslint-disable @itwin/prefer-get */
233803
233826
  /**
233804
233827
  * An `IndexedPolyfaceVisitor` is an iterator-like object that "visits" facets of a mesh.
@@ -233822,6 +233845,10 @@ class IndexedPolyfaceVisitor extends _PolyfaceData__WEBPACK_IMPORTED_MODULE_0__.
233822
233845
  clientPolyface() {
233823
233846
  return this._polyface;
233824
233847
  }
233848
+ /** Return the number of facets this visitor is able to visit. */
233849
+ getVisitableFacetCount() {
233850
+ return this._polyface.facetCount;
233851
+ }
233825
233852
  /**
233826
233853
  * Set the number of vertices replicated in visitor arrays (both data and index arrays).
233827
233854
  * * 0,1,2 are the most common as numWrap.
@@ -233966,53 +233993,99 @@ class IndexedPolyfaceVisitor extends _PolyfaceData__WEBPACK_IMPORTED_MODULE_0__.
233966
233993
  /**
233967
233994
  * An `IndexedPolyfaceSubsetVisitor` is an `IndexedPolyfaceVisitor` which only visits a subset of facets in the polyface.
233968
233995
  * * The subset is defined by an array of facet indices provided when this visitor is created.
233969
- * * Within the subset visitor, `facetIndex` is understood as index within the subset array:
233970
- * * `moveToNextFacet` moves only within the subset.
233971
- * * `moveToReadIndex(i)` moves underlying visitor's `parentFacetIndex(i)`.
233996
+ * * Input indices (e.g., for `moveToReadIndex`) are understood to be indices into the subset array.
233972
233997
  * @public
233973
233998
  */
233974
233999
  class IndexedPolyfaceSubsetVisitor extends IndexedPolyfaceVisitor {
233975
234000
  constructor(polyface, activeFacetIndices, numWrap) {
233976
234001
  super(polyface, numWrap);
233977
234002
  this._parentFacetIndices = activeFacetIndices.slice();
234003
+ this._currentActiveIndex = -1;
233978
234004
  this._nextActiveIndex = 0;
233979
234005
  }
234006
+ isValidSubsetIndex(index) {
234007
+ return (undefined !== this._parentFacetIndices) && index >= 0 && index < this._parentFacetIndices.length;
234008
+ }
233980
234009
  /**
233981
234010
  * Create a visitor for iterating a subset of the facets of `polyface`.
233982
- * * The `activeFacetIndices` array indicates all facets to be visited.
234011
+ * @param polyface reference to the client polyface, supplying facets
234012
+ * @param activeFacetIndices array of indices of facets in the client polyface to visit. This array is cloned.
234013
+ * @param numWrap number of vertices replicated in the visitor arrays to facilitate simpler caller code. Default is zero.
233983
234014
  */
233984
- static createSubsetVisitor(polyface, activeFacetIndices, numWrap) {
234015
+ static createSubsetVisitor(polyface, activeFacetIndices, numWrap = 0) {
233985
234016
  return new IndexedPolyfaceSubsetVisitor(polyface, activeFacetIndices, numWrap);
233986
234017
  }
233987
- /** Advance the iterator to a particular facet in the client polyface. */
234018
+ /**
234019
+ * Advance the iterator to a particular facet in the subset of client polyface facets.
234020
+ * @param activeIndex the index of the facet within the subset, not to be confused with the index of the facet within the client polyface.
234021
+ * @return whether the iterator was successfully moved.
234022
+ */
233988
234023
  moveToReadIndex(activeIndex) {
233989
- if (activeIndex >= 0 && activeIndex <= this._parentFacetIndices.length) {
233990
- this._nextActiveIndex = activeIndex;
233991
- return super.moveToReadIndex(this._parentFacetIndices[activeIndex++]);
234024
+ if (this.isValidSubsetIndex(activeIndex)) {
234025
+ this._currentActiveIndex = activeIndex;
234026
+ this._nextActiveIndex = activeIndex + 1;
234027
+ return super.moveToReadIndex(this._parentFacetIndices[activeIndex]);
233992
234028
  }
233993
234029
  return false;
233994
234030
  }
233995
- /** Advance the iterator to the next facet in the client polyface. */
234031
+ /**
234032
+ * Advance the iterator to the next facet in the subset of client polyface facets.
234033
+ * @return whether the iterator was successfully moved.
234034
+ */
233996
234035
  moveToNextFacet() {
233997
- if (this._nextActiveIndex < this._parentFacetIndices.length) {
233998
- const result = this.moveToReadIndex(this._nextActiveIndex);
233999
- if (result) {
234000
- this._nextActiveIndex++;
234001
- return true;
234002
- }
234003
- }
234004
- return false;
234036
+ if (this._nextActiveIndex !== this._currentActiveIndex)
234037
+ return this.moveToReadIndex(this._nextActiveIndex);
234038
+ this._nextActiveIndex++;
234039
+ return true;
234005
234040
  }
234006
- /** Reset the iterator to start at the first active facet in the polyface. */
234041
+ /** Reset the iterator to start at the first active facet in the subset of client polyface facets. */
234007
234042
  reset() {
234008
- this._nextActiveIndex = 0;
234043
+ this.moveToReadIndex(0);
234044
+ this._nextActiveIndex = 0; // so immediate moveToNextFacet stays here.
234009
234045
  }
234010
- /** Return the parent facet index of the indicated index within the active facets. */
234046
+ /**
234047
+ * Return the parent facet index of the indicated index within the subset of client polyface facets.
234048
+ * @param activeIndex index of the facet within the subset. Default is the active facet.
234049
+ * @return valid client polyface facet index, or `undefined` if invalid input index.
234050
+ */
234011
234051
  parentFacetIndex(activeIndex) {
234012
- if (activeIndex >= 0 && activeIndex <= this._nextActiveIndex) {
234013
- return this._parentFacetIndices[activeIndex];
234052
+ if (undefined === activeIndex)
234053
+ activeIndex = this._currentActiveIndex;
234054
+ return this.isValidSubsetIndex(activeIndex) ? this._parentFacetIndices[activeIndex] : undefined;
234055
+ }
234056
+ /** Return the number of facets this visitor is able to visit. */
234057
+ getVisitableFacetCount() {
234058
+ return this._parentFacetIndices ? this._parentFacetIndices.length : 0;
234059
+ }
234060
+ /**
234061
+ * Create a visitor for those mesh facets with normal in the same half-space as the given vector.
234062
+ * * For example, to visit the top facets of a tiled terrain mesh but skip the "skirt" facets, pass
234063
+ * `compareVector = Vector3d.unitZ()` and a suitable `sideAngle` tolerance. Note that this will also
234064
+ * filter out *interior* facets that are nearly vertical, not just the "skirt" facets on the boundary.
234065
+ * @param mesh the mesh from which to select facets
234066
+ * @param compareVector vector to which to compare facet normals. The visitor will visit only those facets
234067
+ * with normals in the same half-space as this vector. Default is 001.
234068
+ * @param sideAngle optional angular tolerance to filter the facets near the border between half-spaces.
234069
+ * The visitor will *not* visit facets whose normals are nearly perpendicular to `compareVector`.
234070
+ * Default is [[Geometry.smallAngleRadians]].
234071
+ * @param numWrap optional number of entries replicated in visitor arrays. Default is 0.
234072
+ */
234073
+ static createNormalComparison(mesh, compareVector = _geometry3d_Point3dVector3d__WEBPACK_IMPORTED_MODULE_2__.Vector3d.unitZ(), sideAngle = _geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__.Angle.createSmallAngle(), numWrap = 0) {
234074
+ if (mesh instanceof _Polyface__WEBPACK_IMPORTED_MODULE_4__.IndexedPolyface)
234075
+ return this.createNormalComparison(mesh.createVisitor(), compareVector, sideAngle, numWrap);
234076
+ const visitor = mesh;
234077
+ const facets = [];
234078
+ const facetNormal = _geometry3d_Point3dVector3d__WEBPACK_IMPORTED_MODULE_2__.Vector3d.createZero();
234079
+ for (visitor.reset(); visitor.moveToNextFacet();) {
234080
+ if (!_geometry3d_PolygonOps__WEBPACK_IMPORTED_MODULE_5__.PolygonOps.unitNormal(visitor.point, facetNormal))
234081
+ continue; // degenerate facet
234082
+ if (facetNormal.dotProduct(compareVector) < 0.0)
234083
+ continue; // ignore facet facing other half-space
234084
+ if (facetNormal.angleFromPerpendicular(compareVector).isMagnitudeLessThanOrEqual(sideAngle))
234085
+ continue; // ignore side facet
234086
+ facets.push(visitor.currentReadIndex());
234014
234087
  }
234015
- return undefined;
234088
+ return IndexedPolyfaceSubsetVisitor.createSubsetVisitor(visitor.clientPolyface(), facets, numWrap);
234016
234089
  }
234017
234090
  }
234018
234091
 
@@ -238356,40 +238429,22 @@ class PolyfaceQuery {
238356
238429
  return true;
238357
238430
  }
238358
238431
  /**
238359
- * Test for convex volume by dihedral angle tests on all edges.
238360
- * * This tests if all dihedral angles of the mesh are positive.
238361
- * * In a closed solid, this is a strong test for overall mesh convexity with outward facing normals.
238362
- * * See [[dihedralAngleSummary]] for the definition of "dihedral angle".
238363
- * * With `ignoreBoundaries` true, this may be a useful test when all the facets are in a single edge-connected
238364
- * component, such as a pyramid with no underside.
238365
- * * It is not a correct test if there are multiple, disjoint components.
238366
- * * Take the above-mentioned pyramid with no underside.
238367
- * * Within the same mesh, have a second pyramid placed to the side, still facing upward.
238368
- * * The angles will pass the dihedral convexity test, but the composite thing surely is not convex.
238432
+ * Compute a number summarizing the dihedral angles in the mesh.
238433
+ * * A dihedral angle is the signed angle between adjacent facets' normals. This angle is positive when the cross
238434
+ * product `normalA x normalB` has the same direction as facetA's traversal of the facets' shared edge.
238369
238435
  * @param source mesh.
238370
238436
  * @param ignoreBoundaries if `true` ignore simple boundary edges, i.e., allow unclosed meshes. Default is `false`.
238371
- * @returns true if all dihedral angles of the mesh are positive.
238437
+ * See [[isConvexByDihedralAngleCount]] for comments about passing true when there are multiple
238438
+ * connected components.
238439
+ * * Return `0` if all dihedral angles are zero (and `ignoreBoundaries === true`). The mesh is planar.
238440
+ * * Otherwise, return `1` if all dihedral angles are non-negative. The mesh probably encloses a convex volume and
238441
+ * has outward normals.
238442
+ * * Otherwise, return `-1` if all dihedral angles are non-positive. The mesh probably encloses a convex volume and
238443
+ * has inward normals.
238444
+ * * Otherwise, return `-2`. Also return `-2` if a non-manifold condition was detected, or a facet normal could not
238445
+ * be computed. A non-manifold condition is a positive-length edge adjacent to more than 2 facets or (if
238446
+ * `ignoreBoundaries` is false) adjacent to exactly one facet.
238372
238447
  */
238373
- static isConvexByDihedralAngleCount(source, ignoreBoundaries = false) {
238374
- return this.dihedralAngleSummary(source, ignoreBoundaries) > 0;
238375
- }
238376
- /**
238377
- * Compute a number summarizing the dihedral angles in the mesh.
238378
- * * A dihedral angle is the signed angle between adjacent facets' normals. This angle is positive when the cross
238379
- * product `normalA x normalB` has the same direction as facetA's traversal of the facets' shared edge.
238380
- * @param source mesh.
238381
- * @param ignoreBoundaries if `true` ignore simple boundary edges, i.e., allow unclosed meshes. Default is `false`.
238382
- * See [[isConvexByDihedralAngleCount]] for comments about passing true when there are multiple
238383
- * connected components.
238384
- * * Return `0` if all dihedral angles are zero (and `ignoreBoundaries === true`). The mesh is planar.
238385
- * * Otherwise, return `1` if all dihedral angles are non-negative. The mesh probably encloses a convex volume and
238386
- * has outward normals.
238387
- * * Otherwise, return `-1` if all dihedral angles are non-positive. The mesh probably encloses a convex volume and
238388
- * has inward normals.
238389
- * * Otherwise, return `-2`. Also return `-2` if a non-manifold condition was detected, or a facet normal could not
238390
- * be computed. A non-manifold condition is a positive-length edge adjacent to more than 2 facets or (if
238391
- * `ignoreBoundaries` is false) adjacent to exactly one facet.
238392
- */
238393
238448
  static dihedralAngleSummary(source, ignoreBoundaries = false) {
238394
238449
  // more info can be found at geometry/internaldocs/Polyface.md
238395
238450
  const edges = new _IndexedEdgeMatcher__WEBPACK_IMPORTED_MODULE_10__.IndexedEdgeMatcher();
@@ -238445,9 +238500,23 @@ class PolyfaceQuery {
238445
238500
  return 0;
238446
238501
  return -2;
238447
238502
  }
238448
- /** Test if the facets in `source` occur in perfectly mated pairs, as is required for a closed manifold volume. */
238449
- static isPolyfaceClosedByEdgePairing(source) {
238450
- return this.isPolyfaceManifold(source, false);
238503
+ /**
238504
+ * Test for convex volume by dihedral angle tests on all edges.
238505
+ * * This tests if all dihedral angles of the mesh are positive.
238506
+ * * In a closed solid, this is a strong test for overall mesh convexity with outward facing normals.
238507
+ * * See [[dihedralAngleSummary]] for the definition of "dihedral angle".
238508
+ * * With `ignoreBoundaries` true, this may be a useful test when all the facets are in a single edge-connected
238509
+ * component, such as a pyramid with no underside.
238510
+ * * It is not a correct test if there are multiple, disjoint components.
238511
+ * * Take the above-mentioned pyramid with no underside.
238512
+ * * Within the same mesh, have a second pyramid placed to the side, still facing upward.
238513
+ * * The angles will pass the dihedral convexity test, but the composite thing surely is not convex.
238514
+ * @param source mesh.
238515
+ * @param ignoreBoundaries if `true` ignore simple boundary edges, i.e., allow unclosed meshes. Default is `false`.
238516
+ * @returns true if all dihedral angles of the mesh are positive.
238517
+ */
238518
+ static isConvexByDihedralAngleCount(source, ignoreBoundaries = false) {
238519
+ return this.dihedralAngleSummary(source, ignoreBoundaries) > 0;
238451
238520
  }
238452
238521
  /**
238453
238522
  * Test edges pairing in `source` mesh.
@@ -238471,36 +238540,9 @@ class PolyfaceQuery {
238471
238540
  edges.sortAndCollectClusters(undefined, allowSimpleBoundaries ? undefined : badClusters, undefined, badClusters);
238472
238541
  return badClusters.length === 0;
238473
238542
  }
238474
- /**
238475
- * Construct a CurveCollection containing boundary edges.
238476
- * * Each edge is a LineSegment3d.
238477
- * @param source polyface or visitor.
238478
- * @param includeTypical true to in include typical boundary edges with a single adjacent facet.
238479
- * @param includeMismatch true to include edges with more than 2 adjacent facets.
238480
- * @param includeNull true to include edges with identical start and end vertex indices.
238481
- */
238482
- static boundaryEdges(source, includeTypical = true, includeMismatch = true, includeNull = true) {
238483
- const result = new _curve_CurveCollection__WEBPACK_IMPORTED_MODULE_5__.BagOfCurves();
238484
- const announceEdge = (pointA, pointB, _indexA, _indexB, _readIndex) => {
238485
- result.tryAddChild(_curve_LineSegment3d__WEBPACK_IMPORTED_MODULE_11__.LineSegment3d.create(pointA, pointB));
238486
- };
238487
- PolyfaceQuery.announceBoundaryEdges(source, announceEdge, includeTypical, includeMismatch, includeNull);
238488
- if (result.children.length === 0)
238489
- return undefined;
238490
- return result;
238491
- }
238492
- /**
238493
- * Collect boundary edges.
238494
- * * Return the edges as the simplest collection of chains of line segments.
238495
- * @param source polyface or visitor.
238496
- * @param includeTypical true to in include typical boundary edges with a single adjacent facet.
238497
- * @param includeMismatch true to include edges with more than 2 adjacent facets.
238498
- * @param includeNull true to include edges with identical start and end vertex indices.
238499
- */
238500
- static collectBoundaryEdges(source, includeTypical = true, includeMismatch = true, includeNull = true) {
238501
- const collector = new _curve_internalContexts_MultiChainCollector__WEBPACK_IMPORTED_MODULE_12__.MultiChainCollector(_Geometry__WEBPACK_IMPORTED_MODULE_2__.Geometry.smallMetricDistance, _Geometry__WEBPACK_IMPORTED_MODULE_2__.Geometry.smallMetricDistance);
238502
- PolyfaceQuery.announceBoundaryEdges(source, (ptA, ptB) => collector.captureCurve(_curve_LineSegment3d__WEBPACK_IMPORTED_MODULE_11__.LineSegment3d.create(ptA, ptB)), includeTypical, includeMismatch, includeNull);
238503
- return collector.grabResult(true);
238543
+ /** Test if the facets in `source` occur in perfectly mated pairs, as is required for a closed manifold volume. */
238544
+ static isPolyfaceClosedByEdgePairing(source) {
238545
+ return this.isPolyfaceManifold(source, false);
238504
238546
  }
238505
238547
  /**
238506
238548
  * Test if the facets in `source` occur in perfectly mated pairs, as is required for a closed manifold volume.
@@ -238551,6 +238593,37 @@ class PolyfaceQuery {
238551
238593
  }
238552
238594
  }
238553
238595
  }
238596
+ /**
238597
+ * Construct a CurveCollection containing boundary edges.
238598
+ * * Each edge is a LineSegment3d.
238599
+ * @param source polyface or visitor.
238600
+ * @param includeTypical true to in include typical boundary edges with a single adjacent facet.
238601
+ * @param includeMismatch true to include edges with more than 2 adjacent facets.
238602
+ * @param includeNull true to include edges with identical start and end vertex indices.
238603
+ */
238604
+ static boundaryEdges(source, includeTypical = true, includeMismatch = true, includeNull = true) {
238605
+ const result = new _curve_CurveCollection__WEBPACK_IMPORTED_MODULE_5__.BagOfCurves();
238606
+ const announceEdge = (pointA, pointB, _indexA, _indexB, _readIndex) => {
238607
+ result.tryAddChild(_curve_LineSegment3d__WEBPACK_IMPORTED_MODULE_11__.LineSegment3d.create(pointA, pointB));
238608
+ };
238609
+ PolyfaceQuery.announceBoundaryEdges(source, announceEdge, includeTypical, includeMismatch, includeNull);
238610
+ if (result.children.length === 0)
238611
+ return undefined;
238612
+ return result;
238613
+ }
238614
+ /**
238615
+ * Collect boundary edges.
238616
+ * * Return the edges as the simplest collection of chains of line segments.
238617
+ * @param source polyface or visitor.
238618
+ * @param includeTypical true to in include typical boundary edges with a single adjacent facet.
238619
+ * @param includeMismatch true to include edges with more than 2 adjacent facets.
238620
+ * @param includeNull true to include edges with identical start and end vertex indices.
238621
+ */
238622
+ static collectBoundaryEdges(source, includeTypical = true, includeMismatch = true, includeNull = true) {
238623
+ const collector = new _curve_internalContexts_MultiChainCollector__WEBPACK_IMPORTED_MODULE_12__.MultiChainCollector(_Geometry__WEBPACK_IMPORTED_MODULE_2__.Geometry.smallMetricDistance, _Geometry__WEBPACK_IMPORTED_MODULE_2__.Geometry.smallMetricDistance);
238624
+ PolyfaceQuery.announceBoundaryEdges(source, (ptA, ptB) => collector.captureCurve(_curve_LineSegment3d__WEBPACK_IMPORTED_MODULE_11__.LineSegment3d.create(ptA, ptB)), includeTypical, includeMismatch, includeNull);
238625
+ return collector.grabResult(true);
238626
+ }
238554
238627
  /**
238555
238628
  * Load all half edges from a mesh to an IndexedEdgeMatcher.
238556
238629
  * @param polyface a mesh or a visitor assumed to have numWrap === 1.
@@ -238996,13 +239069,17 @@ class PolyfaceQuery {
238996
239069
  }
238997
239070
  return builder.claimPolyface(true);
238998
239071
  }
238999
- /** Return the point count of the `source`. */
239072
+ /**
239073
+ * Return the point count of the `source`.
239074
+ * * If `source` is a visitor, this is an upper bound on the number of addressed mesh vertices.
239075
+ */
239000
239076
  static visitorClientPointCount(source) {
239001
239077
  if (source instanceof _Polyface__WEBPACK_IMPORTED_MODULE_6__.Polyface)
239002
239078
  return source.data.point.length;
239003
239079
  const polyface = source.clientPolyface();
239004
239080
  if (polyface !== undefined)
239005
239081
  return polyface.data.point.length;
239082
+ const saveReadIndex = source.currentReadIndex();
239006
239083
  source.reset();
239007
239084
  let maxIndex = -1;
239008
239085
  while (source.moveToNextFacet()) {
@@ -239010,22 +239087,30 @@ class PolyfaceQuery {
239010
239087
  if (pointIndex > maxIndex)
239011
239088
  maxIndex = pointIndex;
239012
239089
  }
239090
+ source.moveToReadIndex(saveReadIndex);
239013
239091
  return maxIndex + 1;
239014
239092
  }
239015
- /** Return the facet count of the `source`. */
239093
+ /**
239094
+ * Return the facet count of the `source`.
239095
+ * * If `source` is a visitor, this is the number of facets it can visit.
239096
+ */
239016
239097
  static visitorClientFacetCount(source) {
239017
239098
  if (source instanceof _Polyface__WEBPACK_IMPORTED_MODULE_6__.Polyface) {
239018
239099
  if (source.facetCount !== undefined)
239019
239100
  return source.facetCount;
239020
239101
  source = source.createVisitor(0);
239021
239102
  }
239103
+ if (source.getVisitableFacetCount)
239104
+ return source.getVisitableFacetCount();
239022
239105
  const polyface = source.clientPolyface();
239023
239106
  if (polyface !== undefined && polyface.facetCount !== undefined)
239024
239107
  return polyface.facetCount;
239108
+ const saveReadIndex = source.currentReadIndex();
239025
239109
  let facetCount = 0;
239026
239110
  source.reset();
239027
239111
  while (source.moveToNextFacet())
239028
239112
  ++facetCount;
239113
+ source.moveToReadIndex(saveReadIndex);
239029
239114
  return facetCount;
239030
239115
  }
239031
239116
  /**
@@ -239330,21 +239415,6 @@ class PolyfaceQuery {
239330
239415
  }
239331
239416
  return 0;
239332
239417
  }
239333
- /**
239334
- * Collect facet duplicates.
239335
- * @param polyface the polyface.
239336
- * @param includeSingletons if true, non-duplicated facets are included in the output.
239337
- * @returns an array of arrays describing facet duplication. Each array `entry` in the output contains read
239338
- * indices of a cluster of facets with the same vertex indices.
239339
- */
239340
- static collectDuplicateFacetIndices(polyface, includeSingletons = false) {
239341
- const result = [];
239342
- this.announceDuplicateFacetIndices(polyface, (clusterFacetIndices) => {
239343
- if (includeSingletons || clusterFacetIndices.length > 1)
239344
- result.push(clusterFacetIndices.slice());
239345
- });
239346
- return result;
239347
- }
239348
239418
  /**
239349
239419
  * Announce facet duplicates.
239350
239420
  * @returns an array of arrays describing facet duplication. Each array `entry` in the output contains read
@@ -239393,10 +239463,25 @@ class PolyfaceQuery {
239393
239463
  }
239394
239464
  }
239395
239465
  /**
239396
- * Return a new facet set with a subset of facets in polyface.
239466
+ * Collect facet duplicates.
239467
+ * @param polyface the polyface.
239468
+ * @param includeSingletons if true, non-duplicated facets are included in the output.
239469
+ * @returns an array of arrays describing facet duplication. Each array `entry` in the output contains read
239470
+ * indices of a cluster of facets with the same vertex indices.
239471
+ */
239472
+ static collectDuplicateFacetIndices(polyface, includeSingletons = false) {
239473
+ const result = [];
239474
+ this.announceDuplicateFacetIndices(polyface, (clusterFacetIndices) => {
239475
+ if (includeSingletons || clusterFacetIndices.length > 1)
239476
+ result.push(clusterFacetIndices.slice());
239477
+ });
239478
+ return result;
239479
+ }
239480
+ /**
239481
+ * Return a new facet set from the source facets, specifying how to copy duplicate facets.
239397
239482
  * @param source the polyface.
239398
239483
  * @param includeSingletons true to copy facets that only appear once
239399
- * @param clusterSelector indicates whether duplicate clusters are to have 0, 1, or all facets included.
239484
+ * @param clusterSelector indicates whether to copy 0, 1, or all facets in each cluster of duplicate facets.
239400
239485
  */
239401
239486
  static cloneByFacetDuplication(source, includeSingletons, clusterSelector) {
239402
239487
  const builder = _PolyfaceBuilder__WEBPACK_IMPORTED_MODULE_16__.PolyfaceBuilder.create();
@@ -257034,8 +257119,8 @@ __webpack_require__.r(__webpack_exports__);
257034
257119
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
257035
257120
  /* harmony export */ "TorusPipe": () => (/* binding */ TorusPipe)
257036
257121
  /* harmony export */ });
257037
- /* harmony import */ var _curve_Arc3d__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../curve/Arc3d */ "../../core/geometry/lib/esm/curve/Arc3d.js");
257038
- /* harmony import */ var _curve_Loop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../curve/Loop */ "../../core/geometry/lib/esm/curve/Loop.js");
257122
+ /* harmony import */ var _curve_Arc3d__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../curve/Arc3d */ "../../core/geometry/lib/esm/curve/Arc3d.js");
257123
+ /* harmony import */ var _curve_Loop__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../curve/Loop */ "../../core/geometry/lib/esm/curve/Loop.js");
257039
257124
  /* harmony import */ var _curve_Path__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../curve/Path */ "../../core/geometry/lib/esm/curve/Path.js");
257040
257125
  /* harmony import */ var _Geometry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Geometry */ "../../core/geometry/lib/esm/Geometry.js");
257041
257126
  /* harmony import */ var _geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../geometry3d/Angle */ "../../core/geometry/lib/esm/geometry3d/Angle.js");
@@ -257062,23 +257147,27 @@ __webpack_require__.r(__webpack_exports__);
257062
257147
 
257063
257148
 
257064
257149
  /**
257065
- * A torus pipe is a partial torus (donut). In a local coordinate system
257066
- * * The z axis passes through the hole.
257067
- * * The "major hoop" arc has
257068
- * * vectorTheta0 = (radiusA, 0, 0)
257069
- * * vectorTheta90 = (0, radiusA, 0)
257070
- * * The major arc point at angle theta is `C(theta) = vectorTheta0 * cos(theta) + vectorTheta90 * sin(theta)
257071
- * * The minor hoop at theta various with phi "around the minor hoop"
257072
- * * (x,y,z) = C(theta) + (radiusB * cos(theta), radiusB * sin(theta), 0) * cos(phi) + (0, 0, radiusB) * sin(phi)
257150
+ * A torus pipe is a partial torus (donut).
257151
+ * * In its local coordinate system, the z-axis passes through the donut hole.
257152
+ * * The "major hoop" circular arc is defined for theta in the angular sweep. Its formula in local coordinates:
257153
+ * * `vectorTheta0 = (radiusA, 0, 0)`
257154
+ * * `vectorTheta90 = (0, radiusA, 0)`
257155
+ * * `M(theta) = vectorTheta0 * cos(theta) + vectorTheta90 * sin(theta)`
257156
+ * * The "minor hoop" circular arc is defined for phi in [0,2pi]. Its formula, centered at the origin:
257157
+ * * `vectorPhi0 = (radiusB * cos(theta), radiusB * sin(theta), 0)`
257158
+ * * `vectorPhi90 = (0, 0, radiusB)`
257159
+ * * `m(phi) = vectorPhi0 * cos(phi) + vectorPhi90 * sin(phi)`
257160
+ * * Thus the torus pipe in local coordinates has the formula:
257161
+ * * `T(theta, phi) = M(theta) + m(phi)`
257073
257162
  * * The stored form of the torus pipe is oriented for positive volume:
257074
257163
  * * Both radii are positive, with radiusA >= radiusB > 0
257075
257164
  * * The sweep is positive
257076
257165
  * * The coordinate system has positive determinant.
257077
257166
  * * For uv parameterization,
257078
- * * u is around the minor hoop, with (0..1) mapping to phi of (0 degrees ..360 degrees)
257079
- * * v is along the major hoop with (0..1) mapping to theta of (0 .. sweep)
257167
+ * * u is around the minor hoop, with u in [0,1] mapping to phi in [0, 2pi]
257168
+ * * v is along the major hoop, with v in [0,1] mapping to theta in the angular sweep
257080
257169
  * * a constant v section is a full circle
257081
- * * a constant u section is an arc with sweep angle matching the torusPipe sweep angle.
257170
+ * * a constant u section is an arc with the same angular sweep as the torusPipe
257082
257171
  * @public
257083
257172
  */
257084
257173
  class TorusPipe extends _SolidPrimitive__WEBPACK_IMPORTED_MODULE_0__.SolidPrimitive {
@@ -257157,14 +257246,22 @@ class TorusPipe extends _SolidPrimitive__WEBPACK_IMPORTED_MODULE_0__.SolidPrimit
257157
257246
  const frame = _geometry3d_Transform__WEBPACK_IMPORTED_MODULE_2__.Transform.createOriginAndMatrixColumns(center, vectorX, vectorY, vectorZ);
257158
257247
  return TorusPipe.createInFrame(frame, majorRadius, minorRadius, sweep, capped);
257159
257248
  }
257160
- /** Create a TorusPipe from its primary arc and minor radius */
257249
+ /**
257250
+ * Create a TorusPipe from major arc and minor radius.
257251
+ * For best results, `arc` should be circular; otherwise, circularity is coerced.
257252
+ */
257161
257253
  static createAlongArc(arc, minorRadius, capped) {
257162
257254
  if (!_geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__.Angle.isAlmostEqualRadiansAllowPeriodShift(0.0, arc.sweep.startRadians))
257163
257255
  arc = arc.cloneInRotatedBasis(arc.sweep.startAngle);
257164
- const sweepRadians = arc.sweep.sweepRadians;
257256
+ if (!arc.isCircular) { // ensure circularity by squaring the axes and equating their lengths
257257
+ const perpVector90 = arc.perpendicularVector.sizedCrossProduct(arc.vector0, arc.matrixRef.columnXMagnitude());
257258
+ if (!perpVector90)
257259
+ return undefined;
257260
+ arc = _curve_Arc3d__WEBPACK_IMPORTED_MODULE_4__.Arc3d.create(arc.center, arc.vector0, perpVector90, arc.sweep);
257261
+ }
257165
257262
  const data = arc.toScaledMatrix3d();
257166
- const frame = _geometry3d_Transform__WEBPACK_IMPORTED_MODULE_2__.Transform.createOriginAndMatrix(data.center, data.axes);
257167
- return TorusPipe.createInFrame(frame, data.r0, minorRadius, _geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__.Angle.createRadians(sweepRadians), capped);
257263
+ const rigidFrame = _geometry3d_Transform__WEBPACK_IMPORTED_MODULE_2__.Transform.createOriginAndMatrix(arc.center, data.axes);
257264
+ return TorusPipe.createInFrame(rigidFrame, data.r0, minorRadius, _geometry3d_Angle__WEBPACK_IMPORTED_MODULE_3__.Angle.createRadians(arc.sweep.sweepRadians), capped);
257168
257265
  }
257169
257266
  /** Return a coordinate frame (right handed, unit axes)
257170
257267
  * * origin at center of major circle
@@ -257251,7 +257348,7 @@ class TorusPipe extends _SolidPrimitive__WEBPACK_IMPORTED_MODULE_0__.SolidPrimit
257251
257348
  const center = this._localToWorld.multiplyXYZ(majorRadius * c0, majorRadius * s0, 0);
257252
257349
  const vector0 = this._localToWorld.multiplyVectorXYZ(minorRadius * c0, minorRadius * s0, 0);
257253
257350
  const vector90 = this._localToWorld.multiplyVectorXYZ(0, 0, minorRadius);
257254
- return _curve_Loop__WEBPACK_IMPORTED_MODULE_4__.Loop.create(_curve_Arc3d__WEBPACK_IMPORTED_MODULE_5__.Arc3d.create(center, vector0, vector90));
257351
+ return _curve_Loop__WEBPACK_IMPORTED_MODULE_5__.Loop.create(_curve_Arc3d__WEBPACK_IMPORTED_MODULE_4__.Arc3d.create(center, vector0, vector90));
257255
257352
  }
257256
257353
  /** Return an arc at constant u, and arc sweep matching this TorusPipe sweep. */
257257
257354
  constantUSection(uFraction) {
@@ -257265,7 +257362,7 @@ class TorusPipe extends _SolidPrimitive__WEBPACK_IMPORTED_MODULE_0__.SolidPrimit
257265
257362
  const rxy = majorRadius + minorRadius * Math.cos(phiRadians);
257266
257363
  const vector0 = axes.multiplyXYZ(rxy, 0, 0);
257267
257364
  const vector90 = axes.multiplyXYZ(0, rxy, 0);
257268
- return _curve_Path__WEBPACK_IMPORTED_MODULE_6__.Path.create(_curve_Arc3d__WEBPACK_IMPORTED_MODULE_5__.Arc3d.create(center, vector0, vector90, _geometry3d_AngleSweep__WEBPACK_IMPORTED_MODULE_7__.AngleSweep.createStartEndRadians(0.0, theta1Radians)));
257365
+ return _curve_Path__WEBPACK_IMPORTED_MODULE_6__.Path.create(_curve_Arc3d__WEBPACK_IMPORTED_MODULE_4__.Arc3d.create(center, vector0, vector90, _geometry3d_AngleSweep__WEBPACK_IMPORTED_MODULE_7__.AngleSweep.createStartEndRadians(0.0, theta1Radians)));
257269
257366
  }
257270
257367
  /** extend `rangeToExtend` to include this `TorusPipe` */
257271
257368
  extendRange(rangeToExtend, transform) {
@@ -282543,6 +282640,10 @@ class Parser {
282543
282640
  }
282544
282641
  // common case where single value and single label are supplied
282545
282642
  if (tokens.length === 2) {
282643
+ // unit specification comes before value (like currency)
282644
+ if (tokens[1].isNumber && tokens[0].isString) {
282645
+ tokens = [tokens[1], tokens[0]];
282646
+ }
282546
282647
  if (tokens[0].isNumber && tokens[1].isString) {
282547
282648
  const unit = await this.lookupUnitByLabel(tokens[1].value, format, unitsProvider, altUnitLabelsProvider);
282548
282649
  if (undefined === defaultUnit)
@@ -282556,21 +282657,6 @@ class Parser {
282556
282657
  return new _Quantity__WEBPACK_IMPORTED_MODULE_2__.Quantity(defaultUnit, mag);
282557
282658
  }
282558
282659
  }
282559
- else { // unit specification comes before value (like currency)
282560
- if (tokens[1].isNumber && tokens[0].isString) {
282561
- const unit = await this.lookupUnitByLabel(tokens[0].value, format, unitsProvider, altUnitLabelsProvider);
282562
- if (undefined === defaultUnit)
282563
- defaultUnit = unit;
282564
- if (defaultUnit && defaultUnit.name === unit.name) {
282565
- return new _Quantity__WEBPACK_IMPORTED_MODULE_2__.Quantity(defaultUnit, tokens[1].value);
282566
- }
282567
- else if (defaultUnit) {
282568
- const conversion = await unitsProvider.getConversion(unit, defaultUnit);
282569
- const mag = ((tokens[1].value * conversion.factor)) + conversion.offset;
282570
- return new _Quantity__WEBPACK_IMPORTED_MODULE_2__.Quantity(defaultUnit, mag);
282571
- }
282572
- }
282573
- }
282574
282660
  }
282575
282661
  // common case where there are multiple value/label pairs
282576
282662
  if (tokens.length % 2 === 0) {
@@ -282682,8 +282768,16 @@ class Parser {
282682
282768
  }
282683
282769
  // common case where single value and single label are supplied
282684
282770
  if (tokens.length === 2) {
282771
+ // unit specification comes before value (like currency)
282772
+ if (tokens[1].isNumber && tokens[0].isString) {
282773
+ tokens = [tokens[1], tokens[0]];
282774
+ }
282685
282775
  if (tokens[0].isNumber && tokens[1].isString) {
282686
- const conversion = Parser.tryFindUnitConversion(tokens[1].value, unitsConversions, defaultUnit);
282776
+ let conversion = Parser.tryFindUnitConversion(tokens[1].value, unitsConversions, defaultUnit);
282777
+ // if no conversion, ignore value in second token. If we have defaultUnit, use it.
282778
+ if (!conversion && defaultUnit) {
282779
+ conversion = Parser.tryFindUnitConversion(defaultUnit.label, unitsConversions, defaultUnit);
282780
+ }
282687
282781
  if (conversion) {
282688
282782
  const value = tokens[0].value * conversion.factor + conversion.offset;
282689
282783
  return { ok: true, value };
@@ -282691,17 +282785,6 @@ class Parser {
282691
282785
  // if no conversion, just return parsed number and ignore value in second token
282692
282786
  return { ok: true, value: tokens[0].value };
282693
282787
  }
282694
- else { // unit specification comes before value (like currency)
282695
- if (tokens[1].isNumber && tokens[0].isString) {
282696
- const conversion = Parser.tryFindUnitConversion(tokens[0].value, unitsConversions, defaultUnit);
282697
- if (conversion) {
282698
- const value = tokens[1].value * conversion.factor + conversion.offset;
282699
- return { ok: true, value };
282700
- }
282701
- // if no conversion, just return parsed number and ignore value in second token
282702
- return { ok: true, value: tokens[1].value };
282703
- }
282704
- }
282705
282788
  }
282706
282789
  // common case where there are multiple value/label pairs
282707
282790
  if (tokens.length % 2 === 0) {
@@ -297375,7 +297458,7 @@ var loadLanguages = instance.loadLanguages;
297375
297458
  /***/ ((module) => {
297376
297459
 
297377
297460
  "use strict";
297378
- module.exports = JSON.parse('{"name":"@itwin/core-frontend","version":"4.7.0-dev.8","description":"iTwin.js frontend components","main":"lib/cjs/core-frontend.js","module":"lib/esm/core-frontend.js","typings":"lib/cjs/core-frontend","license":"MIT","scripts":{"build":"npm run -s copy:public && npm run -s build:cjs && npm run -s build:esm && npm run -s webpackWorkers && npm run -s copy:workers","build:cjs":"npm run -s copy:js:cjs && tsc 1>&2 --outDir lib/cjs","build:esm":"npm run -s copy:js:esm && tsc 1>&2 --module ES2020 --outDir lib/esm","clean":"rimraf lib .rush/temp/package-deps*.json","copy:public":"cpx \\"./src/public/**/*\\" ./lib/public","copy:js:cjs":"cpx \\"./src/**/*.js\\" ./lib/cjs","copy:js:esm":"cpx \\"./src/**/*.js\\" ./lib/esm","copy:workers":"cpx \\"./lib/workers/webpack/parse-imdl-worker.js\\" ./lib/public/scripts","docs":"betools docs --includes=../../generated-docs/extract --json=../../generated-docs/core/core-frontend/file.json --tsIndexFile=./core-frontend.ts --onlyJson --excludes=webgl/**/*,**/map/*.d.ts,**/tile/*.d.ts,**/*-css.ts","extract-api":"betools extract-api --entry=core-frontend && npm run extract-extension-api","extract-extension-api":"eslint --no-inline-config -c extraction.eslint.config.js \\"./src/**/*.ts\\" 1>&2","lint":"eslint -f visualstudio \\"./src/**/*.ts\\" 1>&2","lint-fix":"eslint --fix -f visualstudio \\"./src/**/*.ts\\" 1>&2","pseudolocalize":"betools pseudolocalize --englishDir ./src/public/locales/en --out ./public/locales/en-PSEUDO","test":"npm run -s webpackTests && certa -r chrome","cover":"npm -s test","test:debug":"certa -r chrome --debug","webpackTests":"webpack --config ./src/test/utils/webpack.config.js 1>&2 && npm run -s webpackTestWorker","webpackTestWorker":"webpack --config ./src/test/worker/webpack.config.js 1>&2 && cpx \\"./lib/test/test-worker.js\\" ./lib/test","webpackWorkers":"webpack --config ./src/workers/ImdlParser/webpack.config.js 1>&2"},"repository":{"type":"git","url":"https://github.com/iTwin/itwinjs-core.git","directory":"core/frontend"},"keywords":["Bentley","BIM","iModel","digital-twin","iTwin"],"author":{"name":"Bentley Systems, Inc.","url":"http://www.bentley.com"},"peerDependencies":{"@itwin/appui-abstract":"workspace:^4.7.0-dev.8","@itwin/core-bentley":"workspace:^4.7.0-dev.8","@itwin/core-common":"workspace:^4.7.0-dev.8","@itwin/core-geometry":"workspace:^4.7.0-dev.8","@itwin/core-orbitgt":"workspace:^4.7.0-dev.8","@itwin/core-quantity":"workspace:^4.7.0-dev.8"},"//devDependencies":["NOTE: All peerDependencies should also be listed as devDependencies since peerDependencies are not considered by npm install","NOTE: All tools used by scripts in this package must be listed as devDependencies"],"devDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/build-tools":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/certa":"workspace:*","@itwin/eslint-plugin":"^4.0.2","@types/chai":"4.3.1","@types/chai-as-promised":"^7","@types/mocha":"^10.0.6","@types/sinon":"^17.0.2","babel-loader":"~8.2.5","babel-plugin-istanbul":"~6.1.1","chai":"^4.3.10","chai-as-promised":"^7.1.1","cpx2":"^3.0.0","eslint":"^8.56.0","glob":"^10.3.12","mocha":"^10.2.0","nyc":"^15.1.0","rimraf":"^3.0.2","sinon":"^17.0.1","source-map-loader":"^4.0.0","typescript":"~5.3.3","typemoq":"^2.1.0","webpack":"^5.76.0"},"//dependencies":["NOTE: these dependencies should be only for things that DO NOT APPEAR IN THE API","NOTE: core-frontend should remain UI technology agnostic, so no react/angular dependencies are allowed"],"dependencies":{"@itwin/cloud-agnostic-core":"^2.1.0","@itwin/object-storage-core":"^2.2.2","@itwin/core-i18n":"workspace:*","@itwin/core-telemetry":"workspace:*","@itwin/webgl-compatibility":"workspace:*","@loaders.gl/core":"^3.1.6","@loaders.gl/draco":"^3.1.6","fuse.js":"^3.3.0","meshoptimizer":"~0.20.0","wms-capabilities":"0.4.0"},"nyc":{"extends":"./node_modules/@itwin/build-tools/.nycrc"}}');
297461
+ module.exports = JSON.parse('{"name":"@itwin/core-frontend","version":"4.8.0-dev.0","description":"iTwin.js frontend components","main":"lib/cjs/core-frontend.js","module":"lib/esm/core-frontend.js","typings":"lib/cjs/core-frontend","license":"MIT","scripts":{"build":"npm run -s copy:public && npm run -s build:cjs && npm run -s build:esm && npm run -s webpackWorkers && npm run -s copy:workers","build:cjs":"npm run -s copy:js:cjs && tsc 1>&2 --outDir lib/cjs","build:esm":"npm run -s copy:js:esm && tsc 1>&2 --module ES2020 --outDir lib/esm","clean":"rimraf lib .rush/temp/package-deps*.json","copy:public":"cpx \\"./src/public/**/*\\" ./lib/public","copy:js:cjs":"cpx \\"./src/**/*.js\\" ./lib/cjs","copy:js:esm":"cpx \\"./src/**/*.js\\" ./lib/esm","copy:workers":"cpx \\"./lib/workers/webpack/parse-imdl-worker.js\\" ./lib/public/scripts","docs":"betools docs --includes=../../generated-docs/extract --json=../../generated-docs/core/core-frontend/file.json --tsIndexFile=./core-frontend.ts --onlyJson --excludes=webgl/**/*,**/map/*.d.ts,**/tile/*.d.ts,**/*-css.ts","extract-api":"betools extract-api --entry=core-frontend && npm run extract-extension-api","extract-extension-api":"eslint --no-inline-config -c extraction.eslint.config.js \\"./src/**/*.ts\\" 1>&2","lint":"eslint -f visualstudio \\"./src/**/*.ts\\" 1>&2","lint-fix":"eslint --fix -f visualstudio \\"./src/**/*.ts\\" 1>&2","pseudolocalize":"betools pseudolocalize --englishDir ./src/public/locales/en --out ./public/locales/en-PSEUDO","test":"npm run -s webpackTests && certa -r chrome","cover":"npm -s test","test:debug":"certa -r chrome --debug","webpackTests":"webpack --config ./src/test/utils/webpack.config.js 1>&2 && npm run -s webpackTestWorker","webpackTestWorker":"webpack --config ./src/test/worker/webpack.config.js 1>&2 && cpx \\"./lib/test/test-worker.js\\" ./lib/test","webpackWorkers":"webpack --config ./src/workers/ImdlParser/webpack.config.js 1>&2"},"repository":{"type":"git","url":"https://github.com/iTwin/itwinjs-core.git","directory":"core/frontend"},"keywords":["Bentley","BIM","iModel","digital-twin","iTwin"],"author":{"name":"Bentley Systems, Inc.","url":"http://www.bentley.com"},"peerDependencies":{"@itwin/appui-abstract":"workspace:^4.8.0-dev.0","@itwin/core-bentley":"workspace:^4.8.0-dev.0","@itwin/core-common":"workspace:^4.8.0-dev.0","@itwin/core-geometry":"workspace:^4.8.0-dev.0","@itwin/core-orbitgt":"workspace:^4.8.0-dev.0","@itwin/core-quantity":"workspace:^4.8.0-dev.0"},"//devDependencies":["NOTE: All peerDependencies should also be listed as devDependencies since peerDependencies are not considered by npm install","NOTE: All tools used by scripts in this package must be listed as devDependencies"],"devDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/build-tools":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/certa":"workspace:*","@itwin/eslint-plugin":"^4.0.2","@types/chai":"4.3.1","@types/chai-as-promised":"^7","@types/mocha":"^10.0.6","@types/sinon":"^17.0.2","babel-loader":"~8.2.5","babel-plugin-istanbul":"~6.1.1","chai":"^4.3.10","chai-as-promised":"^7.1.1","cpx2":"^3.0.0","eslint":"^8.56.0","glob":"^10.3.12","mocha":"^10.2.0","nyc":"^15.1.0","rimraf":"^3.0.2","sinon":"^17.0.1","source-map-loader":"^4.0.0","typescript":"~5.3.3","typemoq":"^2.1.0","webpack":"^5.76.0"},"//dependencies":["NOTE: these dependencies should be only for things that DO NOT APPEAR IN THE API","NOTE: core-frontend should remain UI technology agnostic, so no react/angular dependencies are allowed"],"dependencies":{"@itwin/cloud-agnostic-core":"^2.1.0","@itwin/object-storage-core":"^2.2.2","@itwin/core-i18n":"workspace:*","@itwin/core-telemetry":"workspace:*","@itwin/webgl-compatibility":"workspace:*","@loaders.gl/core":"^3.1.6","@loaders.gl/draco":"^3.1.6","fuse.js":"^3.3.0","meshoptimizer":"~0.20.0","wms-capabilities":"0.4.0"},"nyc":{"extends":"./node_modules/@itwin/build-tools/.nycrc"}}');
297379
297462
 
297380
297463
  /***/ })
297381
297464