diff --git a/.vscode/cSpell.json b/.vscode/cSpell.json index 3da55c4f8f86..23a0cb046d2d 100644 --- a/.vscode/cSpell.json +++ b/.vscode/cSpell.json @@ -120,6 +120,7 @@ "frust", "fstop", "fullwidth", + "geocoordinate", "geolocated", "geolocation", "geometry", @@ -216,6 +217,7 @@ "Nums", "oidc", "oldcolor", + "openid", "origin", "orthogonalize", "overclamped", @@ -242,8 +244,10 @@ "preallocated", "prefetch", "prerelease", + "projectwise", "pseudolocalize", "Queryable", + "rbac", "readlink", "readonly", "rebased", diff --git a/.vscode/settings.json b/.vscode/settings.json index e16b4660d32c..13a8b672de6b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -115,7 +115,8 @@ "eslint.format.enable": true, "eslint.lintTask.enable": true, "editor.codeActionsOnSave": { - "editor.action.fixAll": true, // first run the default formatter, it handles whitespace better + "source.fixAll.markdownlint": true, // first run the markdown linter + "editor.action.fixAll": true, // Run the default formatter before eslint, it handles whitespace better "source.fixAll.eslint": true // then run ESLint auto-fix } } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 571c239b36ff..b64f16be14a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,8 +30,8 @@ Before you create a new issue, please do a search in [open issues](https://githu If you find that your issue already exists, please add relevant comments and your [reaction](/~https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment: -* 👍 - upvote -* 👎 - downvote +- 👍 - upvote +- 👎 - downvote If you cannot find an existing issue that describes your bug or feature, create a new issue using the guidelines below. @@ -47,14 +47,14 @@ The more information you can provide, the more likely someone will be successful Please include the following with each issue: -* A short description of the issue that becomes the title -* Versions of relevant iModel.js packages -* Minimal steps to reproduce the issue or a code snippet that demonstrates the issue -* What you expected to see, versus what you actually saw -* Images that help explain the issue -* Any relevant error messages, logs, or other details -* Impact of the issue -* Use the [`bug`](/~https://github.com/imodeljs/imodeljs/labels/bug) or [`enhancement`](/~https://github.com/imodeljs/imodeljs/labels/enhancement) label to identify the type of issue you are filing +- A short description of the issue that becomes the title +- Versions of relevant iModel.js packages +- Minimal steps to reproduce the issue or a code snippet that demonstrates the issue +- What you expected to see, versus what you actually saw +- Images that help explain the issue +- Any relevant error messages, logs, or other details +- Impact of the issue +- Use the [`bug`](/~https://github.com/imodeljs/imodeljs/labels/bug) or [`enhancement`](/~https://github.com/imodeljs/imodeljs/labels/enhancement) label to identify the type of issue you are filing Don't feel bad if the developers can't reproduce the issue right away. They will simply ask for more information! @@ -86,10 +86,10 @@ Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for We welcome contributions, large or small, including: -* Bug fixes -* New features -* Documentation corrections or additions -* Example code snippets -* Sample data +- Bug fixes +- New features +- Documentation corrections or additions +- Example code snippets +- Sample data Thank you for taking the time to contribute to open source and making great projects like iModel.js possible! diff --git a/README.md b/README.md index 30247c6ecf76..de8e33bee504 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ Each package has its own **node_modules** directory that contains symbolic links ## Prerequisites -* [Git](https://git-scm.com/) -* [Node](https://nodejs.org/en/): an installation of the latest security patch of Node 12. The Node installation also includes the **npm** package manager. -* [Rush](/~https://github.com/Microsoft/web-build-tools/wiki/Rush): to install `npm install -g @microsoft/rush` -* [TypeScript](https://www.typescriptlang.org/): this is listed as a devDependency, so if you're building it from source, you will get it with `rush install`. -* [Visual Studio Code](https://code.visualstudio.com/): an optional dependency, but the repository structure is optimized for its use +- [Git](https://git-scm.com/) +- [Node](https://nodejs.org/en/): an installation of the latest security patch of Node 12. The Node installation also includes the **npm** package manager. +- [Rush](/~https://github.com/Microsoft/web-build-tools/wiki/Rush): to install `npm install -g @microsoft/rush` +- [TypeScript](https://www.typescriptlang.org/): this is listed as a devDependency, so if you're building it from source, you will get it with `rush install`. +- [Visual Studio Code](https://code.visualstudio.com/): an optional dependency, but the repository structure is optimized for its use > See [supported platforms](./docs/learning/SupportedPlatforms.md) for further information. diff --git a/SECURITY.md b/SECURITY.md index ff69f38e742d..d104ebe63e5b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,11 +12,11 @@ Report security concerns in third-party modules to the person or team maintainin We ask that: -* You give us reasonable time to investigate and mitigate an issue you report before making public any information about the report or sharing such information with others. -* You do not interact with an individual account (which includes modifying or accessing data from the account) if the account owner has not consented to such actions. -* You make a good faith effort to avoid privacy violations and disruptions to others, including (but not limited to) unauthorized access to or destruction of data, and interruption or degradation of our services. -* You do not exploit a security issue you discover for any reason. (This includes demonstrating additional risk, such as attempted compromise of sensitive company data or probing for additional issues.) -* You do not intentionally violate any other applicable laws or regulations, including (but not limited to) laws and regulations prohibiting the unauthorized access to data. -* For the purposes of this policy, you are not authorized to access user data or company data, including (but not limited to) personally identifiable information and data relating to an identified or identifiable natural person. +- You give us reasonable time to investigate and mitigate an issue you report before making public any information about the report or sharing such information with others. +- You do not interact with an individual account (which includes modifying or accessing data from the account) if the account owner has not consented to such actions. +- You make a good faith effort to avoid privacy violations and disruptions to others, including (but not limited to) unauthorized access to or destruction of data, and interruption or degradation of our services. +- You do not exploit a security issue you discover for any reason. (This includes demonstrating additional risk, such as attempted compromise of sensitive company data or probing for additional issues.) +- You do not intentionally violate any other applicable laws or regulations, including (but not limited to) laws and regulations prohibiting the unauthorized access to data. +- For the purposes of this policy, you are not authorized to access user data or company data, including (but not limited to) personally identifiable information and data relating to an identified or identifiable natural person. For more information, please read Bentley's [responsible disclosure](https://www.bentley.com/responsible_disclosure.pdf) guidelines. diff --git a/docs/changehistory/1.0.0.md b/docs/changehistory/1.0.0.md index 1c545bb02005..8426af1451e5 100644 --- a/docs/changehistory/1.0.0.md +++ b/docs/changehistory/1.0.0.md @@ -34,8 +34,8 @@ Here is an example of how to adjust your source code: Removed the following parameters to `IModelDb.open` to simplify the implementation: -* [OpenParams](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/openparams).pullOnly(): Use OpenParams.fixedVersion() or OpenParams.pullAndPush() -* AccessMode: Using OpenParams.fixedVersion() always causes the briefcase to be shared, and using OpenParams.pullAndPush() always causes the briefcase to be exclusive. +- [OpenParams](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/openparams).pullOnly(): Use OpenParams.fixedVersion() or OpenParams.pullAndPush() +- AccessMode: Using OpenParams.fixedVersion() always causes the briefcase to be shared, and using OpenParams.pullAndPush() always causes the briefcase to be exclusive. ## Changes to OidcAgentClient @@ -61,15 +61,15 @@ Removed or modified some properties used to feature-gate various tile-related fe Frontend: -* Removed `TileAdmin.requestTilesWithoutEdges`. Tiles are now always requested without edges if edges are not required. -* Removed `TileAdmin.elideEmptyChildContentRequests`. Such requests are now always elided. -* `TileAdmin.enableInstancing` now defaults to `true` instead of `false`. -* Previously, if `TileAdmin.retryInterval` was undefined, requests for tile content and tile tree JSON would not be memoized. Now, they are always memoized, and the interval defaults to 1000ms if not explicitly defined. -* Previously, requests for tile content would by default use POST method and responses would not be cacheable. Now by default they use GET and responses are cacheable. +- Removed `TileAdmin.requestTilesWithoutEdges`. Tiles are now always requested without edges if edges are not required. +- Removed `TileAdmin.elideEmptyChildContentRequests`. Such requests are now always elided. +- `TileAdmin.enableInstancing` now defaults to `true` instead of `false`. +- Previously, if `TileAdmin.retryInterval` was undefined, requests for tile content and tile tree JSON would not be memoized. Now, they are always memoized, and the interval defaults to 1000ms if not explicitly defined. +- Previously, requests for tile content would by default use POST method and responses would not be cacheable. Now by default they use GET and responses are cacheable. Backend: -* Removed `IModelHostConfiguration.useTileContentThreadPool`. The thread pool is now always used. +- Removed `IModelHostConfiguration.useTileContentThreadPool`. The thread pool is now always used. ## Changes to RPC type marshaling system @@ -87,30 +87,30 @@ This change breaks RPC interface [IModelReadRpcInterface](https://www.imodeljs.o Backend: -* Renamed `IModelDb.queryPage` to `IModelDb.queryRows`. This method is also marked `internal` and user should not call it directly. Instead user should always use [IModelDb.query](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/query). This method now also throw exception if query prepare fails. -* Changed method signature for [IModelDb.query](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/query). But first two parameters are same. +- Renamed `IModelDb.queryPage` to `IModelDb.queryRows`. This method is also marked `internal` and user should not call it directly. Instead user should always use [IModelDb.query](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/query). This method now also throw exception if query prepare fails. +- Changed method signature for [IModelDb.query](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/query). But first two parameters are same. Common: -* Renamed `IModelDb.queryPage` to `IModelDb.queryRows`. -* Removed `queryRowCount`method from [IModelReadRpcInterface](https://www.imodeljs.org/v1/reference/imodeljs-common/rpcinterface/imodelreadrpcinterface) +- Renamed `IModelDb.queryPage` to `IModelDb.queryRows`. +- Removed `queryRowCount`method from [IModelReadRpcInterface](https://www.imodeljs.org/v1/reference/imodeljs-common/rpcinterface/imodelreadrpcinterface) Frontend: -* Renamed `IModelConnection.queryPage` to `IModelConnection.queryRows`. This method is also marked `internal` and user should not call it directly. Instead user should always use [IModelConnection.query](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/query). This method now also throw exception if query prepare fails. -* Changed method signature for [IModelConnection.query](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/query). But first two parameters are same. +- Renamed `IModelConnection.queryPage` to `IModelConnection.queryRows`. This method is also marked `internal` and user should not call it directly. Instead user should always use [IModelConnection.query](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/query). This method now also throw exception if query prepare fails. +- Changed method signature for [IModelConnection.query](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/query). But first two parameters are same. ### How can you update code ```ts - const rows = await imodel.queryPage("SELECT ECInstanceId FROM bis.Element LIMIT 1"); +const rows = await imodel.queryPage("SELECT ECInstanceId FROM bis.Element LIMIT 1"); ``` can be be changed to following. ```ts - const rows = []; - for await (const row of imodel.query("SELECT ECInstanceId FROM bis.Element LIMIT 1")) { - rows.push(row); - } +const rows = []; +for await (const row of imodel.query("SELECT ECInstanceId FROM bis.Element LIMIT 1")) { + rows.push(row); +} ``` diff --git a/docs/changehistory/1.1.0.md b/docs/changehistory/1.1.0.md index 31fda84d356f..a7d40869d2fe 100644 --- a/docs/changehistory/1.1.0.md +++ b/docs/changehistory/1.1.0.md @@ -14,10 +14,10 @@ Please see the [TypeScript Roadmap](/~https://github.com/Microsoft/TypeScript/wiki The new `frontend-devtools` package contains a collection of simple UI widgets providing diagnostics and customization related to the display system. These include: - * `MemoryTracker` - reports on total GPU memory usage, breaking it down by different types of objects like textures and buffers. Memory can be reported for all tile trees in the system or only those currently displayed in the viewport. - * `FpsTracker` - reports average frames-per-second. Note: this forces the scene to be redrawn every frame, which may impact battery life on laptops and mobile devices. - * `TileStatisticsTracker` - reports exhaustive tile request statistics, including the current numbers of active and pending requests, the total number of completed, dispatched, failed, and timed-out requests, and more. - * `ToolSettingsTracker` - allows settings affecting the operation of viewing tools to be customized. +- `MemoryTracker` - reports on total GPU memory usage, breaking it down by different types of objects like textures and buffers. Memory can be reported for all tile trees in the system or only those currently displayed in the viewport. +- `FpsTracker` - reports average frames-per-second. Note: this forces the scene to be redrawn every frame, which may impact battery life on laptops and mobile devices. +- `TileStatisticsTracker` - reports exhaustive tile request statistics, including the current numbers of active and pending requests, the total number of completed, dispatched, failed, and timed-out requests, and more. +- `ToolSettingsTracker` - allows settings affecting the operation of viewing tools to be customized. These widgets may be used in any combination. Alternatively, `DiagnosticsPanel` bundles them all together as a set of expandable panels along with a handful of other features like freezing the current scene, controlling display of tile bounding boxes, and hiding particular types of geometry. @@ -27,51 +27,56 @@ These widgets may be used in any combination. Alternatively, `DiagnosticsPanel` Many incremental enhancements contributed to improved performance and quality of the rendering system and decreased memory usage, including: - * Reducing the number of tiles requested and expediently cancelling requests for tiles which are no longer needed. - * Improving culling logic - this particularly improves performance when a clip volume is applied to the view. - * Reclaiming memory from not-recently-drawn tiles. - * Decompressing texture images in the background using web workers. - * Eliminating distortion of text, and of the skybox in orthographic views. - * Enabling tiles to be downloaded without edge data, and optimizing shaders to more efficiently render tiles without edges. - +- Reducing the number of tiles requested and expediently cancelling requests for tiles which are no longer needed. +- Improving culling logic - this particularly improves performance when a clip volume is applied to the view. +- Reclaiming memory from not-recently-drawn tiles. +- Decompressing texture images in the background using web workers. +- Eliminating distortion of text, and of the skybox in orthographic views. +- Enabling tiles to be downloaded without edge data, and optimizing shaders to more efficiently render tiles without edges. ## Changes to handling of GUID ECProperties A [Guid](https://www.imodeljs.org/v1/reference/bentleyjs-core/ids/guid) is stored inside an [IModelDb](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb) as an ECProperty of `binary` type (a "blob" of bytes) with `extendedTypeName="BeGuid"`, but represented in Typescript as a `string`. ECSql queries must translate between these two representations. Previously, querying such a property would return a 16-byte `Uint8Array`; in iModel.js 1.1 it instead returns a `string`. The example below selects a Guid property: + ```ts - for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid IS NOT NULL")) { - // Expect row.federationGuid to be a string of the format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - } +for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid IS NOT NULL")) { + // Expect row.federationGuid to be a string of the format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +} ``` When a Guid is bound to an ECSql parameter, either the `Uint8Array` **or** the `string` representation can be supplied. In the example below, the `string` representation is supplied: + ```ts - for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = ?", ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"])) { - // ... - } +for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = ?", ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"])) { + // ... +} ``` Currently, the `string` representation **cannot** be used directly inside an ECSql statement. This will be fixed in a future version. For now, use the helper functions `GuidToStr` and `StrToGuid` to explicitly convert between binary and string: + ```ts - // WARNING: The following will not work because no implicit conversion between BINARY and STRING is performed. - for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")) { /* */ } +// WARNING: The following will not work because no implicit conversion between BINARY and STRING is performed. +for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")) { /* */ } - // This query is logically equivalent to the above, and will work as expected because the string is explicitly converted to a blob. - for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = StrToGuid('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')")) { /* */ } +// This query is logically equivalent to the above, and will work as expected because the string is explicitly converted to a blob. +for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE FederationGuid = StrToGuid('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')")) { /* */ } - // The inverse conversion can also be useful. - for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE GuidToStr(FederationGuid) = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")) { /* */ } +// The inverse conversion can also be useful. +for await (const row of conn.query("SELECT FederationGuid FROM bis.Element WHERE GuidToStr(FederationGuid) = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")) { /* */ } ``` ## ECSQL support for correlated subqueries ECSql now supports the following syntax for correlated subqueries + +```sql +[NOT] EXISTS () ``` - [NOT] EXISTS () -``` + ### Example + ```sql SELECT ECInstanceId FROM bis.Element E WHERE EXISTS ( @@ -80,27 +85,26 @@ SELECT ECInstanceId FROM bis.Element E SELECT ECInstanceId FROM bis.Element E WHERE NOT EXISTS ( SELECT 1 FROM meta.ECClassDef C WHERE C.ECInstanceId = E.ECClassId AND C.Name='Pump') - ``` ## ECSQL support for bitwise operators ECSql now supports the following bitwise operators. The operand is treated as a signed 64-bit integer. - * `~` not - * `|` or - * `&` and - * `<<` left-shift - * `>>` right-shift +- `~` not +- `|` or +- `&` and +- `<<` left-shift +- `>>` right-shift ### Example + ```sql SELECT 2 & prop FROM test.Foo WHERE prop & 2 = 2 SELECT 2 | prop FROM test.Foo WHERE prop | 2 = 2 -SELECT * FROM test.Foo WHERE (1 << 2) & prop +SELECT * FROM test.Foo WHERE (1 << 2) & prop SELECT * FROM test.Foo WHERE ~prop & 2; ``` - diff --git a/docs/changehistory/1.10.0.md b/docs/changehistory/1.10.0.md index 71edddee6616..25f2f7e07584 100644 --- a/docs/changehistory/1.10.0.md +++ b/docs/changehistory/1.10.0.md @@ -19,50 +19,49 @@ See the [iModel Transformation and Data Exchange]($docs/learning/backend/IModelT Beta support for [device pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) was introduced in v1.9.0. 1.10.0 fixes a handful of bugs associated with this feature. In particular, device pixel ratio may vary between different [Viewport](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport)s. As a result, the previously free-standing APIs have moved to the [Viewport](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport) class: -* [Viewport.devicePixelRatio](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/devicepixelratio) replaces `queryDevicePixelRatio`. -* [Viewport.cssPixelsToDevicePixels](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/csspixelstodevicepixels) replaces `cssPixelsToDevicePixels`. +- [Viewport.devicePixelRatio](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/devicepixelratio) replaces `queryDevicePixelRatio`. +- [Viewport.cssPixelsToDevicePixels](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/csspixelstodevicepixels) replaces `cssPixelsToDevicePixels`. Do not assume that `Viewport.devicePixelRatio` will always return [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio). ## Viewing tools -* New walk tool [LookAndMoveTool](https://www.imodeljs.org/v1/reference/imodeljs-frontend/tools/lookandmovetool). - * Supports mouse look and keyboard (wasd) for movement. - * Touch screen control sticks for look and move. -* Improved responsiveness when using touch controls. +- New walk tool [LookAndMoveTool](https://www.imodeljs.org/v1/reference/imodeljs-frontend/tools/lookandmovetool). + - Supports mouse look and keyboard (wasd) for movement. + - Touch screen control sticks for look and move. +- Improved responsiveness when using touch controls. ## Visualization -* Reduced CPU overhead associated with binding uniform shader program variables, resulting in up to 30% improvement in frames per second. -* Graphics for reality models and background maps load much more quickly and smoothly. +- Reduced CPU overhead associated with binding uniform shader program variables, resulting in up to 30% improvement in frames per second. +- Graphics for reality models and background maps load much more quickly and smoothly. ## Geometry ### Matrix3d inverse state bug fix -* BUG: matrix times matrix multipliers (multiplyMatrixMatrix, multiplyMatrixMatrixInverse, multiplyMatrixInverseMatrix, multiplyMatrixMatrixTranspose, multiplyMatrixTransposeMatrix) did not transfer inverse coefficient arrays into the product. -* When an existing result matrix marked "inverseStored" was supplied, the "inverseStored" marking persisted, but the product inverse coefficient matrix was not constructed -* When no result was supplied in the call, there were no problems. -* As corrected, all 5 multiplications construct inverse products when possible, and mark up appropriately. +- BUG: matrix times matrix multipliers (multiplyMatrixMatrix, multiplyMatrixMatrixInverse, multiplyMatrixInverseMatrix, multiplyMatrixMatrixTranspose, multiplyMatrixTransposeMatrix) did not transfer inverse coefficient arrays into the product. +- When an existing result matrix marked "inverseStored" was supplied, the "inverseStored" marking persisted, but the product inverse coefficient matrix was not constructed +- When no result was supplied in the call, there were no problems. +- As corrected, all 5 multiplications construct inverse products when possible, and mark up appropriately. ### `CurveCurve.intersectionPairsXY` returns details of line-line and arc-arc coincident geometry -* `CurveLocationDetail` data carrier has new optional members - * `fraction1` = fractional position for end of coincident section - * `point` = point at end of coincident section - * `detail.captureFraction1Point1 (f,xyz)` directly captures (no clone) fraction and point. - * CurveLocationDetail.createCurveEvaluatedFractionFraction` constructor with 2 fractions. - * `detail.inverseInterpolateFraction (f, defaultLocalFraction)` maps input fraction f to local fraction of the `fraction, fraction1` interval of the detail. - * `detail.swapFractionsAndPoints ()` swaps the `[fraction,point]` and `[fraction1, point1]` values (if both defined) +- `CurveLocationDetail` data carrier has new optional members + - `fraction1` = fractional position for end of coincident section + - `point` = point at end of coincident section + - `detail.captureFraction1Point1 (f,xyz)` directly captures (no clone) fraction and point. + - CurveLocationDetail.createCurveEvaluatedFractionFraction` constructor with 2 fractions. + - `detail.inverseInterpolateFraction (f, defaultLocalFraction)` maps input fraction f to local fraction of the `fraction, fraction1` interval of the detail. + - `detail.swapFractionsAndPoints ()` swaps the `[fraction,point]` and `[fraction1, point1]` values (if both defined) ### Miscellaneous -* New `Arc3d` method `arc.scaleAboutCenterInPlace (scaleFactor);` -* New `Matrix3d` method `matrixA.multiplyMatrixInverseMatrix(other: Matrix3d, result?: Matrix3d): Matrix3d | undefined` -* New `Segment1d` method `segment.clampDirectedTo01(): boolean;` - * intersect with [0,1] interval - * maintain current direction - * return false if empty after clip. - * New `Segment1d` method `segment.`reverseIfNeededForDeltaSign(sign?: number): void;` - * maintain endpoints, but reverse so direction corresponds to request. - +- New `Arc3d` method `arc.scaleAboutCenterInPlace (scaleFactor);` +- New `Matrix3d` method `matrixA.multiplyMatrixInverseMatrix(other: Matrix3d, result?: Matrix3d): Matrix3d | undefined` +- New `Segment1d` method `segment.clampDirectedTo01(): boolean;` + - intersect with [0,1] interval + - maintain current direction + - return false if empty after clip. + - New `Segment1d` method `segment.`reverseIfNeededForDeltaSign(sign?: number): void;` + - maintain endpoints, but reverse so direction corresponds to request. diff --git a/docs/changehistory/1.11.0.md b/docs/changehistory/1.11.0.md index c83868a30a96..e9552b7e6835 100644 --- a/docs/changehistory/1.11.0.md +++ b/docs/changehistory/1.11.0.md @@ -22,11 +22,13 @@ Upgrading to TypeScript 3.7.2 necessitated an upgrade to a new version of [api-e Upgrading to TypeScript 3.7.2 necessitated an upgrade to [typedoc 0.15.1](https://typedoc.org/) and v2.1.0 of the [typedoc plugin](https://www.npmjs.com/package/typedoc-plugin-external-module-name) used to support external module declarations. This changes the format of `@module` comments. Previous syntax for `@module` comments: + ```ts /** @module ModuleName */ ``` New syntax for `@module` comments: + ```ts /** @packageDocumentation * @module ModuleName @@ -37,30 +39,26 @@ Without the `@packageDocumentation`, the documentation generator will fail to re ## Geometry -* new public methods in RegionOps: - - * RegionOps.sortOuterAndHoleLoopsXY - * apply parity logic to determine containment of holes in parents (or holes in islands) - * RegionOps.constructAllXYRegionLoops - * Compute intersections among unstructured input curves - * Construct areas bounded by those inputs. - * RegionOps.curveArrayRange - * construct range of unstructured array of curves. - * RegionOps.expandLineStrings - * In an array of curve primitives, replace each LineString3d with expansion to LineSegment3d - -* (new method) CurveCurve.allIntersectionsAmongPrimitivesXY - * Supporting changes in CurveCurveIntersectionXY context class. -* CurveLocationDetail - * new method to ask if fraction1 is present (i.e. this is an interval rather than single point. -* Make implementations of CurvePrimitive and CurveCollection methods to collect leaf primitives and strokes more consistent: - - * collectCurvePrimitives method - * new optional args for (a) preallocated collector, (b) controlling expansion of CurveChainWithDistanceIndex - * public entry RegionOps.collectCurvePrimitives - * internal entries in CurveCollection, CurvePrimitive - * internal "Go" methods in: CurveChainWithDistanceIndex, - * CurveChain.cloneStroked is abstract (implemented by Path, Loop, CurveChainWithDistanceIndex -* CurveFactory - * New method to create xy rectangles with optional fillets. - +- new public methods in RegionOps: + - RegionOps.sortOuterAndHoleLoopsXY + - apply parity logic to determine containment of holes in parents (or holes in islands) + - RegionOps.constructAllXYRegionLoops + - Compute intersections among unstructured input curves + - Construct areas bounded by those inputs. + - RegionOps.curveArrayRange + - construct range of unstructured array of curves. + - RegionOps.expandLineStrings + - In an array of curve primitives, replace each LineString3d with expansion to LineSegment3d +- (new method) CurveCurve.allIntersectionsAmongPrimitivesXY + - Supporting changes in CurveCurveIntersectionXY context class. +- CurveLocationDetail + - new method to ask if fraction1 is present (i.e. this is an interval rather than single point. +- Make implementations of CurvePrimitive and CurveCollection methods to collect leaf primitives and strokes more consistent: + - collectCurvePrimitives method + - new optional args for (a) preallocated collector, (b) controlling expansion of CurveChainWithDistanceIndex + - public entry RegionOps.collectCurvePrimitives + - internal entries in CurveCollection, CurvePrimitive + - internal "Go" methods in: CurveChainWithDistanceIndex, + - CurveChain.cloneStroked is abstract (implemented by Path, Loop, CurveChainWithDistanceIndex +- CurveFactory + - New method to create xy rectangles with optional fillets. diff --git a/docs/changehistory/1.12.0.md b/docs/changehistory/1.12.0.md index 551bec4715db..a8f408df5e9b 100644 --- a/docs/changehistory/1.12.0.md +++ b/docs/changehistory/1.12.0.md @@ -11,19 +11,21 @@ MacOS support is officially available for iModel.js backends. Please see the [S ## Plan projection display Alpha support for controlling the display of "plan projection" models has been added. A plan projection model is a spatial model with geometry all residing in an XY plane, indicated by the [GeometricModel3dProps.isPlanProjection](https://www.imodeljs.org/v1/reference/imodeljs-common/entities/geometricmodel3dprops/#isplanprojection) flag. Multiple such models can be combined within a spatial view in various ways by using the `PlanProjectionSettings` associated with a [DisplayStyle3d](https://www.imodeljs.org/v1/reference/imodeljs-backend/viewdefinitions/displaystyle3d) and [DisplayStyle3dState](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystyle3dstate). This allows each model to be displayed with any of the following: - * An absolute elevation in meters; - * A uniform transparency; - * As an overlay, drawn in front of all other geometry in the view; - * Deterministic draw order based on display priority. + +- An absolute elevation in meters; +- A uniform transparency; +- As an overlay, drawn in front of all other geometry in the view; +- Deterministic draw order based on display priority. The latter groups geometry within plan projection models into "layers" based on subcategory Id: each subcategory represents a single layer containing geometry from any number of plan projection models, and each subcategory's [SubCategoryAppearance](https://www.imodeljs.org/v1/reference/imodeljs-common/symbology/subcategoryappearance) defines a display priority. At display time, if 2 (or more) plan projection models are displayed at the same elevation, their geometry is drawn in ascending order by the corresponding subcategory's display priority, such that geometry with a higher priority displays in front of geometry with a lower priority. Subcategory priorities can be overridden using [DisplayStyleSettings.overrideSubCategory](https://www.imodeljs.org/v1/reference/imodeljs-common/displaystyles/displaystylesettings/overridesubcategory). ## Feature flags Options used to enable or disable certain features when invoking [IModelApp.startup](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelapp/imodelapp/#startup) have changed: - * [RenderSystem.Options.logarithmicDepthBuffer](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rendering/rendersystem.options/logarithmicdepthbuffer) now defaults to `true`. - * `TileAdmin.Props.enableImprovedElision` now defaults to `true`. - * `TileAdmin.Props.ignoreAreaPatterns` has been added to temporarily mitigate issues with large amounts of geometry produced for area patterns. It defaults to `false`. + +- [RenderSystem.Options.logarithmicDepthBuffer](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rendering/rendersystem.options/logarithmicdepthbuffer) now defaults to `true`. +- `TileAdmin.Props.enableImprovedElision` now defaults to `true`. +- `TileAdmin.Props.ignoreAreaPatterns` has been added to temporarily mitigate issues with large amounts of geometry produced for area patterns. It defaults to `false`. ## View details @@ -32,102 +34,114 @@ Access to optional [ViewDefinition](https://www.imodeljs.org/v1/reference/imodel ## UI ### ControlledTree - * New abstract classes: `AbstractTreeNodeLoader` and `AbstractTreeNodeLoaderWitProvider` - * Uses `TreeModelSource` to add loaded nodes to the model - * `protected abstract load(parentId: TreeModelNode | TreeModelRootNode, childIndex: number): Observable` is called to load nodes - * `protected updateModel(loadedHierarchy: LoadedNodeHierarchy): void` is called when nodes are loaded and is responsible for adding them to the model - * `onNodeLoaded` event removed from `ITreeNodeLoader` - * `AbstractTreeNodeLoader.updateModel(loadedHierarchy: LoadedNodeHierarchy): void` should be overridden instead of listening for `onNodeLoaded` event - * `TreeNodeLoader` and `PagedTreeNodeLoader` extends `AbstractTreeNodeLoaderWitProvider` and requires `TreeModelSource` to be passed to constructor - * overriding `protected updateModel(loadedHierarchy: LoadedNodeHierarchy): void` allows to control how nodes are added to the model. - * `useNodeLoader` and `usePagedNodeLoader` hooks require `TreeModelSource` - * `function useNodeLoader(dataProvider: TDataProvider, modelSource: TreeModelSource): TreeNodeLoader;` - * `function usePagedNodeLoader(dataProvider: TDataProvider, pageSize: number, modelSource: TreeModelSource): PagedTreeNodeLoader;` - * `useModelSource` hook takes `TreeDataProvider` instead of `ITreeNodeLoader` - * `function useModelSource(dataProvider: TreeDataProvider): TreeModelSource;` - * Removed function: `createDefaultNodeLoadHandler(modelSource: TreeModelSource): (loadedHierarchy: LoadedNodeHierarchy) => void;` - * Removed function: `createModelSourceForNodeLoader(nodeLoader: ITreeNodeLoader): { modelSource: TreeModelSource; disposeModelSource: () => void; };` + +- New abstract classes: `AbstractTreeNodeLoader` and `AbstractTreeNodeLoaderWitProvider` + - Uses `TreeModelSource` to add loaded nodes to the model + - `protected abstract load(parentId: TreeModelNode | TreeModelRootNode, childIndex: number): Observable` is called to load nodes + - `protected updateModel(loadedHierarchy: LoadedNodeHierarchy): void` is called when nodes are loaded and is responsible for adding them to the model +- `onNodeLoaded` event removed from `ITreeNodeLoader` + - `AbstractTreeNodeLoader.updateModel(loadedHierarchy: LoadedNodeHierarchy): void` should be overridden instead of listening for `onNodeLoaded` event +- `TreeNodeLoader` and `PagedTreeNodeLoader` extends `AbstractTreeNodeLoaderWitProvider` and requires `TreeModelSource` to be passed to constructor + - overriding `protected updateModel(loadedHierarchy: LoadedNodeHierarchy): void` allows to control how nodes are added to the model. +- `useNodeLoader` and `usePagedNodeLoader` hooks require `TreeModelSource` + - `function useNodeLoader(dataProvider: TDataProvider, modelSource: TreeModelSource): TreeNodeLoader;` + - `function usePagedNodeLoader(dataProvider: TDataProvider, pageSize: number, modelSource: TreeModelSource): PagedTreeNodeLoader;` +- `useModelSource` hook takes `TreeDataProvider` instead of `ITreeNodeLoader` + - `function useModelSource(dataProvider: TreeDataProvider): TreeModelSource;` +- Removed function: `createDefaultNodeLoadHandler(modelSource: TreeModelSource): (loadedHierarchy: LoadedNodeHierarchy) => void;` +- Removed function: `createModelSourceForNodeLoader(nodeLoader: ITreeNodeLoader): { modelSource: TreeModelSource; disposeModelSource: () => void; };` ## Geometry ### Ellipsoid - * New instance method: `ellipsoid.localToWorld(localPoint: XYAndZ, result?: Point3d): Point3d` - * New instance method: `worldToLocal(worldPoint: XYAndZ, result?: Point3d): Point3d | undefined` - * `local` image of a world point is in the coordinate system of a unit sphere. - * The point is (inside,on,outside) the ellipsoid if its local point magnitude (distance from local origin) is respectively (less than, equal to, greater than) one. -* New instance method: `ellipsoid.silhouette (eyePoint:Point4d): Arc3d | undefined` -* New instance methods to implement the `Clipper` interface: - * `ellipsoid.isPointOnOrInside(point: Point3d): boolean` - * `ellipsoid.announceClippedArcIntervals(arc: Arc3d, announce?: AnnounceNumberNumberCurvePrimitive): boolean` - * `ellipsoid.announceClippedSegmentIntervals(f0: number, f1: number, pointA: Point3d, pointB: Point3d, announce?: AnnounceNumberNumber): boolean` + +- New instance method: `ellipsoid.localToWorld(localPoint: XYAndZ, result?: Point3d): Point3d` +- New instance method: `worldToLocal(worldPoint: XYAndZ, result?: Point3d): Point3d | undefined` +- `local` image of a world point is in the coordinate system of a unit sphere. + - The point is (inside,on,outside) the ellipsoid if its local point magnitude (distance from local origin) is respectively (less than, equal to, greater than) one. +- New instance method: `ellipsoid.silhouette (eyePoint:Point4d): Arc3d | undefined` +- New instance methods to implement the `Clipper` interface: + - `ellipsoid.isPointOnOrInside(point: Point3d): boolean` + - `ellipsoid.announceClippedArcIntervals(arc: Arc3d, announce?: AnnounceNumberNumberCurvePrimitive): boolean` + - `ellipsoid.announceClippedSegmentIntervals(f0: number, f1: number, pointA: Point3d, pointB: Point3d, announce?: AnnounceNumberNumber): boolean` ### PolyfaceQuery - * Existing static methods for area booleans of polygons have added (optional) argument to request triangulation of results. - * `polygonXYAreaUnionLoopsToPolyface` - * `polygonXYAreaDifferenceLoopsToPolyface` - * `polygonXYAreaIntersectLoopsToPolyface` - * New (static) method: `cloneByFacetDuplication(source: Polyface, includeSingletons: boolean, clusterSelector: DuplicateFacetClusterSelector): Polyface` - * Copy facets from source to a new polyface - * `includeSingletons` controls inclusion of facets that appear only once - * `clusterSelector` indicates - * omit all duplicated facets - * include single representative among each cluster of duplicates - * omit all if even count, retain one if odd count. (Parity rules) - * include all within clusters of duplicates - * supporting methods to announce and collect arrays of clustered facet indices: - * `PolyfaceQuery.announceDuplicateFacetIndices(polyface: Polyface, announceCluster: (clusterFacetIndices: number[]) => void): void` - * `PolyfaceQuery.collectDuplicateFacetIndices(polyface: Polyface, includeSingletons?: boolean): number[][]` - - ### Arc3d - * Allow undefined center in create methods - * `Arc3d.create(center: Point3d | undefined, vector0: Vector3d, vector90: Vector3d, sweep?: AngleSweep, result?: Arc3d): Arc3d;` - * `Arc3d.createCenterNormalRadius(center: Point3d | undefined, normal: Vector3d, radius: number, result?: Arc3d): Arc3d;` - * `Arc3d.createScaledXYColumns(center: Point3d | undefined, matrix: Matrix3d, radius0: number, radius90: number, sweep?: AngleSweep, result?: Arc3d): Arc3d;` - * in `myArc.extendRange(range, transform)`, compute exact (rather than sampled) range. + +- Existing static methods for area booleans of polygons have added (optional) argument to request triangulation of results. + - `polygonXYAreaUnionLoopsToPolyface` + - `polygonXYAreaDifferenceLoopsToPolyface` + - `polygonXYAreaIntersectLoopsToPolyface` +- New (static) method: `cloneByFacetDuplication(source: Polyface, includeSingletons: boolean, clusterSelector: DuplicateFacetClusterSelector): Polyface` + - Copy facets from source to a new polyface + - `includeSingletons` controls inclusion of facets that appear only once + - `clusterSelector` indicates + - omit all duplicated facets + - include single representative among each cluster of duplicates + - omit all if even count, retain one if odd count. (Parity rules) + - include all within clusters of duplicates + - supporting methods to announce and collect arrays of clustered facet indices: + - `PolyfaceQuery.announceDuplicateFacetIndices(polyface: Polyface, announceCluster: (clusterFacetIndices: number[]) => void): void` + - `PolyfaceQuery.collectDuplicateFacetIndices(polyface: Polyface, includeSingletons?: boolean): number[][]` + +### Arc3d + +- Allow undefined center in create methods + - `Arc3d.create(center: Point3d | undefined, vector0: Vector3d, vector90: Vector3d, sweep?: AngleSweep, result?: Arc3d): Arc3d;` + - `Arc3d.createCenterNormalRadius(center: Point3d | undefined, normal: Vector3d, radius: number, result?: Arc3d): Arc3d;` +- `Arc3d.createScaledXYColumns(center: Point3d | undefined, matrix: Matrix3d, radius0: number, radius90: number, sweep?: AngleSweep, result?: Arc3d): Arc3d;` +- in `myArc.extendRange(range, transform)`, compute exact (rather than sampled) range. ### Matrix3d - * New instance method: `matrix.multiplyInverseXYZW(x: number, y: number, z: number, w: number, result?: Point4d): Point4d | undefined;` + +- New instance method: `matrix.multiplyInverseXYZW(x: number, y: number, z: number, w: number, result?: Point4d): Point4d | undefined;` ### Point4d - * New instance method: `point4d.crossWeightedMinusPoint3d(other: Point3d, result?: Vector3d): Vector3d;` - * New instance method: `point4d.realPointOrVector (): Point3d | Vector3d;` + +- New instance method: `point4d.crossWeightedMinusPoint3d(other: Point3d, result?: Vector3d): Vector3d;` +- New instance method: `point4d.realPointOrVector (): Point3d | Vector3d;` ### Vector3d - * New static method: `Vector3d.dotProductAsXYAndZ(dataA: XYAndZ, dataB: XYAndZ): number` - * dot product between x,y,z components of `dataA` and `dataB`, even if strong typing (e.g. as Point3d) says they should not be able to act as vectors. + +- New static method: `Vector3d.dotProductAsXYAndZ(dataA: XYAndZ, dataB: XYAndZ): number` + - dot product between x,y,z components of `dataA` and `dataB`, even if strong typing (e.g. as Point3d) says they should not be able to act as vectors. ### Transform - * New instance method: `multiplyInversePoint4d(weightedPoint: Point4d, result?: Point4d): Point4d | undefined;` + +- New instance method: `multiplyInversePoint4d(weightedPoint: Point4d, result?: Point4d): Point4d | undefined;` ### Point3d and Vector3d - * New instance method `data.setAt(index, value)` to address x,y,z by index (in `XYZ` base class) + +- New instance method `data.setAt(index, value)` to address x,y,z by index (in `XYZ` base class) ### ConvexClipPlaneSet - * allow undefined (zero) tilt in construction `ConvexClipPlaneSet.createSweptPolyline(points: Point3d[], upVector: Vector3d, tiltAngle?: Angle): ConvexClipPlaneSet | undefined` + +- allow undefined (zero) tilt in construction `ConvexClipPlaneSet.createSweptPolyline(points: Point3d[], upVector: Vector3d, tiltAngle?: Angle): ConvexClipPlaneSet | undefined` ### MomentData - * (BUG) in `MomentData.inertiaProductsToPrincipalAxes(rawMomentData.origin, rawMomentData.sums)`, when the computed quantity (e.g. area) is negative, adjust axes directions to have the loop be CCW in the `localToWorldMap` xy plane. - * New optional property `absoluteQuantity` is - * `undefined` in raw moment data - * the (positive) quantity sum in principal moment data (produced by call to `inertiaProductsToPrincipalAxes`) + +- (BUG) in `MomentData.inertiaProductsToPrincipalAxes(rawMomentData.origin, rawMomentData.sums)`, when the computed quantity (e.g. area) is negative, adjust axes directions to have the loop be CCW in the `localToWorldMap` xy plane. +- New optional property `absoluteQuantity` is + - `undefined` in raw moment data + - the (positive) quantity sum in principal moment data (produced by call to `inertiaProductsToPrincipalAxes`) ### `Clipper` support - * new static method `ClipUtilities.isClipper(candidate: any)` to test if candidate supports all the methods of the Clipper interface. - * new (static) methods in `BooleanClipFactory`. The static list (including some older methods) is - * JSON serialization: - * BooleanClipFactory.anyClipperToJSON(clipper: any): any | undefined; - * BooleanClipFactory.parseToClipper(source?: object): Clipper | undefined; - * `create` methods for various boolean trees: - * `BooleanClipFactory.createCaptureClipOutside(primaryClipper: Clipper): Clipper;` - * `BooleanClipFactory.createCaptureDifference(primaryClipper: Clipper, excludedClipper: Clipper, keepInside: boolean): Clipper;` - * `BooleanClipFactory.createCaptureIntersection(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` - * `BooleanClipFactory.createCaptureParity(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` - * `BooleanClipFactory.createCaptureUnion(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` + +- new static method `ClipUtilities.isClipper(candidate: any)` to test if candidate supports all the methods of the Clipper interface. +- new (static) methods in `BooleanClipFactory`. The static list (including some older methods) is + - JSON serialization: + - BooleanClipFactory.anyClipperToJSON(clipper: any): any | undefined; + - BooleanClipFactory.parseToClipper(source?: object): Clipper | undefined; + - `create` methods for various boolean trees: + - `BooleanClipFactory.createCaptureClipOutside(primaryClipper: Clipper): Clipper;` + - `BooleanClipFactory.createCaptureDifference(primaryClipper: Clipper, excludedClipper: Clipper, keepInside: boolean): Clipper;` + - `BooleanClipFactory.createCaptureIntersection(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` + - `BooleanClipFactory.createCaptureParity(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` + - `BooleanClipFactory.createCaptureUnion(clippers: Clipper | Clipper[], keepInside: boolean): Clipper;` ## IModelSchemaLoader - * New utility class in @bentley/imodeljs-backend to retrieve full Schema information from an iModel. - * Requires the @bentley/ecschema-metadata package to be installed. This package contains the EC Schema metadata classes which are the building blocks of the schema returned from the iModel. - * Contains two methods for Schema retrieval. - * `getSchema` Gets a Schema by name from the iModel and throws an exception if it cannot be found or loaded. - * `tryGetSchema` Attempts to retrieve a Schema by name from the iModel. Returns `undefined` if it cannot be found. +- New utility class in @bentley/imodeljs-backend to retrieve full Schema information from an iModel. +- Requires the @bentley/ecschema-metadata package to be installed. This package contains the EC Schema metadata classes which are the building blocks of the schema returned from the iModel. +- Contains two methods for Schema retrieval. + - `getSchema` Gets a Schema by name from the iModel and throws an exception if it cannot be found or loaded. + - `tryGetSchema` Attempts to retrieve a Schema by name from the iModel. Returns `undefined` if it cannot be found. diff --git a/docs/changehistory/1.2.0.md b/docs/changehistory/1.2.0.md index 5dc9b86d5cc3..b868138fbc47 100644 --- a/docs/changehistory/1.2.0.md +++ b/docs/changehistory/1.2.0.md @@ -10,12 +10,12 @@ Markers are used to position decorations in a view that follow a position in wor ## Updates to authorization -* [OidcBrowserClient](https://www.imodeljs.org/v1/reference/imodeljs-frontend/oidc/oidcbrowserclient /) now uses local storage instead of session storage to store access tokens. The state of the authorization would therefore now be preserved if the browser was closed and reopened. +- [OidcBrowserClient](https://www.imodeljs.org/v1/reference/imodeljs-frontend/oidc/oidcbrowserclient) now uses local storage instead of session storage to store access tokens. The state of the authorization would therefore now be preserved if the browser was closed and reopened. **Note**: The browser setting to clear local storage on exit must not be enabled. -* [OidcBrowserClient](https://www.imodeljs.org/v1/reference/imodeljs-frontend/oidc/oidcbrowserclient/) can now be used in authorization code workflows. A new responseType parameter can be set to "code" to support these workflows. This also requires a new client to be registered. +- [OidcBrowserClient](https://www.imodeljs.org/v1/reference/imodeljs-frontend/oidc/oidcbrowserclient/) can now be used in authorization code workflows. A new responseType parameter can be set to "code" to support these workflows. This also requires a new client to be registered. -* [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient) is now available as beta (it was marked internal earlier). Using the client requires an Agent registration and potential changes to the Connect Project settings - see more documentation in [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient). +- [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient) is now available as beta (it was marked internal earlier). Using the client requires an Agent registration and potential changes to the Connect Project settings - see more documentation in [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient). ## Support for vertex array objects @@ -23,11 +23,11 @@ On systems that support the [required WebGL extension](https://developer.mozilla ## Display system bug fixes -* Fixed two bugs in which [Viewport.changeCategoryDisplay](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/changecategorydisplay) and [Viewport.addViewedModels](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/addviewedmodels) would sometimes fail to immediately update the contents of the viewport. +- Fixed two bugs in which [Viewport.changeCategoryDisplay](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/changecategorydisplay) and [Viewport.addViewedModels](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport/addviewedmodels) would sometimes fail to immediately update the contents of the viewport. -* Fixed a regression that prevented the tiles comprising the background map from being reprojected using the the geocoordinate system defined in the iModel, causing the map graphics to be incorrectly aligned with the model geometry. +- Fixed a regression that prevented the tiles comprising the background map from being reprojected using the the geocoordinate system defined in the iModel, causing the map graphics to be incorrectly aligned with the model geometry. -* Fixed the behavior of the "Data Attribution" link that, when clicked, displays copyright information for map tiles displayed in the view. Previously it would always open an empty modal dialog. Now, if any copyright information is available, it will be correctly displayed in the dialog; otherwise, a toast message will be displayed indicating the unavailability of attribution. +- Fixed the behavior of the "Data Attribution" link that, when clicked, displays copyright information for map tiles displayed in the view. Previously it would always open an empty modal dialog. Now, if any copyright information is available, it will be correctly displayed in the dialog; otherwise, a toast message will be displayed indicating the unavailability of attribution. ## Option to discard ImageBuffer alpha channel @@ -35,11 +35,11 @@ Functions for converting the contents of an [ImageBuffer](https://www.imodeljs.o ## Enhancements to IModelDb.exportGraphics -* [IModelDb.exportGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportgraphics) can now optionally return information about [GeometryPart](https://www.imodeljs.org/v1/reference/imodeljs-backend/elements/geometrypart) instances encountered in a [GeometryStreamProps](https://www.imodeljs.org/v1/reference/imodeljs-common/geometry/geometrystreamprops). [IModelDb.exportPartGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportpartgraphics) can then be used to handle this information in a more efficient manner. +- [IModelDb.exportGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportgraphics) can now optionally return information about [GeometryPart](https://www.imodeljs.org/v1/reference/imodeljs-backend/elements/geometrypart) instances encountered in a [GeometryStreamProps](https://www.imodeljs.org/v1/reference/imodeljs-common/geometry/geometrystreamprops). [IModelDb.exportPartGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportpartgraphics) can then be used to handle this information in a more efficient manner. -* [IModelDb.exportGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportgraphics) can now optionally return information about linework (or "open") geometry encountered in a GeometryStream. +- [IModelDb.exportGraphics](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/imodeldb/exportgraphics) can now optionally return information about linework (or "open") geometry encountered in a GeometryStream. -* An example GLTF 2.0 exporter demonstrating these features is now available under test-apps in the iModel.js monorepo. +- An example GLTF 2.0 exporter demonstrating these features is now available under test-apps in the iModel.js monorepo. ## Added a roadmap @@ -47,17 +47,17 @@ Functions for converting the contents of an [ImageBuffer](https://www.imodeljs.o ## Geometry -* Various new methods for manipulating polygons and curves - * [RegionOps.computeXYAreaMoments](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#computexyareamoments) - * [RegionOps.constructPolygonWireXYOffset](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#constructpolygonwirexyoffset) - * [PolylineOps.compressByChordError](https://www.imodeljs.org/v1/reference/geometry-core/cartesiangeometry/polylineops/#compressbychorderror) - * [CurveCurve.intersectionXYZ](https://www.imodeljs.org/v1/reference/geometry-core/curve/curvecurve/#intersectionxyz) -* Correct stroking of [BezierCurve3d](https://www.imodeljs.org/v1/reference/geometry-core/bspline/beziercurve3d) +- Various new methods for manipulating polygons and curves + - [RegionOps.computeXYAreaMoments](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#computexyareamoments) + - [RegionOps.constructPolygonWireXYOffset](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#constructpolygonwirexyoffset) + - [PolylineOps.compressByChordError](https://www.imodeljs.org/v1/reference/geometry-core/cartesiangeometry/polylineops/#compressbychorderror) + - [CurveCurve.intersectionXYZ](https://www.imodeljs.org/v1/reference/geometry-core/curve/curvecurve/#intersectionxyz) +- Correct stroking of [BezierCurve3d](https://www.imodeljs.org/v1/reference/geometry-core/bspline/beziercurve3d) ## iModel UI Enhancements -* UI Items now support badging with BetaBadge. Applications can now specify an image to overlay on an item to highlight it. For example, early release tools can be marked with a badge to indicate their beta state. +- UI Items now support badging with BetaBadge. Applications can now specify an image to overlay on an item to highlight it. For example, early release tools can be marked with a badge to indicate their beta state. -* The 9-zone UI now supports an external set of Stage Panels. These panels can be used to move high-density widgets out of the area shared by the graphical viewport for ease of use. The Stage Panels feature is part of the ui-ninezone package and is in preview. +- The 9-zone UI now supports an external set of Stage Panels. These panels can be used to move high-density widgets out of the area shared by the graphical viewport for ease of use. The Stage Panels feature is part of the ui-ninezone package and is in preview. -* Applications can now serialize and deserialize the layout and content of the ContentView using the SaveViewLayout class. The SavedView and SavedViewLayout classes are in preview. +- Applications can now serialize and deserialize the layout and content of the ContentView using the SaveViewLayout class. The SavedView and SavedViewLayout classes are in preview. diff --git a/docs/changehistory/1.3.0.md b/docs/changehistory/1.3.0.md index 6a7ac73df597..32555088c8eb 100644 --- a/docs/changehistory/1.3.0.md +++ b/docs/changehistory/1.3.0.md @@ -14,10 +14,10 @@ version: '1.3.0' The background map is typically drawn behind all other geometry. This can be disorienting when viewing geometry that should be located below the ground. Now, the map can be rendered with depth, so that underground geometry is not visible when looking down at the map; or with transparency, so that underground geometry is only partially visible beneath the map. Additionally, the map can be draped onto real-world terrain meshes obtained from the [Cesium World Terrain](https://cesium.com/content/) service. All of these settings can be controlled by modifying the [BackgroundMapSettings](https://www.imodeljs.org/v1/reference/imodeljs-common/displaystyles/backgroundmapsettings) associated with a [DisplayStyleState](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystylestate). -* Top-left: Ordinary background map -* Top-right: Background map with depth -* Bottom-left: Background map with transparency -* Bottom-right: Background map with terrain +- Top-left: Ordinary background map +- Top-right: Background map with depth +- Bottom-left: Background map with transparency +- Bottom-right: Background map with terrain ![background map](./assets/map.png "Different ways of rendering the background map") @@ -45,91 +45,90 @@ Shadows can now be displayed in 3d views. The implementation uses exponential va ## Geometry -* Summary: - * Triangulate cut faces in polyface clip. - * Variant point data parse. - * Bilinear Patch ray intersection - * polyline small feature filtering - * compute WireMoment on curves - * compute volume moments on meshes. - -* When clipping a polyface with a plane, new method optionally outputs triangulation of the cut plane face. - * (static) `clipPolyfaceClipPlaneWithClosureFace(polyface: Polyface, clipper: ClipPlane, insideClip?: boolean, buildClosureFace?: boolean): Polyface;` -* Methods that support points loosely structured as type MultiLineStringDataVariant - * Many point variants are parsed: - * point as Point3d - * point as [1,2,3] - * point as {x:1, y:2, z:3} - * Array [] of any of the above - * GrowableXYZArray with points packed (x,y,z, x,y,z, x,y,z, ...) - * Methods to convert the variant structures to specific preferred types: - * (static) `GrowableXYZArray.createArrayOfGrowableXYZArrayFromVariantData (data: MultiLineStringDataVariant): GrowableXYZArray[];` - * Return array of GrowableXYZArray. - * (static) `LineString3d.createArrayOfLineString3dFromVariantData (data: MultiLineStringDataVariant): LineString3d[];` - * (static) `Range3d.createFromVariantData(data: MultiLineStringDataVariant):Range3d` - * (static) `Point3dArray.convertVariantDataToDeepXYZNumberArrays(data: MultiLineStringDataVariant): any[];` - * (static) `Point3dArray.convertVariantDataToDeepXYZNumberArrays(data: MultiLineStringDataVariant): any[];` -* (static) `FrameBuilder.createFrameWithCCWPolygon (points: Point3d[])` - * Create a transform in the plane of points. - * flip Z directed so the polygon has CCW orientation. -* (static) `orientLoopsCCWForOutwardNormalInPlace(loops: GrowableXYZArray | GrowableXYZArray[], outwardNormal: Vector3d): number` - * reverse order of loops (individually, no hole analysis) so all are CCW orientation for given outward normal. - * Return number reversed. -* `Arc3d` methods - * (static) `Arc3d.cloneAtZ(z?: number): Arc3d` +- Summary: + - Triangulate cut faces in polyface clip. + - Variant point data parse. + - Bilinear Patch ray intersection + - polyline small feature filtering + - compute WireMoment on curves + - compute volume moments on meshes. + +- When clipping a polyface with a plane, new method optionally outputs triangulation of the cut plane face. + - (static) `clipPolyfaceClipPlaneWithClosureFace(polyface: Polyface, clipper: ClipPlane, insideClip?: boolean, buildClosureFace?: boolean): Polyface;` +- Methods that support points loosely structured as type MultiLineStringDataVariant + - Many point variants are parsed: + - point as Point3d + - point as [1,2,3] + - point as {x:1, y:2, z:3} + - Array [] of any of the above + - GrowableXYZArray with points packed (x,y,z, x,y,z, x,y,z, ...) + - Methods to convert the variant structures to specific preferred types: + - (static) `GrowableXYZArray.createArrayOfGrowableXYZArrayFromVariantData (data: MultiLineStringDataVariant): GrowableXYZArray[];` + - Return array of GrowableXYZArray. + - (static) `LineString3d.createArrayOfLineString3dFromVariantData (data: MultiLineStringDataVariant): LineString3d[];` + - (static) `Range3d.createFromVariantData(data: MultiLineStringDataVariant):Range3d` + - (static) `Point3dArray.convertVariantDataToDeepXYZNumberArrays(data: MultiLineStringDataVariant): any[];` + - (static) `Point3dArray.convertVariantDataToDeepXYZNumberArrays(data: MultiLineStringDataVariant): any[];` +- (static) `FrameBuilder.createFrameWithCCWPolygon (points: Point3d[])` + - Create a transform in the plane of points. + - flip Z directed so the polygon has CCW orientation. +- (static) `orientLoopsCCWForOutwardNormalInPlace(loops: GrowableXYZArray | GrowableXYZArray[], outwardNormal: Vector3d): number` + - reverse order of loops (individually, no hole analysis) so all are CCW orientation for given outward normal. + - Return number reversed. +- `Arc3d` methods + - (static) `Arc3d.cloneAtZ(z?: number): Arc3d` Return projection to plane at `z` - * (static) `Arc3d.createXYZXYZXYZ(cx: number, cy: number, cz: number, ux: number, uy: number, uz: number, vx: number, vy: number, vz: number, sweep?: * AngleSweep, result?: Arc3d): Arc3d;` - * create an arc with center, vector to 0 degree point, and vector to 90 degree point. - * (static) `Arc3d.fractionAndRadialFractionToPoint(arcFraction: number, radialFraction: number, result?: Point3d): Point3d;` - * evaluate a point at fraction position "along" the arc and at multiple of the radius. -* `GrowableXYZArray` instance methods to access individual x,y,z by point index without creating Point3d object: - * `myGrowableXYZArray.getXAtUncheckedPointIndex (pointIndex: number) : number;` - * `myGrowableXYZArray.getYAtUncheckedPointIndex (pointIndex: number) : number;` - * `myGrowableXYZArray.getZAtUncheckedPointIndex (pointIndex: number) : number;` - * `myGrowableXYZArray.length` - * `GrowableXYZArray.moveIndexToIndex (fromIndex, toIndex)` -* `ParityRegion` methods to facilitate adding or creating with (strongly typed) loop objects - * For both `create` or `add`, data presented as possibly deep arrays of arrays of loops is flattened to the ParityRegion form of a single array of Loops. - * `(static) createLoops(data?: Loop | Loop[] | Loop[][]): Loop | ParityRegion;` - * Note that in the single-loop case this returns a Loop object rather than ParityRegion. - * `myParityRegion.addLoops(data?: Loop | Loop[] | Loop[][]): void;` -* `BilinearPatch` methods - * Method to compute points of intersection with a ray: - * intersectRay(ray: Ray3d): CurveAndSurfaceLocationDetail[] | undefined; -* `LineString3d` methods - * method to create capture a GrowableXYZArray as the packed points of a LineString3d: - * (static) `createCapture(points: GrowableXYZArray): LineString3d;` -* `NumberArray` methods - * In existing static method `NumberArray.maxAbsDiff`, allow both `number[]` and `Float64Array`, viz - * (static) `NumberArray.maxAbsDiff(dataA: number[] | Float64Array, dataB: number[] | Float64Array): number;` -* `PolyfaceBuilder` methods - * convert a single loop polygon to triangulated facets. - * (static) `PolyfaceBuilder.polygonToTriangulatedPolyface(points: Point3d[], localToWorld?: Transform): IndexedPolyface | undefined;` -* `SweepContour` methods - * (static) `SweepContour.createForPolygon(points: MultiLineStringDataVariant, defaultNormal?: Vector3d): SweepContour | undefined;` -* `Range3d` methods - * Existing methods with input type `Point3d[]` allow `GrowableXYZArray` with packed x,y,z content - * (static) `Range3d.createInverseTransformedArray(transform: Transform, points: Point3d[] | GrowableXYZArray): T;` - * (static) `Range3d.createTransformedArray(transform: Transform, points: Point3d[] | GrowableXYZArray): T;` -* `XYZ` methods (become visible in both Point3d and Vector3d) - * `myPoint.subtractInPlace (vector: XYAndZ); -* Numerics - * Gaussian elimination step for inplace updated of subset of a row `rowB[i] += a * rowA[i]` for `i > pivotIndex` - * Solve up to 4 roots of a pair of bilinear equations - * (static) `solveBilinearPair(a0: number, b0: number, c0: number, d0: number, a1: number, b1: number, c1: number, d1: number): Point2d[] | undefined;` -* `PolylineOps` new methods - * (static) `PolylineOps.compressByPerpendicularDistance(source: Point3d[], maxDistance: number, numPass?: number): Point3d[]` - * (static) `PolylineOps,compressShortEdges(source: Point3d[], maxEdgeLength: number): Point3d[]]` - * (static) `PolylineOps.compressSmallTriangles(source: Point3d[], maxTriangleArea: number): Point3d[]` -* `RegionOps` new methods - * (static) `RegionOps.computeXYZWireMomentSums(root: AnyCurve): MomentData | undefined` - * (static) `RegionOps.constructCurveXYOffset(curves: Path | Loop, offsetDistanceOrOptions: number | JointOptions): CurveCollection | undefined;` - * Create a path or loop offset by distance (positive to left) - * (static) `RegionOps.createLoopPathOrBagOfCurves(curves: CurvePrimitive[], wrap?: boolean): CurveCollection | undefined;` - * Create a curve structure, choosing type `Loop`, `Path`, or `BagOfCurves` appropriate to how the inputs join. -* `PolyfaceQuery` new methods - * (static) `momentData = computePrincipalVolumeMoments(source: Polyface): MomentData | undefined` - * Returns momentData structure with centroid, volume, radii of gyration. - * (static) `static boundaryEdges(source: Polyface, includeDanglers: boolean = true, includeMismatch: boolean = true, includeNull: boolean = true): CurveCollection | undefined` - * Within a polyface, find edges that have unusual adjacency and hence qualify as "boundary" edges. - + - (static) `Arc3d.createXYZXYZXYZ(cx: number, cy: number, cz: number, ux: number, uy: number, uz: number, vx: number, vy: number, vz: number, sweep?: * AngleSweep, result?: Arc3d): Arc3d;` + - create an arc with center, vector to 0 degree point, and vector to 90 degree point. + - (static) `Arc3d.fractionAndRadialFractionToPoint(arcFraction: number, radialFraction: number, result?: Point3d): Point3d;` + - evaluate a point at fraction position "along" the arc and at multiple of the radius. +- `GrowableXYZArray` instance methods to access individual x,y,z by point index without creating Point3d object: + - `myGrowableXYZArray.getXAtUncheckedPointIndex (pointIndex: number) : number;` + - `myGrowableXYZArray.getYAtUncheckedPointIndex (pointIndex: number) : number;` + - `myGrowableXYZArray.getZAtUncheckedPointIndex (pointIndex: number) : number;` + - `myGrowableXYZArray.length` + - `GrowableXYZArray.moveIndexToIndex (fromIndex, toIndex)` +- `ParityRegion` methods to facilitate adding or creating with (strongly typed) loop objects + - For both `create` or `add`, data presented as possibly deep arrays of arrays of loops is flattened to the ParityRegion form of a single array of Loops. + - `(static) createLoops(data?: Loop | Loop[] | Loop[][]): Loop | ParityRegion;` + - Note that in the single-loop case this returns a Loop object rather than ParityRegion. + - `myParityRegion.addLoops(data?: Loop | Loop[] | Loop[][]): void;` +- `BilinearPatch` methods + - Method to compute points of intersection with a ray: + - intersectRay(ray: Ray3d): CurveAndSurfaceLocationDetail[] | undefined; +- `LineString3d` methods + - method to create capture a GrowableXYZArray as the packed points of a LineString3d: + - (static) `createCapture(points: GrowableXYZArray): LineString3d;` +- `NumberArray` methods + - In existing static method `NumberArray.maxAbsDiff`, allow both `number[]` and `Float64Array`, viz + - (static) `NumberArray.maxAbsDiff(dataA: number[] | Float64Array, dataB: number[] | Float64Array): number;` +- `PolyfaceBuilder` methods + - convert a single loop polygon to triangulated facets. + - (static) `PolyfaceBuilder.polygonToTriangulatedPolyface(points: Point3d[], localToWorld?: Transform): IndexedPolyface | undefined;` +- `SweepContour` methods + - (static) `SweepContour.createForPolygon(points: MultiLineStringDataVariant, defaultNormal?: Vector3d): SweepContour | undefined;` +- `Range3d` methods + - Existing methods with input type `Point3d[]` allow `GrowableXYZArray` with packed x,y,z content + - (static) `Range3d.createInverseTransformedArray(transform: Transform, points: Point3d[] | GrowableXYZArray): T;` + - (static) `Range3d.createTransformedArray(transform: Transform, points: Point3d[] | GrowableXYZArray): T;` +- `XYZ` methods (become visible in both Point3d and Vector3d) + - `myPoint.subtractInPlace (vector: XYAndZ); +- Numerics + - Gaussian elimination step for inplace updated of subset of a row `rowB[i] += a - rowA[i]` for `i > pivotIndex` + - Solve up to 4 roots of a pair of bilinear equations + - (static) `solveBilinearPair(a0: number, b0: number, c0: number, d0: number, a1: number, b1: number, c1: number, d1: number): Point2d[] | undefined;` +- `PolylineOps` new methods + - (static) `PolylineOps.compressByPerpendicularDistance(source: Point3d[], maxDistance: number, numPass?: number): Point3d[]` + - (static) `PolylineOps,compressShortEdges(source: Point3d[], maxEdgeLength: number): Point3d[]]` + - (static) `PolylineOps.compressSmallTriangles(source: Point3d[], maxTriangleArea: number): Point3d[]` +- `RegionOps` new methods + - (static) `RegionOps.computeXYZWireMomentSums(root: AnyCurve): MomentData | undefined` + - (static) `RegionOps.constructCurveXYOffset(curves: Path | Loop, offsetDistanceOrOptions: number | JointOptions): CurveCollection | undefined;` + - Create a path or loop offset by distance (positive to left) + - (static) `RegionOps.createLoopPathOrBagOfCurves(curves: CurvePrimitive[], wrap?: boolean): CurveCollection | undefined;` + - Create a curve structure, choosing type `Loop`, `Path`, or `BagOfCurves` appropriate to how the inputs join. +- `PolyfaceQuery` new methods + - (static) `momentData = computePrincipalVolumeMoments(source: Polyface): MomentData | undefined` + - Returns momentData structure with centroid, volume, radii of gyration. + - (static) `static boundaryEdges(source: Polyface, includeDanglers: boolean = true, includeMismatch: boolean = true, includeNull: boolean = true): CurveCollection | undefined` + - Within a polyface, find edges that have unusual adjacency and hence qualify as "boundary" edges. diff --git a/docs/changehistory/1.4.0.md b/docs/changehistory/1.4.0.md index 1a53df0cf3b5..47c2c39d116d 100644 --- a/docs/changehistory/1.4.0.md +++ b/docs/changehistory/1.4.0.md @@ -7,56 +7,60 @@ version: '1.4.0' ## Geometry ### Summary - * New class `CurveFactory` to hold future static methods that construct multi-component curves. - * First method: CurveFactory.createFilletsInLineString - * `PolyfaceBuilder` static method to build xy triangulation of array of points. - * `PolyfaceClip` static method to compute cut-fill between 2.5D meshes. + +- New class `CurveFactory` to hold future static methods that construct multi-component curves. + - First method: CurveFactory.createFilletsInLineString +- `PolyfaceBuilder` static method to build xy triangulation of array of points. +- `PolyfaceClip` static method to compute cut-fill between 2.5D meshes. + ### Details - * `Arc3d` - * (static) `Arc3d.createFilletArc(point0: Point3d, point1: Point3d, point2: Point3d, radius: number): ArcBlendData;` - * Create (if possible) a single arc that is a fillet between line segment from `point0` to `point` and `point1` to `point`. - * Annotated return with fractional position of tangent, fractions from middle point outward along segments. - * `point1` (middle points) is commonly called the PI (point of inflection) for the linestring being filleted. - * See new support interface `ArcBlendData` - * `CurveFactory` - * (static) `CurveFactory.createFilletsInLineString(points: LineString3d | IndexedXYZCollection | Point3d[], radius: number, allowBackupAlongEdge?: boolean): Path | undefined;` - * Create a path with alternating lines and tangent arcs. - * `CurveCollection` - * (static) `static createCurveLocationDetailOnAnyCurvePrimitive(source: GeometryQuery | undefined, fraction?: number): CurveLocationDetail | undefined;` - * Find any curve primitive in the collection. Evaluate it at a fractional position. - * `CurveCurve` - * (static) `CurveCurve.intersectionXYPairs(geometryA: GeometryQuery, extendA: boolean, geometryB: GeometryQuery, extendB: boolean): CurveLocationDetailPair[]` - * Same as existing (deprecated) `CurveCurve.intersectionXY`, but bundles pairs of `CurveLocationDetailPair` in single array more useful for processing. - * `Point3dArray` - * (static) `Point3dArray.static computeConvexHullXY(points: Point3d[], hullPoints: Point3d[], insidePoints: Point3d[], addClosurePoint?: boolean): void;` - * Return `hullPoints` in CCW order around the hull - * Return all non-hull points in `insidePoints` - * `PolyfaceBuilder` - * (static) `PolyfaceBuilder.pointsToTriangulatedPolyface(points: Point3d[]): IndexedPolyface | undefined;` - * Return triangulated mesh within the convex hull around the points. - * `PolyfaceClip` - * (static) - * `ClipPlane` and `ConvexClipPlaneSet` support - * `myClipPlane.convexPolygonSplitInsideOutsideGrowableArrays(xyz: GrowableXYZArray, xyzIn: GrowableXYZArray, xyzOut: GrowableXYZArray, altitudeRange: Range1d): void;` - * Split a polygon across a plane; optimized for `GrowableXYZArray` storage. - * (static) `ClipPlane.createNormalAndPointXYZXYZ(normalX: number, normalY: number, normalZ: number, originX: number, originY: number, originZ: number, invisible?: boolean, interior?: boolean, result?: ClipPlane): ClipPlane | undefined;` - * (preexisting) added optional `result` parameter - * `Ray3d` - * `interval = myRay.intersectionWithRange3d(range: Range3d, result?: Range1d): Range1d` - * return fractions (along the ray `myRay`) where the `myRay` enters and exits a `Range3d`, or null `Range1d` if no in intersection. + +- `Arc3d` + - (static) `Arc3d.createFilletArc(point0: Point3d, point1: Point3d, point2: Point3d, radius: number): ArcBlendData;` + - Create (if possible) a single arc that is a fillet between line segment from `point0` to `point` and `point1` to `point`. + - Annotated return with fractional position of tangent, fractions from middle point outward along segments. + - `point1` (middle points) is commonly called the PI (point of inflection) for the linestring being filleted. + - See new support interface `ArcBlendData` +- `CurveFactory` + - (static) `CurveFactory.createFilletsInLineString(points: LineString3d | IndexedXYZCollection | Point3d[], radius: number, allowBackupAlongEdge?: boolean): Path | undefined;` + - Create a path with alternating lines and tangent arcs. +- `CurveCollection` + - (static) `static createCurveLocationDetailOnAnyCurvePrimitive(source: GeometryQuery | undefined, fraction?: number): CurveLocationDetail | undefined;` + - Find any curve primitive in the collection. Evaluate it at a fractional position. +- `CurveCurve` + - (static) `CurveCurve.intersectionXYPairs(geometryA: GeometryQuery, extendA: boolean, geometryB: GeometryQuery, extendB: boolean): CurveLocationDetailPair[]` + - Same as existing (deprecated) `CurveCurve.intersectionXY`, but bundles pairs of `CurveLocationDetailPair` in single array more useful for processing. +- `Point3dArray` + - (static) `Point3dArray.static computeConvexHullXY(points: Point3d[], hullPoints: Point3d[], insidePoints: Point3d[], addClosurePoint?: boolean): void;` + - Return `hullPoints` in CCW order around the hull + - Return all non-hull points in `insidePoints` +- `PolyfaceBuilder` + - (static) `PolyfaceBuilder.pointsToTriangulatedPolyface(points: Point3d[]): IndexedPolyface | undefined;` + - Return triangulated mesh within the convex hull around the points. +- `PolyfaceClip` + - (static) +- `ClipPlane` and `ConvexClipPlaneSet` support + - `myClipPlane.convexPolygonSplitInsideOutsideGrowableArrays(xyz: GrowableXYZArray, xyzIn: GrowableXYZArray, xyzOut: GrowableXYZArray, altitudeRange: Range1d): void;` + - Split a polygon across a plane; optimized for `GrowableXYZArray` storage. + - (static) `ClipPlane.createNormalAndPointXYZXYZ(normalX: number, normalY: number, normalZ: number, originX: number, originY: number, originZ: number, invisible?: boolean, interior?: boolean, result?: ClipPlane): ClipPlane | undefined;` + - (preexisting) added optional `result` parameter +- `Ray3d` + - `interval = myRay.intersectionWithRange3d(range: Range3d, result?: Range1d): Range1d` + - return fractions (along the ray `myRay`) where the `myRay` enters and exits a `Range3d`, or null `Range1d` if no in intersection. ## Enhancements to IModelDb.exportGraphics - * IModelDb.exportGraphics and associated functions are now out of beta and tagged as public. - * Added [ExportGraphicsOptions.minBRepFeatureSize](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/exportgraphicsoptions/minbrepfeaturesize) to improve performance when exporting graphics for breps. +- IModelDb.exportGraphics and associated functions are now out of beta and tagged as public. +- Added [ExportGraphicsOptions.minBRepFeatureSize](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodels/exportgraphicsoptions/minbrepfeaturesize) to improve performance when exporting graphics for breps. ## Authorization Changes ### Changes to Agent authorization [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient) now implements [IAuthorizationClient](https://www.imodeljs.org/v1/reference/imodeljs-clients/authentication/iauthorizationclient). The following methods are now marked deprecated - -* [AgentAuthorizationClient.getToken](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient/gettoken) -* [AgentAuthorizationClient.refreshToken](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient/refreshtoken) + +- [AgentAuthorizationClient.getToken](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient/gettoken) +- [AgentAuthorizationClient.refreshToken](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient/refreshtoken) The access token is now stored in the client, and can be accessed by calling [AgentAuthorizationClient.getAccessToken](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient/getaccesstoken). This method validates and refreshes the token as necessary. @@ -65,4 +69,3 @@ validates and refreshes the token as necessary. The API now allows swapping the authorization client used for backend operations like downloading a briefcase or change sets of an iModel. Set [IModelHost.authorizationClient](https://www.imodeljs.org/v1/reference/imodeljs-backend/imodelhost/imodelhost/authorizationclient) to the required authorization client - e.g., an instance of [OidcAgentClient](https://www.imodeljs.org/v1/reference/imodeljs-clients-backend/authentication/oidcagentclient). - diff --git a/docs/changehistory/1.5.0.md b/docs/changehistory/1.5.0.md index 40f315c3e8ea..1ac19e71d2ff 100644 --- a/docs/changehistory/1.5.0.md +++ b/docs/changehistory/1.5.0.md @@ -6,46 +6,46 @@ version: '1.5.0' ## Upgrade to TypeScript 3.6.2 -* This version now uses TypeScript version 3.6.2. It is recommended that consumers of iModel.js packages upgrade to that version too. +- This version now uses TypeScript version 3.6.2. It is recommended that consumers of iModel.js packages upgrade to that version too. ## Display system enhancements ### Performance enhancements -* Made display system enhancement for rendering directly to screen. This significantly improves performance on iOS and some non-Chrome browsers. For models that aren't bound by primitive count, this can be a more than doubling of FPS. - * To enable this enhancement, see `RenderSystem.Options.directScreenRendering`. +- Made display system enhancement for rendering directly to screen. This significantly improves performance on iOS and some non-Chrome browsers. For models that aren't bound by primitive count, this can be a more than doubling of FPS. + - To enable this enhancement, see `RenderSystem.Options.directScreenRendering`. ## Blank IModelConnections -* The new method `IModelConnection.createBlank` provides a way for applications to create an `IModelConnection` that is not connected to an iModel or a backend. This is useful for using iModel.js to show *just* Reality data (reality meshes, point clouds, terrain, etc.), background maps, and other non-iModel-based graphics without requiring a backend server. -* There is also a new convenience method [SpatialViewState.createBlank](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/#createblank) to create a *blank* spatial view appropriate for these non-iModel based visualizations. See the [Blank Connection]($docs/learning/frontend/BlankConnection.md) learning article for further details. +- The new method `IModelConnection.createBlank` provides a way for applications to create an `IModelConnection` that is not connected to an iModel or a backend. This is useful for using iModel.js to show *just* Reality data (reality meshes, point clouds, terrain, etc.), background maps, and other non-iModel-based graphics without requiring a backend server. +- There is also a new convenience method [SpatialViewState.createBlank](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelconnection/imodelconnection/#createblank) to create a *blank* spatial view appropriate for these non-iModel based visualizations. See the [Blank Connection]($docs/learning/frontend/BlankConnection.md) learning article for further details. ## Favorite Properties ### Summary -* Favorite properties manager stores favorite properties and determines whether a given field should be displayed as favorite. -* `PresentationPropertyDataProvider` puts all favorite properties into an additional 'Favorite' category that's displayed +- Favorite properties manager stores favorite properties and determines whether a given field should be displayed as favorite. +- `PresentationPropertyDataProvider` puts all favorite properties into an additional 'Favorite' category that's displayed at the top and is auto-expanded. ### Details -* `FavoritePropertyManager` (accessed through singleton `Presentation.favoriteProperties`) in `@bentley/presentation-frontend` - * `add(field: Field): void` - * For `PropertiesField` and `NestedContentField` - marks all properties in the field as favorite. - * For other types of fields - marks the field as favorite by its name. - * `remove(field: Field): void` - * For `PropertiesField` and `NestedContentField` - removes all properties in the field from favorites list. - * For other types of fields - removes the field from favorites list. - * `has(field: Field): boolean` - * For `PropertiesField` and `NestedContentField` - returns true if field contains at least one favorite property. - * For other types of fields - returns true if field's name is in the favorites list. - * `onFavoritesChanged: BeEvent<() => void>` - * Event that's raised when favorite properties change. - -* `ContentDataProvider` (base of `PresentationPropertyDataProvider` and `PresentationTableDataProvider`) in `@bentley/presentation-components` - * `getFieldByPropertyRecord(propertyRecord: PropertyRecord): Promise` - * Returns a field object that was used to create the given `PropertyRecord`. The field contains meta-data about the properties whose values are stored in the `PropertyRecord`. +- `FavoritePropertyManager` (accessed through singleton `Presentation.favoriteProperties`) in `@bentley/presentation-frontend` + - `add(field: Field): void` + - For `PropertiesField` and `NestedContentField` - marks all properties in the field as favorite. + - For other types of fields - marks the field as favorite by its name. + - `remove(field: Field): void` + - For `PropertiesField` and `NestedContentField` - removes all properties in the field from favorites list. + - For other types of fields - removes the field from favorites list. + - `has(field: Field): boolean` + - For `PropertiesField` and `NestedContentField` - returns true if field contains at least one favorite property. + - For other types of fields - returns true if field's name is in the favorites list. + - `onFavoritesChanged: BeEvent<() => void>` + - Event that's raised when favorite properties change. + +- `ContentDataProvider` (base of `PresentationPropertyDataProvider` and `PresentationTableDataProvider`) in `@bentley/presentation-components` + - `getFieldByPropertyRecord(propertyRecord: PropertyRecord): Promise` + - Returns a field object that was used to create the given `PropertyRecord`. The field contains meta-data about the properties whose values are stored in the `PropertyRecord`. ### Usage example @@ -91,35 +91,35 @@ private async buildContextMenu(args: PropertyGridContextMenuArgs) { ### Summary -* PolyfaceQuery method to partition by connectivity -* Optimize triangle flipping -* `PolyfaceQuery.cutFill` uses GriddedRaggedRange2dSet (rather than prior `LinearSearchRange2dGrid`) +- PolyfaceQuery method to partition by connectivity +- Optimize triangle flipping +- `PolyfaceQuery.cutFill` uses GriddedRaggedRange2dSet (rather than prior `LinearSearchRange2dGrid`) ### Details -* `PolyfaceQuery` methods - * (static) `PolyfaceQuery.partitionFacetIndicesByEdgeConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` - * Return arrays of facet indices - * Within each array, each facet has an edge in common with others in the same array. - * (static) `PolyfaceQuery.partitionFacetIndicesByVertexConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` - * Return arrays of facet indices - * Within each array, each facet has (at least) a vertex in common with others in the same array. - * (static) `PolyfaceQuery.clonePartitions(polyface: Polyface | PolyfaceVisitor, partitions: number[][]): Polyface[]` - * Return an array of polyfaces - * Each polyface has all the facets from one of the input facet index arrays. - * `PolyfaceVisitor` - * `myVisitor.setNumWrap (numWrap: number)` - * set numWrap for subsequent visits. - * `PolyfaceBuilder` - * `myBuilder.reversed: boolean` - * read property to query the state controlled by `myBuilder.toggleReversedFlag` - * Carry `twoSided` flag through polyface builder actions. - * `PolyfaceQuery` - * (static) `PolyfaceQuery.partitionFacetIndicesByVertexConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` - * `UnionFindContext` - * New class to implement the UnionFind algorithm on a set of integers. - * Classes for 2d range searching. - * `RangeLengthData, UsageSums` -- carrier interface for computing average range sizes. - * `LinearSearchRange2dArray` -- array of Range2d for linear search. - * `GriddedRaggedRange2dSet` -- grid of LinearSearchRange2dArray - * `GriddedRaggedRange2dSetWithOverflow` -- GriddedRaggedRange2dSet for typical ranges, `LinearSearchRange2dArray` for larger overflow ranges. +- `PolyfaceQuery` methods + - (static) `PolyfaceQuery.partitionFacetIndicesByEdgeConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` + - Return arrays of facet indices + - Within each array, each facet has an edge in common with others in the same array. + - (static) `PolyfaceQuery.partitionFacetIndicesByVertexConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` + - Return arrays of facet indices + - Within each array, each facet has (at least) a vertex in common with others in the same array. + - (static) `PolyfaceQuery.clonePartitions(polyface: Polyface | PolyfaceVisitor, partitions: number[][]): Polyface[]` + - Return an array of polyfaces + - Each polyface has all the facets from one of the input facet index arrays. + - `PolyfaceVisitor` + - `myVisitor.setNumWrap (numWrap: number)` + - set numWrap for subsequent visits. + - `PolyfaceBuilder` + - `myBuilder.reversed: boolean` + - read property to query the state controlled by `myBuilder.toggleReversedFlag` + - Carry `twoSided` flag through polyface builder actions. + - `PolyfaceQuery` + - (static) `PolyfaceQuery.partitionFacetIndicesByVertexConnectedComponent(polyface: Polyface | PolyfaceVisitor): number[][]` + - `UnionFindContext` + - New class to implement the UnionFind algorithm on a set of integers. + - Classes for 2d range searching. + - `RangeLengthData, UsageSums` -- carrier interface for computing average range sizes. + - `LinearSearchRange2dArray` -- array of Range2d for linear search. + - `GriddedRaggedRange2dSet` -- grid of LinearSearchRange2dArray + - `GriddedRaggedRange2dSetWithOverflow` -- GriddedRaggedRange2dSet for typical ranges, `LinearSearchRange2dArray` for larger overflow ranges. diff --git a/docs/changehistory/1.6.0.md b/docs/changehistory/1.6.0.md index 3cf402dd1f70..41a657e5eb6b 100644 --- a/docs/changehistory/1.6.0.md +++ b/docs/changehistory/1.6.0.md @@ -12,7 +12,6 @@ The [Hilite](https://www.imodeljs.org/v1/reference/imodeljs-common/rendering/hil ## Geometry -* [PolyfaceBuilder.addGreedyTriangulationBetweenLineStrings](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacebuilder/addgreedytriangulationbetweenlinestrings) method to build triangles "between" loosely related linestrings. -* [RegionOps.consolidateAdjacentPrimitives](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#consolidateadjacentprimitives) method to consolidate adjacent lines and linestrings, and adjacent arcs of the same underlying circle or ellipse. -* [RegionOps.rectangleEdgeTransform](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#rectangleedgetransform) method to decide if a Loop object or point array is a simple rectangle. - +- [PolyfaceBuilder.addGreedyTriangulationBetweenLineStrings](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacebuilder/addgreedytriangulationbetweenlinestrings) method to build triangles "between" loosely related linestrings. +- [RegionOps.consolidateAdjacentPrimitives](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#consolidateadjacentprimitives) method to consolidate adjacent lines and linestrings, and adjacent arcs of the same underlying circle or ellipse. +- [RegionOps.rectangleEdgeTransform](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#rectangleedgetransform) method to decide if a Loop object or point array is a simple rectangle. diff --git a/docs/changehistory/1.7.0.md b/docs/changehistory/1.7.0.md index 372bb9063a27..49579b31dfcd 100644 --- a/docs/changehistory/1.7.0.md +++ b/docs/changehistory/1.7.0.md @@ -7,10 +7,11 @@ version: '1.7.0' ## Improvements to solar shadows Several enhancements were made to the display of `SolarShadows`: -* The shadow map now continuously refines as new geometry is loaded. -* The position of the solar light is now synchronized with sun direction. See [DisplayStyle3dState.sunDirection](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystyle3dstate/sundirection). -* World decorations no longer receive shadows. -* A display style can now configure whether or not transparent surfaces cast shadows. Any surface whose transparency is greater than the transparency threshold defined by the [DisplayStyle3dState](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystyle3dstate) will not cast shadows. See [HiddenLine.Settings.transparencyThreshold](https://www.imodeljs.org/v1/reference/imodeljs-common/displaystyles/hiddenline/hiddenline.settings/transparencythreshold). + +- The shadow map now continuously refines as new geometry is loaded. +- The position of the solar light is now synchronized with sun direction. See [DisplayStyle3dState.sunDirection](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystyle3dstate/sundirection). +- World decorations no longer receive shadows. +- A display style can now configure whether or not transparent surfaces cast shadows. Any surface whose transparency is greater than the transparency threshold defined by the [DisplayStyle3dState](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/displaystyle3dstate) will not cast shadows. See [HiddenLine.Settings.transparencyThreshold](https://www.imodeljs.org/v1/reference/imodeljs-common/displaystyles/hiddenline/hiddenline.settings/transparencythreshold). ![shadows transparency](./assets/shadows_transparency.png "Using transparency threshold to control how solar shadows interact with transparent surfaces.")

Solar shadows interacting with transparent surfaces

@@ -21,18 +22,18 @@ All [RenderGraphic](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rend ## Spatial classification improvements -* Volume classification is now fully supported. -* Flash and hilite effects are now applied correctly. -* Planar classifiers now support transparency; the classified geometry will use the transparency specified by the classifier geometry. -* Classification of point clouds now works properly. -* Classification now works correctly in perspective views. +- Volume classification is now fully supported. +- Flash and hilite effects are now applied correctly. +- Planar classifiers now support transparency; the classified geometry will use the transparency specified by the classifier geometry. +- Classification of point clouds now works properly. +- Classification now works correctly in perspective views. ## Display system startup options The following changes have been made to the [RenderSystem.Options](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rendering/rendersystem.options) used to initialize the [RenderSystem](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rendering/rendersystem) when invoking [IModelApp.startup](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelapp/imodelapp/#startup): -* `displaySolarShadows` now defaults to `true` if not defined, instead of false. -* `directScreenRendering` has been deprecated; it no longer has any effect. +- `displaySolarShadows` now defaults to `true` if not defined, instead of false. +- `directScreenRendering` has been deprecated; it no longer has any effect. ## Improvements to ambient occlusion @@ -40,18 +41,18 @@ The default settings for ambient occlusion have been changed to make the effect ## Geometry -* [PolyfaceBuilder.addGreedyTriangulationBetweenLineStrings](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacebuilder/addgreedytriangulationbetweenlinestrings) method to build triangles "between" loosely related linestrings. -* [RegionOps.consolidateAdjacentPrimitives](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#consolidateadjacentprimitives) method to consolidate adjacent lines and linestrings, and adjacent arcs of the same underlying circle or ellipse. -* [RegionOps.rectangleEdgeTransform](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#rectangleedgetransform) method to decide if a Loop object or point array is a simple rectangle. -* [Range2d.corners3d](https://www.imodeljs.org/v1/reference/geometry-core/cartesiangeometry/range2d/corners3d) method to get a `Point3d[]` containing the range corners. -* [GrowableXYArray.length](https://www.imodeljs.org/v1/reference/geometry-core/arraysandinterfaces/growablexyarray/length) property is writable (e.g. to trim the array) -* [IndexedXYZCollection.getRange](https://www.imodeljs.org/v1/reference/geometry-core/arraysandinterfaces/indexedxyzcollection/#getrange) -- return the range of data in the collection. -* Support methods for using `PolyfaceVisitor` as staging area for new facets to be given to a `PolyfaceBuilder` - * [PolyfaceVisitor.clearArrays](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/cleararrays) -- empty all arrays - * [PolyfaceVisitor.pushDataFrom](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/#pushdatafrom) -- add new point, param, normal, color from indexed position in another `PolyfaceVisitor` -* [PolyfaceVisitor.pushInterpolatedDataFrom](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/pushinterpolateddatafrom) -- add new point, param, normal, color interpolated between two indexed positions in another `PolyfaceVisitor` -* `[PolyfaceQuery.cloneWithTVertexFixup](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacequery/#clonewithcolinearedgefixup) -- clone a polyface, inserting vertices within edges that are incident to points on other facets. -* `[PolyfaceQuery.cloneWithColinearEdgeFixup](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacequery/#clonewithcolinearedgefixup) -- clone a polyface, removing mid-edge vertices that are interior to adjacent colinear edges and are _not_ used as non-colinear vertex on any other facet. +- [PolyfaceBuilder.addGreedyTriangulationBetweenLineStrings](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacebuilder/addgreedytriangulationbetweenlinestrings) method to build triangles "between" loosely related linestrings. +- [RegionOps.consolidateAdjacentPrimitives](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#consolidateadjacentprimitives) method to consolidate adjacent lines and linestrings, and adjacent arcs of the same underlying circle or ellipse. +- [RegionOps.rectangleEdgeTransform](https://www.imodeljs.org/v1/reference/geometry-core/curve/regionops/#rectangleedgetransform) method to decide if a Loop object or point array is a simple rectangle. +- [Range2d.corners3d](https://www.imodeljs.org/v1/reference/geometry-core/cartesiangeometry/range2d/corners3d) method to get a `Point3d[]` containing the range corners. +- [GrowableXYArray.length](https://www.imodeljs.org/v1/reference/geometry-core/arraysandinterfaces/growablexyarray/length) property is writable (e.g. to trim the array) +- [IndexedXYZCollection.getRange](https://www.imodeljs.org/v1/reference/geometry-core/arraysandinterfaces/indexedxyzcollection/#getrange) -- return the range of data in the collection. +- Support methods for using `PolyfaceVisitor` as staging area for new facets to be given to a `PolyfaceBuilder` + - [PolyfaceVisitor.clearArrays](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/cleararrays) -- empty all arrays + - [PolyfaceVisitor.pushDataFrom](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/#pushdatafrom) -- add new point, param, normal, color from indexed position in another `PolyfaceVisitor` +- [PolyfaceVisitor.pushInterpolatedDataFrom](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacevisitor/pushinterpolateddatafrom) -- add new point, param, normal, color interpolated between two indexed positions in another `PolyfaceVisitor` +- `[PolyfaceQuery.cloneWithTVertexFixup](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacequery/#clonewithcolinearedgefixup) -- clone a polyface, inserting vertices within edges that are incident to points on other facets. +- `[PolyfaceQuery.cloneWithColinearEdgeFixup](https://www.imodeljs.org/v1/reference/geometry-core/polyface/polyfacequery/#clonewithcolinearedgefixup) -- clone a polyface, removing mid-edge vertices that are interior to adjacent colinear edges and are _not_ used as non-colinear vertex on any other facet. ## Presentation diff --git a/docs/changehistory/1.8.0.md b/docs/changehistory/1.8.0.md index c94decce025a..cd930e29aefe 100644 --- a/docs/changehistory/1.8.0.md +++ b/docs/changehistory/1.8.0.md @@ -33,8 +33,8 @@ Added new view cursors for rotate, look, walk, and zoom view tools. Viewing tools that require identification of an object to define the point the tool will operate about now provide better feedback for the current cursor location. -* The 3d rotate view tool now shows a preview of the point it will rotate about. -* Pan, zoom, and scroll view tools now show a preview of the depth point used when the camera is on. +- The 3d rotate view tool now shows a preview of the point it will rotate about. +- Pan, zoom, and scroll view tools now show a preview of the depth point used when the camera is on. ![depth point preview](./assets/depth_point_preview.png "Rotate point preview: 1) Cursor over sky 2) Cursor over element 3) Cursor over terrain")

Rotate view tool showing rotate point used for various cursor locations

@@ -46,6 +46,7 @@ Viewing tools that require identification of an object to define the point the t ## Removal of `EntityProps` String Indexer In prior releases, the `EntityProps` interface implemented by most types that represent data inside an iModel exposed an [indexer](https://basarat.gitbooks.io/typescript/docs/types/index-signatures.html) declared as follows: + ```ts export interface EntityProps { [propName: string]: any; @@ -53,28 +54,30 @@ export interface EntityProps { ``` The dubious motivation was to enable access to arbitrary properties known to exist on some sub-type of `EntityProps` without requiring a cast. This was problematic for a number of reasons: -* If the object was *not* in fact of the expected sub-type, the property might not exist. -* Even if the expected property did in fact exist, the compiler could not catch typos in the property name. -* It disabled *all* type-checking on *all* properties of *all* sub-types of `EntityProps` - even those explicitly defined. + +- If the object was *not* in fact of the expected sub-type, the property might not exist. +- Even if the expected property did in fact exist, the compiler could not catch typos in the property name. +- It disabled *all* type-checking on *all* properties of *all* sub-types of `EntityProps` - even those explicitly defined. That final problem defeats the entire purpose of using TypeScript instead of JavaScript - it essentially forces the compiler to accept any expression `myEntity.anythingAtAll` and to consider it to have any type at all. -To prevent bugs resulting from this complete lack of type-safety, the indexer has been removed (and as a result, several existing bugs were exposed). The onus is now on the user of `EntityProps` to accomodate the type checker. Required changes may involve, in order of preference: -* Using explicit types such that no casts are required; or -* Casting to a known type that defines the properties of interest (e.g., `myEntity as ElementProps`); or -* Casting to `any` to bypass the type system entirely. +To prevent bugs resulting from this complete lack of type-safety, the indexer has been removed (and as a result, several existing bugs were exposed). The onus is now on the user of `EntityProps` to accommodate the type checker. Required changes may involve, in order of preference: + +- Using explicit types such that no casts are required; or +- Casting to a known type that defines the properties of interest (e.g., `myEntity as ElementProps`); or +- Casting to `any` to bypass the type system entirely. ## Geometry PolyfaceQuery methods to support edge visibility markup. -* PolyfaceQuery.setSingleEdgeVisibility (polyface, facetIndex, vertexIndex, value) - * within indicated facet, mark visibility of edge that starts with indicated vertexIndex -* PolyfaceQuery.markPairedEdgesInvisible (polyface, sharpEdgeAngle?) - * Mark all unpaired edges visible - * Also marked paired edges with large angle across the edge visible. - * mark all other paired edges invisible -* PolyfaceQuery.computeFacetUnitNormal (visitor, facetIndex, result?): Vector3d | undefined - * move the visitor to the indicated facet and compute a unit normal with `PolygonOps.unitNormal` -* PolyfaceQuery.markAllEdgeVisibility (mesh, value : boolean) - * mark all edges of all facets visible (true) or invisible (false) +- PolyfaceQuery.setSingleEdgeVisibility (polyface, facetIndex, vertexIndex, value) + - within indicated facet, mark visibility of edge that starts with indicated vertexIndex +- PolyfaceQuery.markPairedEdgesInvisible (polyface, sharpEdgeAngle?) + - Mark all unpaired edges visible + - Also marked paired edges with large angle across the edge visible. + - mark all other paired edges invisible +- PolyfaceQuery.computeFacetUnitNormal (visitor, facetIndex, result?): Vector3d | undefined + - move the visitor to the indicated facet and compute a unit normal with `PolygonOps.unitNormal` +- PolyfaceQuery.markAllEdgeVisibility (mesh, value : boolean) + - mark all edges of all facets visible (true) or invisible (false) diff --git a/docs/changehistory/1.9.0.md b/docs/changehistory/1.9.0.md index afdb73273cf8..116d7861f1e2 100644 --- a/docs/changehistory/1.9.0.md +++ b/docs/changehistory/1.9.0.md @@ -6,19 +6,20 @@ version: '1.9.0' ## Upgrade to Electron 6.1.5 -* iModel.js has moved up to Electron version 6.1.5 from the previous version of 4.1.0. +- iModel.js has moved up to Electron version 6.1.5 from the previous version of 4.1.0. ## Added Tween library -* iModel.js now incorporates (a copy of) the tweening library from [tween.js](/~https://github.com/tweenjs/tween.js). +- iModel.js now incorporates (a copy of) the tweening library from [tween.js](/~https://github.com/tweenjs/tween.js). ## High-DPI display support The renderer now takes into account the [device pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) ("DPI") of the display by adjusting [Viewport](https://www.imodeljs.org/v1/reference/imodeljs-frontend/views/viewport) resolution to match screen resolution, including any scaling applied by the operating system or browser. This corrects issues like blurriness on high-DPI retina displays. This behavior is enabled by default; to disable it, set [RenderSystem.Options.dpiAwareViewports](https://www.imodeljs.org/v1/reference/imodeljs-frontend/rendering/rendersystem.options/dpiawareviewports) to `false` when initializing the [IModelApp](https://www.imodeljs.org/v1/reference/imodeljs-frontend/imodelapp/imodelapp). All APIs continue to specify pixel-valued *inputs* as CSS pixels. However, APIs that read and **return** pixel values now do so in **device** pixels. The following new APIs can help when dealing with this discrepancy: -* `queryDevicePixelRatio` to obtain the device pixel ratio; and -* `cssPixelsToDevicePixels` to convert from CSS pixels to device pixels. + +- `queryDevicePixelRatio` to obtain the device pixel ratio; and +- `cssPixelsToDevicePixels` to convert from CSS pixels to device pixels. The primary affected API is [Viewport.readPixels]($frontend). Below is an example of how to correctly account for DPI scale when using that function: @@ -50,29 +51,30 @@ function isElementDrawnInRect(vp: Viewport, rect: ViewRect, elementId: Id64Strin ## Geometry ### `Ellipsoid` and `EllipsoidPatch` classes -* Range, ray intersection, and project-point-to-surface for Ellipsoid with patch limits -* `LongitudeLatitudeNumber` class to carry position and altitude + +- Range, ray intersection, and project-point-to-surface for Ellipsoid with patch limits +- `LongitudeLatitudeNumber` class to carry position and altitude ### Miscellaneous -* `AngleSweep` class options for considering period shifts, added as optional args in - * static `AngleSweep.isRadiansInStartEnd(radians: number, radians0: number, radians1: number, allowPeriodShift?: boolean): boolean;` - * instance method `mySweep.isRadiansInSweep` optional arg for periodic shift. -* `Angle` instance property `isNorthOrSouthPole` -* static `NumberArray.createArrayWithMaxStepSize(low: number, high: number, step: number): number[];` - * new method, returns array of numbers with (max) step size between low and high -* `Plane3dByOriginAndVectors` instance methods for extracting normalized directions - * instance method `myPlane.normalizeInPlace (): boolean` to normalize the vectors. - * instance method `myPlane.toRigidFrame` to extract local normalized frame - * instance method `myPlane.unitNormal` to extract unit normal - * instance method `myPlane.unitNormalRay` to extract perpendicular ray - * apply `Vector3d` instance method `normalizeInPlace()` to both `vectorU` and `vectorV` of the plane -* `Range3d` class methods - * instance method `myRange.extendSingleAxis(a: number, axisIndex: AxisIndex): void;` - * branch to one of `extendXOnly`, `extendYOnly`, `extendZOnly` -* `Ray3d` class methods - * instance method `myRay.cloneInverseTransformed(transform: Transform): Ray3d | undefined;` - * multiply by inverse of a transform and return the modified ray -* `Transform` class methods - * static `createRigidFromOriginAndColumns(origin: XYZ | undefined, vectorX: Vector3d, vectorY: Vector3d, axisOrder: AxisOrder, result?: Transform): Transform | undefined; - * Careful logic to avoid object allocation when reusing result. +- `AngleSweep` class options for considering period shifts, added as optional args in + - static `AngleSweep.isRadiansInStartEnd(radians: number, radians0: number, radians1: number, allowPeriodShift?: boolean): boolean;` + - instance method `mySweep.isRadiansInSweep` optional arg for periodic shift. +- `Angle` instance property `isNorthOrSouthPole` +- static `NumberArray.createArrayWithMaxStepSize(low: number, high: number, step: number): number[];` + - new method, returns array of numbers with (max) step size between low and high +- `Plane3dByOriginAndVectors` instance methods for extracting normalized directions + - instance method `myPlane.normalizeInPlace (): boolean` to normalize the vectors. + - instance method `myPlane.toRigidFrame` to extract local normalized frame + - instance method `myPlane.unitNormal` to extract unit normal + - instance method `myPlane.unitNormalRay` to extract perpendicular ray + - apply `Vector3d` instance method `normalizeInPlace()` to both `vectorU` and `vectorV` of the plane +- `Range3d` class methods + - instance method `myRange.extendSingleAxis(a: number, axisIndex: AxisIndex): void;` + - branch to one of `extendXOnly`, `extendYOnly`, `extendZOnly` +- `Ray3d` class methods + - instance method `myRay.cloneInverseTransformed(transform: Transform): Ray3d | undefined;` + - multiply by inverse of a transform and return the modified ray +- `Transform` class methods + - static `createRigidFromOriginAndColumns(origin: XYZ | undefined, vectorX: Vector3d, vectorY: Vector3d, axisOrder: AxisOrder, result?: Transform): Transform | undefined; + - Careful logic to avoid object allocation when reusing result. diff --git a/docs/changehistory/2.0.0.md b/docs/changehistory/2.0.0.md index 8ad6b0f21144..4dfb1d8de477 100644 --- a/docs/changehistory/2.0.0.md +++ b/docs/changehistory/2.0.0.md @@ -313,7 +313,6 @@ The logger categories setup in `@bentley/imodeljs-clients` have now migrated to | `ClientsLoggerCategory.ImsClients` | Removed | Removed | | `ClientsLoggerCategory.UlasClient` | `@bentley/usage-logging-client` | UsageLoggingClientLoggerCategory.Client | - #### Removed support for SAML-based authorization - *All authentication must now be done using OIDC.* The iModel.js API includes wrappers around popular 3rd party utilities for OIDC based authentication/authorization for web, desktop and agent applications. diff --git a/docs/changehistory/2.1.0.md b/docs/changehistory/2.1.0.md index 4bae8847e4a7..9bdbefa68e15 100644 --- a/docs/changehistory/2.1.0.md +++ b/docs/changehistory/2.1.0.md @@ -1,26 +1,26 @@ ---- -deltaDoc: true -version: '2.1.0' ---- +--- +deltaDoc: true +version: '2.1.0' +--- # 2.1.0 Change Notes ## Geometry -* New methods to reorder and reverse curves to form chains and offset loops. - * `RegionOps.collectChains(fragments: GeometryQuery[], gapTolerance: number)` - * For use case where there is no set expectation of whether there are one or many chains. - * `RegionOps.collectInsideAndOutsideOffsets(fragments: GeometryQuery[], offsetDistance: number, gapTolerance: number)` - * For use case where inputs are expected to form a loop, with clear sense of inside and outside offsetting. +- New methods to reorder and reverse curves to form chains and offset loops. + - `RegionOps.collectChains(fragments: GeometryQuery[], gapTolerance: number)` + - For use case where there is no set expectation of whether there are one or many chains. + - `RegionOps.collectInsideAndOutsideOffsets(fragments: GeometryQuery[], offsetDistance: number, gapTolerance: number)` + - For use case where inputs are expected to form a loop, with clear sense of inside and outside offsetting. ## Display ### Thematic Display Optimizations -* A new `distanceCutoff` property has been added to [ThematicDisplaySensorSettingsProps]($common) and the corresponding [ThematicDisplaySensorSettings]($common) type. - * This is a value in meters. For a position on screen to be affected by a sensor, it must be at least this close to the sensor. - * If the distance cutoff value is specified as zero or negative, then no distance cutoff is applied (all sensors affect all positions regardless of nearness). - * This defaults to zero if unspecified. - * Specifying a reasonable positive value for `distanceCutoff` allows the WebGL renderer to group sensors to particular 3D tiles that are affected by those sensors. By doing this, sensors can be culled from the particular parts of the scene that they do not affect. This results in lowering the amount of work that must be done by the GPU and results in a significant performance gain in many views and zoom levels. +- A new `distanceCutoff` property has been added to [ThematicDisplaySensorSettingsProps]($common) and the corresponding [ThematicDisplaySensorSettings]($common) type. + - This is a value in meters. For a position on screen to be affected by a sensor, it must be at least this close to the sensor. + - If the distance cutoff value is specified as zero or negative, then no distance cutoff is applied (all sensors affect all positions regardless of nearness). + - This defaults to zero if unspecified. + - Specifying a reasonable positive value for `distanceCutoff` allows the WebGL renderer to group sensors to particular 3D tiles that are affected by those sensors. By doing this, sensors can be culled from the particular parts of the scene that they do not affect. This results in lowering the amount of work that must be done by the GPU and results in a significant performance gain in many views and zoom levels. ## UI @@ -35,5 +35,4 @@ This allows an easy way to trigger the same processing on more that just the act Renamed the following to better match their intention: -* `SelectionContextUtilities` to `HideIsolateEmphasizeManager` - +- `SelectionContextUtilities` to `HideIsolateEmphasizeManager` diff --git a/docs/changehistory/2.10.0.md b/docs/changehistory/2.10.0.md index cfdc01315ae5..597b3b8838ce 100644 --- a/docs/changehistory/2.10.0.md +++ b/docs/changehistory/2.10.0.md @@ -11,13 +11,15 @@ version: '2.10.0' ## Changes to display style excluded elements [DisplayStyleSettings.excludedElements]($common) allows a display style to specify a set of elements that should not be drawn. Previously, this set was always persisted to the database as an array of element Ids, and represented in JSON and in memory as a `Set`. However, element Ids tend to be long strings (at least 13 characters), and sets of excluded elements can occasionally grow quite large. To reduce the amount of data associated with these sets: - * They are now always persisted to the database as a [CompressedId64Set]($bentleyjs-core). - * The type of [DisplayStyleSettingsProps.excludedElements]($common) has changed from `Id64Array` to `Id64Array | CompressedId64Set`. - * [DisplayStyleSettings.excludedElements]($common) - a `Set` - has been deprecated in favor of [DisplayStyleSettings.excludedElementIds]($common) - an [OrderedId64Iterable]($bentleyjs-core). - * [IModelDb.Views.getViewStateData]($backend) and [ElementLoadProps]($common) allow the caller to specify whether the Ids should be returned in compressed (string) form or as an uncompressed array; by default, they are uncompressed. - * [IModelConnection.Views.load]($frontend) will always use the compressed representation of the Ids. + +- They are now always persisted to the database as a [CompressedId64Set]($bentleyjs-core). +- The type of [DisplayStyleSettingsProps.excludedElements]($common) has changed from `Id64Array` to `Id64Array | CompressedId64Set`. +- [DisplayStyleSettings.excludedElements]($common) - a `Set` - has been deprecated in favor of [DisplayStyleSettings.excludedElementIds]($common) - an [OrderedId64Iterable]($bentleyjs-core). +- [IModelDb.Views.getViewStateData]($backend) and [ElementLoadProps]($common) allow the caller to specify whether the Ids should be returned in compressed (string) form or as an uncompressed array; by default, they are uncompressed. +- [IModelConnection.Views.load]($frontend) will always use the compressed representation of the Ids. To adjust code that uses [DisplayStyleSettings.excludedElements]($common), given `settings: DisplayStyleSettings`: + ```ts settings.excludedElements.add(id); // Replace this... settings.addExcludedElements(id); // ...with this. @@ -36,9 +38,9 @@ Note that [DisplayStyleSettings.addExcludedElements]($common) and [DisplayStyleS ## Breaking API changes -* The union type [Matrix3dProps]($geometry-core) inadvertently included [Matrix3d]($geometry-core). "Props" types are wire formats and so must be pure JavaScript primitives. To fix compilation errors where you are using `Matrix3d` where a `Matrix3dProps` is expected, simply call [Matrix3d.toJSON]($geometry-core) on your Matrix3d object. Also, since [TransformProps]($geometry-core) includes Matrix3dProps, you may need to call [Transform.toJSON]($geometry-core) on your Transform objects some places too. +- The union type [Matrix3dProps]($geometry-core) inadvertently included [Matrix3d]($geometry-core). "Props" types are wire formats and so must be pure JavaScript primitives. To fix compilation errors where you are using `Matrix3d` where a `Matrix3dProps` is expected, simply call [Matrix3d.toJSON]($geometry-core) on your Matrix3d object. Also, since [TransformProps]($geometry-core) includes Matrix3dProps, you may need to call [Transform.toJSON]($geometry-core) on your Transform objects some places too. -* The type of [Texture.data]($backend) has been corrected from `string` to `Uint8Array` to match the type in the BIS schema. If you get compilation errors, simply remove calls to `Buffer.from(texture.data, "base64")` for read, and `texture.data.toString("base64")` if you create texture objects. +- The type of [Texture.data]($backend) has been corrected from `string` to `Uint8Array` to match the type in the BIS schema. If you get compilation errors, simply remove calls to `Buffer.from(texture.data, "base64")` for read, and `texture.data.toString("base64")` if you create texture objects. ## Updated version of Electron @@ -50,10 +52,10 @@ The globe location tools now will properly use GCS reprojection when navigating. The tools affected are: -* [ViewGlobeSatelliteTool]($frontend) -* [ViewGlobeBirdTool]($frontend) -* [ViewGlobeLocationTool]($frontend) -* [ViewGlobeIModelTool]($frontend) +- [ViewGlobeSatelliteTool]($frontend) +- [ViewGlobeBirdTool]($frontend) +- [ViewGlobeLocationTool]($frontend) +- [ViewGlobeIModelTool]($frontend) The [ViewGlobeLocationTool]($frontend) has been further improved to navigate better across long distances when using plane mode. @@ -61,6 +63,5 @@ There is now a method called `lookAtGlobalLocationFromGcs` on [ViewState3d]($fro [ViewState3d]($frontend) also has GCS versions of these methods: -* `rootToCartographicFromGcs` behaves like `rootToCartographic` except it is async and uses the GCS to reproject the location. -* `cartographicToRootFromGcs` behaves like `cartographicToRoot` except it is async and uses the GCS to reproject the location. - +- `rootToCartographicFromGcs` behaves like `rootToCartographic` except it is async and uses the GCS to reproject the location. +- `cartographicToRootFromGcs` behaves like `cartographicToRoot` except it is async and uses the GCS to reproject the location. diff --git a/docs/changehistory/2.2.0.md b/docs/changehistory/2.2.0.md index 464135fb1a06..828bc87b773e 100644 --- a/docs/changehistory/2.2.0.md +++ b/docs/changehistory/2.2.0.md @@ -58,4 +58,3 @@ There were no API changes, but imports and dependencies will need to be adjusted The `@bentley/physical-material-backend` package is new and contains classes for working with physical materials on the backend. > See: [PhysicalMaterialSchema]($physical-material-backend) - diff --git a/docs/changehistory/2.3.0.md b/docs/changehistory/2.3.0.md index 67d7ae67f61f..cebde16387c7 100644 --- a/docs/changehistory/2.3.0.md +++ b/docs/changehistory/2.3.0.md @@ -9,9 +9,10 @@ version: '2.3.0' ### New gradient modes Thematic display supports several new gradient mode values for the `mode` property of [ThematicGradientSettings]($common): -* `ThematicGradientMode.Stepped` applies a stepped color gradient to the scene. -* `ThematicGradientMode.SteppedWithDelimiter` applies a stepped color gradient to the scene with delimiters (lines between the color steps). -* `ThematicGradientMode.IsoLines` applies isolines to the scene to achieve an effect similar to a contour map. + +- `ThematicGradientMode.Stepped` applies a stepped color gradient to the scene. +- `ThematicGradientMode.SteppedWithDelimiter` applies a stepped color gradient to the scene with delimiters (lines between the color steps). +- `ThematicGradientMode.IsoLines` applies isolines to the scene to achieve an effect similar to a contour map. Note: Gradient modes `ThematicGradientMode.SteppedWithDelimiter` and `ThematicGradientMode.IsoLines` cannot be used with thematic display mode values other than `ThematicDisplayMode.Height`. @@ -27,10 +28,11 @@ Note: Gradient modes `ThematicGradientMode.SteppedWithDelimiter` and `ThematicGr ### New display modes Thematic display supports several new display mode values for the `displayMode` property of [ThematicDisplay]($common): -* `ThematicDisplayMode.Slope` applies a color gradient to surface geometry based on the slope of the surface relative to a specified axis. The slope value is calculated based on the angle between the surface and the axis specified in the associated [ThematicDisplay]($common) object. -* `ThematicDisplayMode.HillShade` applies a color gradient to surface geometry based on the direction of a sun shining on the surface. - * [ThematicDisplay]($common) has a new property named `sunDirection`, a 3d vector, which describes the solar direction used by this display mode. - * If desired, in order to create a sun direction from azimuth and altitude values, a new API function is available: [calculateSolarDirectionFromAngles]($common). This function takes an azimuth and altitude as input and returns a solar direction vector. + +- `ThematicDisplayMode.Slope` applies a color gradient to surface geometry based on the slope of the surface relative to a specified axis. The slope value is calculated based on the angle between the surface and the axis specified in the associated [ThematicDisplay]($common) object. +- `ThematicDisplayMode.HillShade` applies a color gradient to surface geometry based on the direction of a sun shining on the surface. + - [ThematicDisplay]($common) has a new property named `sunDirection`, a 3d vector, which describes the solar direction used by this display mode. + - If desired, in order to create a sun direction from azimuth and altitude values, a new API function is available: [calculateSolarDirectionFromAngles]($common). This function takes an azimuth and altitude as input and returns a solar direction vector. ![slope display mode applied relative to a Z axis with a range of 0 to 90 degrees and a blue-red color scheme](./assets/thematic_slope.png)

Slope display mode applied relative to a Z axis with a range of 0 to 90 degrees and a blue-red color scheme

@@ -42,17 +44,17 @@ Thematic display supports several new display mode values for the `displayMode` The hyper-modeling [Extension]($frontend) has been replaced by the `hypermodeling-frontend` package to permit customization of its behavior. -* Use [HyperModeling.initialize]($hypermodeling) to initialize the package before using any of its APIs. -* Use [HyperModeling.startOrStop]($hypermodeling) to enable or disable hypermodeling for a [Viewport]($frontend). -* Use [HyperModelingConfig]($hypermodeling) to customize the package's behavior. +- Use [HyperModeling.initialize]($hypermodeling) to initialize the package before using any of its APIs. +- Use [HyperModeling.startOrStop]($hypermodeling) to enable or disable hypermodeling for a [Viewport]($frontend). +- Use [HyperModelingConfig]($hypermodeling) to customize the package's behavior. ## Rendering styles A [DisplayStyle]($backend) defines how the contents of a [ViewDefinition]($backend) are rendered. However, the display style contains some data that is specific to the containing iModel, or to the project to which the iModel belongs. It can be very useful to be able to define various "rendering styles" that can be applied to any display style in any iModel or project to change the lighting, thematic display settings, and other visual aspects of the view. To facilitate this, three new methods have been introduced: -* [DisplayStyleSettings.toOverrides]($common) to selectively capture a subset of the settings as a JSON object; -* [DisplayStyleSettings.applyOverrides]($common) to selectively override a subset of the display style settings; and -* [Viewport.overrideDisplayStyle]($frontend) to apply overrides to the viewport's display style and ensure the results become immediately visible. +- [DisplayStyleSettings.toOverrides]($common) to selectively capture a subset of the settings as a JSON object; +- [DisplayStyleSettings.applyOverrides]($common) to selectively override a subset of the display style settings; and +- [Viewport.overrideDisplayStyle]($frontend) to apply overrides to the viewport's display style and ensure the results become immediately visible. A "rendering style" is simply a partial [DisplayStyle3dSettingsProps]($common). When applied to a [DisplayStyleSettings]($common), any settings explicitly defined by the rendering style will be overridden; the remainder will retain their original values. @@ -65,9 +67,11 @@ Examples of some general-purpose rendering styles can be found in [display-test- When multiple providers are registered, no attempt is made to reconcile conflicts between two providers overriding the same [Feature]($common) - that is left to the application. Note that most [FeatureSymbology.Overrides]($frontend) methods like `overrideModel` take an optional `replaceExisting` argument indicating whether or not to replace an existing override for the same entity, so if you have two providers, one of which should never overwrite changes made by the other, that one should pass `false` for `replaceExisting` while the other one should pass `true` (the default). This change necessitates the deprecation of [Viewport.featureOverrideProvider]($frontend), previously used to get or set the sole provider. This property will be removed in a future version. For now, the getter will return a provider if and only if exactly one provider is currently registered. The setter will remove all existing providers and, if a new provider is supplied, register it as the sole provider. We recommend migrating to the new APIs. You can do so as follows: + - Replace `viewport.featureOverrideProvider = myProvider` with `viewport.addFeatureOverrideProvider(myProvider)`. - Replace `viewport.featureOverrideProvider = undefined` with `viewport.dropFeatureOverrideProvider(myProvider)`. - Replace calls to the getter with a call to `findFeatureOverrideProvider` or `findFeatureOverrideProviderOfType`. For example: + ```ts class MyProvider implements FeatureOverrideProvider { public id: string; @@ -85,15 +89,15 @@ This change necessitates the deprecation of [Viewport.featureOverrideProvider]($ Added the following expressions and functions: 1. ` IS [NOT] (type-list)` - Filter parent type by subtype - * [Lesson 9: Type Filter](../learning/ECSQLTutorial/TypeFilter.md) + - [Lesson 9: Type Filter](../learning/ECSQLTutorial/TypeFilter.md) 1. `CASE-WHEN-THEN-ELSE` - Conditional expression - * [Lesson 10: Conditional Expressions](../learning/ECSQLTutorial/ConditionalExpr.md) + - [Lesson 10: Conditional Expressions](../learning/ECSQLTutorial/ConditionalExpr.md) 1. `IIF()` - Conditional expression - * [Lesson 10: Conditional Expressions](../learning/ECSQLTutorial/ConditionalExpr.md) + - [Lesson 10: Conditional Expressions](../learning/ECSQLTutorial/ConditionalExpr.md) 1. `ec_classname()` - Get formatted class names for a ECClassId - * [Lesson 11: Built-In functions](../learning/ECSQLTutorial/BuiltInFunctions.md) + - [Lesson 11: Built-In functions](../learning/ECSQLTutorial/BuiltInFunctions.md) 1. `ec_classid())` - Get ECClassId from a qualified classname. - * [Lesson 11: Built-In functions](../learning/ECSQLTutorial/BuiltInFunctions.md) + - [Lesson 11: Built-In functions](../learning/ECSQLTutorial/BuiltInFunctions.md) ## Schema upgrades diff --git a/docs/changehistory/2.4.0.md b/docs/changehistory/2.4.0.md index 1e7b459ecc72..d9e83fb32232 100644 --- a/docs/changehistory/2.4.0.md +++ b/docs/changehistory/2.4.0.md @@ -24,8 +24,8 @@ If [RenderSystem.Options.devicePixelRatioOverride]($frontend) is defined when su Please note: -* If this setting is used to decrease the effective device pixel ratio, the view will appear pixelated. -* This setting should only be used to increase performance in situations like the iOS Simulator for testing purposes only. It should not be used in a production situation. +- If this setting is used to decrease the effective device pixel ratio, the view will appear pixelated. +- This setting should only be used to increase performance in situations like the iOS Simulator for testing purposes only. It should not be used in a production situation. This option has no effect if [RenderSystem.Options.dpiAwareViewports]($frontend) is overridden to be `false`. @@ -54,4 +54,3 @@ Antialiasing can now be turned on and off per view by setting [Viewport.antialia ![example of no antialiasing on left, and antialiasing with 4 samples on the right](./assets/AntialiasExample2.png)

Example: no antialiasing on left, and antialiasing with 4 samples on the right

- diff --git a/docs/changehistory/2.5.0.md b/docs/changehistory/2.5.0.md index bb46dedc9b71..fa9d8d2af5fc 100644 --- a/docs/changehistory/2.5.0.md +++ b/docs/changehistory/2.5.0.md @@ -1,41 +1,42 @@ ---- -deltaDoc: true -version: '2.5.0' ---- +--- +deltaDoc: true +version: '2.5.0' +--- # 2.5.0 Change Notes ## Restart Query (ECSQL) + Added method that let you cancel last query with same token. This cause last query to throw a exception that was cancelled. ```ts - // A async task running following query +// A async task running following query +for await (const row of db.restartQuery("my-tag", "SELECT * FROM ts.Foo")) { + // ... +} + +// Now submit another query with same tag 'my-tag'. +// If above query still running it would be cancelled and exception would be thrown +for await (const row of db.restartQuery("my-tag", "SELECT * FROM ts.Goo")) { + ... +} + +// In order to see what error was thrown use +try { for await (const row of db.restartQuery("my-tag", "SELECT * FROM ts.Foo")) { // ... } - - // Now submit another query with same tag 'my-tag'. - // If above query still running it would be cancelled and exception would be thrown - for await (const row of db.restartQuery("my-tag", "SELECT * FROM ts.Goo")) { - ... - } - - // In order to see what error was thrown use - try { - for await (const row of db.restartQuery("my-tag", "SELECT * FROM ts.Foo")) { - // ... - } - } catch(err) { - if (err.errorNumber === DbResult.BE_SQLITE_INTERRUPT){ - // query cancelled - } +} catch(err) { + if (err.errorNumber === DbResult.BE_SQLITE_INTERRUPT){ + // query cancelled } +} ``` This method is available on all following classes -* ECDb (backend) -* IModelDb (backend) -* IModelConnection (frontend) +- ECDb (backend) +- IModelDb (backend) +- IModelConnection (frontend) ## Cached decorations @@ -99,6 +100,7 @@ Types related to overriding feature symbology - previously defined in `imodeljs- ## Locatable flag for background map Previously, [TerrainSettings.locatable]($common) and [TerrainProps.nonLocatable]($common) could be used to control whether or not tools could locate and interact with the background map while terrain was enabled - but there was no way to similarly control locatability of the map when terrain was disabled. Now, these two properties are deprecated in favor of [BackgroundMapSettings.locatable]($common) and [BackgroundMapProps.nonLocatable]($common). The new properties control locatability of the map regardless of whether or not terrain is enabled. To retain backwards compatibility with the deprecated properties: + - If `TerrainProps.nonLocatable` is `true`, then the terrain will be non-locatable. - Otherwise, the terrain will be locatable if and only if the background map is locatable. @@ -107,7 +109,8 @@ Previously, [TerrainSettings.locatable]($common) and [TerrainProps.nonLocatable] Breaking change to the `beta` interface [ColorPickerProps]($ui-components). The `activeColor` property has been renamed to `initialColor`. The modified props are used by the [ColorPickerButton]($ui-components) React component. ## Model Appearance Overrides -Appearance overrides can be applied to models in a similar manner to subcategory overries with [DisplayStyleState.overrideModelAppearance] or [Viewport.overrideModelAppearance]. Overrides can be applied to the "contextual" reality models included within display styles with [DisplayStyleState.overrideRealityModelAppearance] or [Viewport.overrideRealityModelAppearance]. For reality models only transparency, color, emphasized and nonLocatable overrides are applicable. + +Appearance overrides can be applied to models in a similar manner to subcategory overrides with [DisplayStyleState.overrideModelAppearance] or [Viewport.overrideModelAppearance]. Overrides can be applied to the "contextual" reality models included within display styles with [DisplayStyleState.overrideRealityModelAppearance] or [Viewport.overrideRealityModelAppearance]. For reality models only transparency, color, emphasized and nonLocatable overrides are applicable. ## CSRF Security Option @@ -117,7 +120,7 @@ IModelApp now supports passing FrontendSecurityOptions at startup. In particular The @bentley/build-tools package now supports ESLint ^6.8.0 and a configuration file to match, the now deprecated, TSLint configuration. The TSLint configuration and custom rules will still exist for the rest of iModel.js 2.x and will be removed in iModel.js 3.0. -To start using the new configuration add the following to the package.json to extend the build-tools package and run the eslint rules against all `ts` and `tsx` files: +To start using the new configuration add the following to the package.json to extend the build-tools package and run the eslint rules against all `ts` and `tsx` files: ```json "scripts": { @@ -131,4 +134,3 @@ To start using the new configuration add the following to the package.json to ex "extends": "./node_modules/@bentley/build-tools/.eslintrc.js" } ``` - diff --git a/docs/changehistory/2.6.0.md b/docs/changehistory/2.6.0.md index 42d4f5ff3305..782a38868211 100644 --- a/docs/changehistory/2.6.0.md +++ b/docs/changehistory/2.6.0.md @@ -1,7 +1,7 @@ ---- -deltaDoc: true -version: '2.6.0' ---- +--- +deltaDoc: true +version: '2.6.0' +--- # 2.6.0 Change Notes ## Addition of @bentley/telemetry-client @@ -38,5 +38,4 @@ The old configuration path `@bentley/build-tools/.eslintrc.js` remains in place ## Electron Security enhancements -To reduce security risks when running under Electron, this version now runs with `nodeIntegration=false`, `contextIsoloation=true`, and `sandbox=true`. To understand the rationale and implications of these changes, please see the [Electon Security Checklist]( https://www.electronjs.org/docs/tutorial/security#checklist-security-recommendations). Note that these choices are the defaults, but can be overriden by arguments to `ElectronManger.initialize`. If you previously passed `webPreferences` arguments to that function, it is best to remove them entirely and rely on the default values. - +To reduce security risks when running under Electron, this version now runs with `nodeIntegration=false`, `contextIsoloation=true`, and `sandbox=true`. To understand the rationale and implications of these changes, please see the [Electron Security Checklist]( https://www.electronjs.org/docs/tutorial/security#checklist-security-recommendations). Note that these choices are the defaults, but can be overriden by arguments to `ElectronManger.initialize`. If you previously passed `webPreferences` arguments to that function, it is best to remove them entirely and rely on the default values. diff --git a/docs/changehistory/2.7.0.md b/docs/changehistory/2.7.0.md index b21e23d33386..8be25e3e235d 100644 --- a/docs/changehistory/2.7.0.md +++ b/docs/changehistory/2.7.0.md @@ -1,7 +1,7 @@ ---- -deltaDoc: true -version: '2.7.0' ---- +--- +deltaDoc: true +version: '2.7.0' +--- # 2.7.0 Change Notes ## Lighting for decoration graphics @@ -9,15 +9,16 @@ version: '2.7.0' Most types of decorations can receive lighting in 3d views (see [GraphicType]($frontend) for details about how lighting applies to each type). But lighting requires normals, and until now a [GraphicBuilder[($frontend) would never generate normals; therefore, decorations were always unlit. Now, [GraphicBuilder.wantNormals]($frontend) can be used to indicate that normals should be generated. This property defaults to `false` to preserve the previous behavior. Meshes produced for any geometry added while the property is set to `true` will result in graphics with normals. For example: + ```ts - // Create a GraphicBuilder for a "scene" graphic, which can be affected by the view's light settings. - const builder = decorateContext.createSceneGraphicBuilder(); - // Add a shape (with normals) that will receive lighting as configured in the view. - builder.wantNormals = true; - builder.addShape(shapePoints); - // Add a planar region (without normals) that will not receive lighting. - builder.wantNormals = false; - builder.addLoop(loop); +// Create a GraphicBuilder for a "scene" graphic, which can be affected by the view's light settings. +const builder = decorateContext.createSceneGraphicBuilder(); +// Add a shape (with normals) that will receive lighting as configured in the view. +builder.wantNormals = true; +builder.addShape(shapePoints); +// Add a planar region (without normals) that will not receive lighting. +builder.wantNormals = false; +builder.addLoop(loop); ``` Caveat: currently, no API exists for generating normals for a [Polyface]($geometry-core). So for now, if you want a lit polyface, you must both set `GraphicBuilder.wantNormals` **and** ensure the `Polyface` you supply to [GraphicBuilder.addPolyface]($frontend) has predefined normals. (If the `Polyface` has predefined normals but `GraphicBuilder.wantNormals` is `false`, the normals will be ignored). This behavior will change once an API for generating normals becomes available - then, the normals will be generated if the `Polyface` lacks them and `wantNormals` is `true`. @@ -61,7 +62,7 @@ Add components [DatePickerPopupButton]($ui-components) and [DatePicker]($ui-comp Add support for [KeyinPalettePopup] component that opens using the Ctrl+F2 key combination. opening a popup that provides a list of key-ins supported by registered tools and allows a user to select and run a key-in. iModel.js applications must enable the use by enabling the feature flag as shown below. ```ts - IModelApp.uiAdmin.updateFeatureFlags({ allowKeyinPalette: true }); +IModelApp.uiAdmin.updateFeatureFlags({ allowKeyinPalette: true }); ``` An application can also provide a tool button to popup the Key-in Popup using the newly provided item definition `CoreTools.keyinPaletteButtonItemDef`. @@ -71,22 +72,26 @@ An application can also provide a tool button to popup the Key-in Popup using th The method to pull, merge and push change sets at the *frontend* has been split and moved to a new location. These frontend API continue to be work in progress, and are marked with the appropriate @alpha release tag. The corresponding backend API remains unchanged. Before: + ```ts - const changeSetId = await iModelConnection.editing.concurrencyControl.pullMergePush("", false /*=doPush*/); +const changeSetId = await iModelConnection.editing.concurrencyControl.pullMergePush("", false /*=doPush*/); ``` After: + ```ts await iModelConnection.pullAndMergeChanges(); const changeSetId = iModelConnection.changeSetId; ``` Before: + ```ts const changeSetId = await iModelConnection.editing.concurrencyControl.pullMergePush("Push message", true /*=doPush*/); ``` After: + ```ts await iModelConnection.pushChanges("Push message"); const changeSetId = iModelConnection.changeSetId; @@ -95,12 +100,13 @@ After: The method to get the parent change set id from the IModelConnection has been removed. It's available as a property that's kept up to date as change sets are pulled/pushed: Before: + ```ts const changeSetId = await iModelConnection.editing.getParentChangeSetId(); ``` After: + ```ts const changeSetId = iModelConnection.changeSetId; ``` - diff --git a/docs/changehistory/2.8.0.md b/docs/changehistory/2.8.0.md index 140ad2890ade..6d862b3e04af 100644 --- a/docs/changehistory/2.8.0.md +++ b/docs/changehistory/2.8.0.md @@ -1,7 +1,7 @@ ---- -deltaDoc: true -version: '2.8.0' ---- +--- +deltaDoc: true +version: '2.8.0' +--- # 2.8.0 Change Notes ## Color mix property added to thematic gradient settings @@ -112,10 +112,9 @@ Previously, when traversing from a parent node, that is based on multiple instan Now, in the situation described above, there will be no more duplication. -## Hilite/Emphasis interaction modified. +## Hilite/Emphasis interaction modified The visual interaction between hilited and emphasized geometry has been modified to look better. Hilited geometry now always shows through emphasized geometry and visa versa. Geometry which is both hilited and emphasized now shows the outline for both (provided they are of different widths). ![Cylinder is hilited, Torus is emphasized, and Block is both hilited and emphasized](./assets/HiliteEmphasisInteraction.png)

Cylinder is hilited, Torus is emphasized, and Block is both hilited and emphasized.

- diff --git a/docs/changehistory/2.9.0.md b/docs/changehistory/2.9.0.md index e77cf331e49a..0364ec3d09be 100644 --- a/docs/changehistory/2.9.0.md +++ b/docs/changehistory/2.9.0.md @@ -31,6 +31,7 @@ if (models.length > 0) ## Map Layers Map layers such as BingMaps and MapBox require keys so that they may be accessed. These keys were previously hardcoded in multiple locations. These keys have been moved and added as default [MapLayerOptions]($frontend). Keys should now be passed through [IModelApp.startup]($frontend), as an IModelAppOption like: + ``` IModelApp.startup({mapLayerOptions: {BingMaps: {key: "expected-key-name-for-key-value-pair", value: "access-token-goes-here"}}}) ``` @@ -181,7 +182,7 @@ Fix: }); ``` -## Hilite/Emphasis interaction modified. +## Hilite/Emphasis interaction modified The visual interaction between hilited and emphasized geometry has been modified to look better. Hilited geometry now always shows through emphasized geometry and visa versa. Geometry which is both hilited and emphasized now shows the outline for both (provided they are of different widths). diff --git a/docs/changehistory/leftNav.md b/docs/changehistory/leftNav.md index 9a6a26d458a0..7bf4c2508a49 100644 --- a/docs/changehistory/leftNav.md +++ b/docs/changehistory/leftNav.md @@ -1,4 +1,5 @@ ## Change History + --- ### Roadmap @@ -8,6 +9,7 @@ --- ### Versions + - [2.11.0](./2.11.0.md) - [2.10.0](./2.10.0.md) @@ -37,37 +39,40 @@ ### Previous Versions -- [1.14.0](./1.14.0.md) +- [1.14.0](./1.14.0.md) + +- [1.13.0](./1.13.0.md) -- [1.13.0](./1.13.0.md) +- [1.12.0](./1.12.0.md) -- [1.12.0](./1.12.0.md) +- [1.11.0](./1.11.0.md) -- [1.11.0](./1.11.0.md) +- [1.10.0](./1.10.0.md) -- [1.10.0](./1.10.0.md) +- [1.9.0](./1.9.0.md) -- [1.9.0](./1.9.0.md) +- [1.8.0](./1.8.0.md) -- [1.8.0](./1.8.0.md) +- [1.7.0](./1.7.0.md) -- [1.7.0](./1.7.0.md) +- [1.6.0](./1.6.0.md) -- [1.6.0](./1.6.0.md) +- [1.5.0](./1.5.0.md) -- [1.5.0](./1.5.0.md) +- [1.4.0](./1.4.0.md) -- [1.4.0](./1.4.0.md) +- [1.3.0](./1.3.0.md) -- [1.3.0](./1.3.0.md) +- [1.2.0](./1.2.0.md) -- [1.2.0](./1.2.0.md) +- [1.1.0](./1.1.0.md) -- [1.1.0](./1.1.0.md) +- [1.0.0](./1.0.0.md) -- [1.0.0](./1.0.0.md) --- + ### [Change Logs](./ChangeLogs.md) + - [imodeljs-backend](../reference/imodeljs-backend/changelog) - [imodeljs-frontend](../reference/imodeljs-frontend/changelog) diff --git a/docs/changehistory/migration-guides/MigratingBuildSystems.md b/docs/changehistory/migration-guides/MigratingBuildSystems.md index 60f88d429377..d049de7e675d 100644 --- a/docs/changehistory/migration-guides/MigratingBuildSystems.md +++ b/docs/changehistory/migration-guides/MigratingBuildSystems.md @@ -59,25 +59,27 @@ With the above background in mind, the quickest/easiest migration pattern for al ``` 1. Add a separate `tsconfig.json` for backend build called `tsconfig.backend.json`. - - The build between the frontend and backend are now slightly different in their configuration meaning that an app now needs two separate tsconfigs - - The contents of the `tsconfig.backend.json` should be similar to the following: - - ```json - { - "extends": "./node_modules/@bentley/build-tools/tsconfig-base.json", - "compilerOptions": { - "target": "es2017", - "module": "commonjs", - "outDir": "./lib" - }, - "include": [ - "./src/backend/*.ts", - "./src/common/*.ts" - ], - "exclude": [ - "lib", - "node_modules" - ] - } + + - The build between the frontend and backend are now slightly different in their configuration meaning that an app now needs two separate tsconfigs + - The contents of the `tsconfig.backend.json` should be similar to the following: + + ```json + { + "extends": "./node_modules/@bentley/build-tools/tsconfig-base.json", + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "outDir": "./lib" + }, + "include": [ + "./src/backend/*.ts", + "./src/common/*.ts" + ], + "exclude": [ + "lib", + "node_modules" + ] + } ``` ## FAQ diff --git a/docs/getting-started/development-prerequisites.md b/docs/getting-started/development-prerequisites.md index 3997f463dd9b..715fe64efb2d 100644 --- a/docs/getting-started/development-prerequisites.md +++ b/docs/getting-started/development-prerequisites.md @@ -10,7 +10,7 @@ Writing an iModel.js application requires the following software: - [Git](https://git-scm.com/downloads) - This is the source code control system for the iModel.js repositories. -### Suggested tools +## Suggested tools The following tools are very helpful and highly suggested for working with iModel.js: @@ -18,12 +18,12 @@ The following tools are very helpful and highly suggested for working with iMode - This is the recommended editor and debugger for iModel.js applications. - VS Code also supplies a graphical user interface for working with Git. - The following VS Code extensions can also be quite helpful: - - [TSLint](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin) (use tslint.json from @bentley/build-tools to enforce Bentley coding standards) + - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) (use the [@bentley/eslint-plugin](https://www.npmjs.com/package/@bentley/eslint-plugin) to enforce Bentley coding standards) - [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) - [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) (great tools for using Git inside VS Code) - [MarkdownLint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint) (for editing documentation) -### Recommended reading +## Recommended reading - [TypeScript](http://www.typescriptlang.org/) - iModel.js applications are written in TypeScript and then _compiled_ to plain JavaScript. diff --git a/docs/getting-started/environment-variables.md b/docs/getting-started/environment-variables.md index 5284b3363453..c893011444cf 100644 --- a/docs/getting-started/environment-variables.md +++ b/docs/getting-started/environment-variables.md @@ -14,4 +14,4 @@ $env:variable_name = '' ``` cmd export variable_name= -``` \ No newline at end of file +``` diff --git a/docs/getting-started/leftNav.md b/docs/getting-started/leftNav.md index eb9962951eca..771c11222ba6 100644 --- a/docs/getting-started/leftNav.md +++ b/docs/getting-started/leftNav.md @@ -1,18 +1,29 @@ ## [Dashboards](/getting-started/registration-dashboard?tab=1) ##### [iModel Registration Dashboard](/getting-started/registration-dashboard?tab=1) + ##### [Application Registration Dashboard](/getting-started/registration-dashboard?tab=0) --- + ## [Offline](./offline-quickstart.md) + ##### [1. Get the tools](./offline-quickstart.md#1-get-the-tools) + ##### [2. Get the code](./offline-quickstart.md#2-get-the-code) + ##### [3. Build and run a sample app](./offline-quickstart.md#3-build-and-run-a-sample-app) --- + ## [Online](./online-quickstart.md) + ##### [1. Get the tools](./online-quickstart.md#1-get-the-tools) + ##### [2. Get a sample iModel](./online-quickstart.md#2-get-a-sample-imodel) + ##### [3. Get the sample code](./online-quickstart.md#3-get-the-sample-code) + ##### [4. Configure](./online-quickstart.md#4-configure) + ##### [5. Build and run a sample app](./online-quickstart.md#5-build-and-run-a-sample-app) diff --git a/docs/getting-started/online-quickstart.md b/docs/getting-started/online-quickstart.md index c21980a15522..986eef20aace 100644 --- a/docs/getting-started/online-quickstart.md +++ b/docs/getting-started/online-quickstart.md @@ -13,23 +13,28 @@ Writing an iModel.js application requires the following software: - This is the source code control system for the iModel.js repositories. ### Suggested IDE + - [Visual Studio Code](https://code.visualstudio.com/) - This is the recommended editor and debugger for iModel.js applications. - VS Code also supplies a GUI for working with Git. ## 2. Get a sample iModel + [Click here and use the registration dashboard to create a new iModel](/getting-started/registration-dashboard?tab=1&create=bentleyExample) ## 3. Get the sample code + The samples are included in the [imodeljs-samples](/~https://github.com/imodeljs/imodeljs-samples) repo on GitHub. For a complete list of samples see the README. > `git clone /~https://github.com/imodeljs/imodeljs-samples.git` ## 4. Configure + Edit imodeljs-samples/interactive-app/basic-viewport-app/.env.local > `imjs_test_imodel` = The name of your iModel created in step 2
## 5. Build and run a sample app + > `cd interactive-app` > `cd basic-viewport-app` @@ -43,7 +48,9 @@ Edit imodeljs-samples/interactive-app/basic-viewport-app/.env.local     --- + ## Next Steps + ### [Follow tutorials to dive deeper into iModel.js]($docs/learning/tutorials/index.md) ### [iModel.js Blog](https://medium.com/imodeljs) diff --git a/docs/learning/App.md b/docs/learning/App.md index 2d49e1dd1f82..2eda0c66679b 100644 --- a/docs/learning/App.md +++ b/docs/learning/App.md @@ -2,12 +2,12 @@ From the same JavaScript codebase, it is possible to create: -* [Backend Agents and Services](#agents-and-services) that process iModels and respond to events from iModelHub -* [Interactive Apps](#interactive-apps) that have a GUI and access iModel content. Several kinds of apps are supported: - * [Web Apps](#web-apps) that run in web browsers and communicate with backend code running in Web servers - * [Desktop Apps](#desktop-apps) that run on personal computers - * [Mobile Apps](#mobile-apps) that run on tablets and phones -* [Bridges](../learning/WriteABridge.md) +- [Backend Agents and Services](#agents-and-services) that process iModels and respond to events from iModelHub +- [Interactive Apps](#interactive-apps) that have a GUI and access iModel content. Several kinds of apps are supported: + - [Web Apps](#web-apps) that run in web browsers and communicate with backend code running in Web servers + - [Desktop Apps](#desktop-apps) that run on personal computers + - [Mobile Apps](#mobile-apps) that run on tablets and phones +- [Bridges](../learning/WriteABridge.md) ## Agents and Services diff --git a/docs/learning/AppTailoring.md b/docs/learning/AppTailoring.md index bb9d81737beb..31ff4b0754e6 100644 --- a/docs/learning/AppTailoring.md +++ b/docs/learning/AppTailoring.md @@ -10,21 +10,21 @@ An app is prepared for deployment by "last mile" scripts. Different scripts will An app [frontend](../learning/Glossary.md#frontend) typically has a different "main" for each configuration to do the following: -* Change the app's UI and functionality to suit the configuration and platform. - * Do platform-specific initialization: - * UI "chrome" - * Entitlements - * Other platform integration - * [Tailor the GUI](#change-the-gui) -* [Configure interfaces on the client side](../learning/RpcInterface.md#client-side-configuration). - * You may apply the [backends-for-frontends pattern](#backends-for-frontends). - * Web apps have several configuration options, as described in [the article on writing an interactive Web app](./WriteAnInteractiveWebApp.md). +- Change the app's UI and functionality to suit the configuration and platform. + - Do platform-specific initialization: + - UI "chrome" + - Entitlements + - Other platform integration + - [Tailor the GUI](#change-the-gui) +- [Configure interfaces on the client side](../learning/RpcInterface.md#client-side-configuration). + - You may apply the [backends-for-frontends pattern](#backends-for-frontends). + - Web apps have several configuration options, as described in [the article on writing an interactive Web app](./WriteAnInteractiveWebApp.md). An app [backend](../learning/Glossary.md#backend) may have a different "main" if it supports more than one configuration. For more information, see: -* [Web app](../learning/WriteAnInteractiveWebApp.md) -* [Desktop app](../learning/WriteAnInteractiveDesktopApp.md) -* [Mobile app](../learning/WriteAnInteractiveMobileApp.md) +- [Web app](../learning/WriteAnInteractiveWebApp.md) +- [Desktop app](../learning/WriteAnInteractiveDesktopApp.md) +- [Mobile app](../learning/WriteAnInteractiveMobileApp.md) The last-mile packaging and deployment scripts select the appropriate main for frontend and backend. diff --git a/docs/learning/ECSQL.md b/docs/learning/ECSQL.md index 66bedf6966f3..46d53326242d 100644 --- a/docs/learning/ECSQL.md +++ b/docs/learning/ECSQL.md @@ -133,7 +133,7 @@ ECSQL supports dates without time (`DATE`), dates with time (`TIMESTAMP`), and t `TIME 'hh:mm:ss[.nnn]'` -The time stamp format matches the [ISO 8601 standard](https://www.iso.org/iso-8601-date-and-time-format.html) (see also https://en.wikipedia.org/wiki/ISO_8601) +The time stamp format matches the [ISO 8601 standard](https://www.iso.org/iso-8601-date-and-time-format.html) (see also ) #### Basic functions @@ -219,6 +219,7 @@ ECSQL | Description `SELECT Name FROM myschema.Company WHERE Location.Zip=12314` | Returns rows that match the Location's Zip member value based on this ECSchema snippet: + ```xml @@ -304,7 +305,7 @@ In ECSchemas ECRelationshipClasses are used to relate two ECClasses. ECRelations If [navigation properties](#navigation-properties) are defined for the ECRelationship class, use the navigation property instead of a join. -#### Examples +### Examples Without navigation property (2 JOINs needed): diff --git a/docs/learning/ECSQLTutorial/BuiltInFunctions.md b/docs/learning/ECSQLTutorial/BuiltInFunctions.md index cc4e5b59fd68..f871d73c4809 100644 --- a/docs/learning/ECSQLTutorial/BuiltInFunctions.md +++ b/docs/learning/ECSQLTutorial/BuiltInFunctions.md @@ -2,6 +2,7 @@ # ECSQL Built-In functions ECSQL allows use of these built-in functions: + 1. `ec_classname()` - Gets the formatted/qualified class name, given ECClassId as input 2. `ec_classid())` - Gets ECClassId, given a formatted/qualified class name as input diff --git a/docs/learning/ECSQLTutorial/ChangeSummaryQueries.md b/docs/learning/ECSQLTutorial/ChangeSummaryQueries.md index 50751163f958..57715482d2fc 100644 --- a/docs/learning/ECSQLTutorial/ChangeSummaryQueries.md +++ b/docs/learning/ECSQLTutorial/ChangeSummaryQueries.md @@ -109,6 +109,7 @@ also serves to return the ECInstanceIds of the corresponding Change Summaries wh > ordered from oldest to newest. > > *ECSQL* +> > ```sql > SELECT Summary.Id, WsgId, Description, PushDate, UserCreated, ParentWsgId FROM imodelchange.Changeset ORDER BY PushDate > ``` @@ -131,6 +132,7 @@ Now that we know what changesets there are, let us look what instances were chan > for each change. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ChangedInstance.Id, ChangedInstance.ClassId, OpCode FROM ecchange.change.InstanceChange WHERE Summary.Id=0x35 > ``` @@ -155,6 +157,7 @@ For the sake of readability we modify the query by joining to the [ECDbMeta ECSc > for each change. > > *ECSQL* +> > ```sql > SELECT ic.ECInstanceId, ic.ChangedInstance.Id, s.Name || '.' || c.Name ChangedClass, ic.OpCode FROM ecchange.change.InstanceChange ic > JOIN main.meta.ECClassDef c ON ic.ChangedInstance.ClassId=c.ECInstanceId @@ -192,6 +195,7 @@ out what properties were modified. > *Goal:* Return the names of the properties that were modified in the InstanceChange `0x48`. > > *ECSQL* +> > ```sql > SELECT AccessString FROM change.PropertyValueChange WHERE InstanceChange.Id=0x48 > ``` @@ -214,6 +218,7 @@ from the previous query. As always we can use a join, if we only know the id of > *Goal:* Return the names of the properties that were modified in Device `0x20000000001` in Change Summary `0x35`. > > *ECSQL* +> > ```sql > SELECT AccessString FROM change.PropertyValueChange pc JOIN change.InstanceChange ic ON pc.InstanceChange.Id=ic.ECInstanceId WHERE ic.ChangedInstance.Id=0x20000000001 AND ic.ChangedInstance.ClassId=0x100 AND ic.Summary.Id=0x35 > ``` @@ -234,6 +239,7 @@ Now that we looked at this, let's modify the previous query and use the Change S > *Goal:* Return the names of the properties of Device `0x20000000001` that were affected in Change Summary `0x1`. > > *ECSQL* +> > ```sql > SELECT AccessString FROM change.PropertyValueChange pc JOIN change.InstanceChange ic ON pc.InstanceChange.Id=ic.ECInstanceId WHERE ic.ChangedInstance.Id=0x20000000001 AND ic.ChangedInstance.ClassId=0x100 AND ic.Summary.Id=0x1 > ``` @@ -275,6 +281,7 @@ that tells us what kind of change this was, i.e. what the OpCode of that change > *Goal:* Return the OpCode for the change of Device `0x20000000001` in Change Summary `0x1`. > > *ECSQL* +> > ```sql > SELECT OpCode FROM change.InstanceChange WHERE Summary.Id=0x1 AND ChangedInstance.Id=0x20000000001 AND ChangedInstance.ClassId=0x100 > ``` @@ -310,6 +317,7 @@ Before looking at how the Devices have changed over the time, let's look at the > *Goal:* Return id, CodeValue and UserLabel of all Devices. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device > ``` @@ -338,6 +346,7 @@ Before looking at how the Devices have changed over the time, let's look at the > *Goal:* Return id, CodeValue and UserLabel of the Devices that were **inserted** in Change Summary `0x6c`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x6c,'AfterInsert') > ``` @@ -357,6 +366,7 @@ Now let's change the [ChangedValueState]($common) argument in the query. > *Goal:* Return id, CodeValue and UserLabel of the Devices that were **updated** in Change Summary `0x6c`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x6c,'AfterUpdate') > ``` @@ -381,6 +391,7 @@ From the previous queries we know that in this changeset a new Device with code > *Goal:* Return id, CodeValue and UserLabel of the Devices that were **inserted** in Change Summary `0x35`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x35,'AfterInsert') > ``` @@ -399,6 +410,7 @@ Note: `NULL` is returned for `CodeValue` because it was not affected by this cha > *Goal:* Return id, CodeValue and UserLabel of the Devices **before** they were **updated** in Change Summary `0x35`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x35,'BeforeUpdate') > ``` @@ -414,6 +426,7 @@ Note: `NULL` is returned for `CodeValue` because it was not affected by this cha > *Goal:* Return id, CodeValue and UserLabel of the Devices **after** they were **updated** in Change Summary `0x35`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x35,'AfterUpdate') > ``` @@ -433,6 +446,7 @@ In the third changeset the Device with code `DEV-A-G-3` which was inserted in th > *Goal:* Return id, CodeValue and UserLabel of the Devices **before** they were **deleted** in Change Summary `0x1`. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,CodeValue,UserLabel FROM mydomain.Device.Changes(0x1,'BeforeDelete') > ``` diff --git a/docs/learning/ECSQLTutorial/ECSQLDataTypes.md b/docs/learning/ECSQLTutorial/ECSQLDataTypes.md index c03b02d32a86..0ae9be6464cc 100644 --- a/docs/learning/ECSQLTutorial/ECSQLDataTypes.md +++ b/docs/learning/ECSQLTutorial/ECSQLDataTypes.md @@ -18,9 +18,11 @@ ECClassId | Refers to the ECClassId of an ECClass. It uniquely identifies an ECC > *Goal:* Return the actual Element subclass of the [Element](../../bis/domains/BisCore.ecschema.md#element) with id 0x20000000004. > > *ECSQL* +> > ```sql > SELECT ECClassId, CodeValue FROM bis.Element WHERE ECInstanceId=0x20000000004 > ``` +> ## Primitive Data Types @@ -36,9 +38,11 @@ For Boolean types ECSQL supports the literals `True` and `False`. > *Goal:* Find out which [Model](../../bis/domains/BisCore.ecschema.md#model) are private or not. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ECClassId, IsPrivate FROM bis.Model > ``` +> Boolean properties or expressions do not need to be compared to `True` and `False` as they return a @@ -49,13 +53,17 @@ boolean value already. > *Goal:* Find private [Model](../../bis/domains/BisCore.ecschema.md#model)s. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.Model WHERE IsPrivate = True > ``` +> > and +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.Model WHERE IsPrivate > ``` +> > are equivalent. @@ -66,13 +74,17 @@ And the same example with `False`: > *Goal:* Find non-private [Model](../../bis/domains/BisCore.ecschema.md#model)s. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.Model WHERE IsPrivate = False > ``` +> > and +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.Model WHERE NOT IsPrivate > ``` +> ## DateTime @@ -88,9 +100,11 @@ See [ECSQL Reference](../ECSQL.md#datetime) for details. > *Goal:* Find all elements which were modified between 12:30pm and 12:31pm UTC on March, 11th 2020. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, CodeValue, LastMod FROM bis.Element WHERE LastMod BETWEEN TIMESTAMP '2020-03-11T12:30:20.492Z' AND TIMESTAMP '2020-03-11T12:31:03.494Z' > ``` +> ## Points @@ -112,9 +126,11 @@ Property | Description > lower corner point (0, 0, 0) and the upper corner point (10, 10, 10). > > *ECSQL* +> > ```sql > SELECT ecinstanceid, Origin FROM bis.spatialelement WHERE Origin.X BETWEEN 0 AND 10 AND Origin.Y BETWEEN 0 AND 10 AND Origin.Z BETWEEN 0 AND 10 > ``` +> ## Navigation Properties @@ -138,20 +154,23 @@ Property | Description > *Goal:* Return the parent [Element](../../bis/domains/BisCore.ecschema.md#element) for the element with code value *0x20000000007*. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, CodeValue, LastMod, Parent FROM bis.Element WHERE ECInstanceId = 0x20000000007 > ``` +> - > **Try it yourself** > > *Goal:* Return the id of the parent [Element](../../bis/domains/BisCore.ecschema.md#element) for the element with id value *0x20000000007*. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, CodeValue, LastMod, Parent.Id FROM bis.Element WHERE ECInstanceId = 0x20000000007 > ``` +> --- @@ -161,9 +180,11 @@ Property | Description > *Goal:* Return the id and RelECClassId of the parent [Element](../../bis/domains/BisCore.ecschema.md#element) separately for the element with id value *0x20000000007*. > > *ECSQL* +> > ```sql > SELECT Parent.Id, Parent.RelECClassId FROM bis.Element WHERE ECInstanceId = 0x20000000007 > ``` +> Find more examples in the lesson about [Joins and ECRelationshipClasses](./Joins.md#examples). @@ -182,6 +203,7 @@ Follow the steps in the sections [Generate Change Summaries](./ChangeSummaryQuer > *Goal:* Return ChangedInstance struct (of type [InstanceKey](../ECDbChange.ecschema.md#instancekey)) as a whole and OpCode for the InstanceChange object `0x36`. > > *ECSQL* +> > ```sql > SELECT ChangedInstance,OpCode FROM change.InstanceChange WHERE ECInstanceId=0x36 > ``` @@ -199,6 +221,7 @@ And here is an example where individual members of the struct are used. > *Goal:* Return the ids of changed instances (structs of type [InstanceKey](../ECDbChange.ecschema.md#instancekey)) that are [Device](./MyDomain.ecschema.md#device)s (ECClass `0x100`) and the corresponding Change Summary id and OpCode. > > *ECSQL* +> > ```sql > SELECT Summary.Id,ChangedInstance.Id,OpCode FROM change.InstanceChange WHERE ChangedInstance.ClassId=0x100 > ``` @@ -224,6 +247,7 @@ In ECSQL you can refer to Array ECProperties only as a whole. in the array property [ECEnumerationDef.EnumValues](../ECDbMeta.ecschema.md#ecenumerationdef). > > *ECSQL* +> > ```sql > SELECT Name, EnumValues FROM meta.ECEnumerationDef WHERE Name='SectionType' > ``` diff --git a/docs/learning/ECSQLTutorial/FirstExamples.md b/docs/learning/ECSQLTutorial/FirstExamples.md index 462d45d69f6c..f9f1cb2c0208 100644 --- a/docs/learning/ECSQLTutorial/FirstExamples.md +++ b/docs/learning/ECSQLTutorial/FirstExamples.md @@ -9,9 +9,11 @@ We will start off the tutorial by a simple ECSQL example using the "House Sample > *Goal:* Return id, subclass and UserLabel of all [SpatialLocationElement](../../bis/domains/BisCore.ecschema.md#spatiallocationelement)s in the iModel. > > *ECSQL:* +> > ```sql > SELECT ECInstanceId, ECClassId, UserLabel FROM bis.SpatialLocationElement > ``` +> ## Fully qualified class names @@ -29,9 +31,11 @@ The example from above uses the schema alias. If you replace it by the schema na > *Goal:* Return id, subclass and UserLabel of all [SpatialLocationElement](../../bis/domains/BisCore.ecschema.md#spatiallocationelement)s in the iModel. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ECClassId, UserLabel FROM BisCore.SpatialLocationElement > ``` +> If you omit the schema, you will get an error: @@ -41,9 +45,11 @@ If you omit the schema, you will get an error: > *Goal:* Return id, subclass and UserLabel of all [SpatialLocationElement](../../bis/domains/BisCore.ecschema.md#spatiallocationelement)s in the iModel. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ECClassId, UserLabel FROM SpatialLocationElement > ``` +> ## Element Count @@ -55,9 +61,11 @@ The above example is not very meaningful. In large iModels the query might retur > *Goal:* Find out how many [Element](../../bis/domains/BisCore.ecschema.md#element)s there are in the iModel. > > *ECSQL* +> > ```sql > SELECT count(*) FROM bis.Element > ``` +> This query considers all kinds of [Element](../../bis/domains/BisCore.ecschema.md#element)s. If we want to focus only on Elements which represent realworld assets, we can use the BIS class [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s instead. @@ -67,9 +75,11 @@ This query considers all kinds of [Element](../../bis/domains/BisCore.ecschema.m > *Goal:* Find out how many [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s there are in the iModel. > > *ECSQL* +> > ```sql > SELECT count(*) FROM bis.SpatialElement > ``` +> Let's compute some more Element statistic with ECSQL. We want to find out how many [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s there are in the iModel per actual element type (where element type here refers to the subclasses of the [Element](../../bis/domains/BisCore.ecschema.md#element) ECClass). @@ -79,9 +89,11 @@ Let's compute some more Element statistic with ECSQL. We want to find out how ma > *Goal:* Find out how many [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s there are in the iModel per actual element type. > > *ECSQL* +> > ```sql > SELECT ECClassId, count(*) ElementCount FROM bis.SpatialElement GROUP BY ECClassId ORDER BY ECClassId > ``` +> ## Limiting the result set @@ -95,9 +107,11 @@ Let's apply `LIMIT` and `OFFSET` to he first ECSQL example from above ([first EC > *Goal:* Return the first 5 [SpatialLocationElement](../../bis/domains/BisCore.ecschema.md#spatiallocationelement)s only. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ECClassId, CodeValue FROM bis.SpatialLocationElement LIMIT 5 > ``` +> --- @@ -107,9 +121,11 @@ Let's apply `LIMIT` and `OFFSET` to he first ECSQL example from above ([first EC > *Goal:* Return the 11th through 15th [SpatialLocationElement](../../bis/domains/BisCore.ecschema.md#spatiallocationelement) only. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, ECClassId, CodeValue FROM bis.SpatialLocationElement LIMIT 5 OFFSET 10 > ``` +> ## Formatting the Output @@ -121,9 +137,11 @@ Let's apply `LIMIT` and `OFFSET` to he first ECSQL example from above ([first EC > *Goal:* Find out how many [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s there are in the iModel and give the resulting column the more meaningful name *Element Count*. > > *ECSQL* +> > ```sql > SELECT count(*) ElementCount FROM bis.SpatialElement > ``` +> > **Try it yourself** @@ -131,9 +149,11 @@ Let's apply `LIMIT` and `OFFSET` to he first ECSQL example from above ([first EC > *Goal:* Return id and code of all [Element](../../bis/domains/BisCore.ecschema.md#element)s in the iModel and give the id column the name *ElementId* and the code value column the name *Code*. > > *ECSQL* +> > ```sql > SELECT ECInstanceId ElementId, ECClassId, CodeValue Code FROM bis.Element LIMIT 3 > ``` +> One aspect of the power of ECSQL (and SQL) is the richness of expressiveness. Instead of just returning the property values from @@ -144,19 +164,21 @@ some class, you can let ECSQL do calculations. The following example uses ECSQL > *Goal:* Compute the perimeter and area of a circle with a radius of 10 cm. > > *ECSQL* +> > ```sql > SELECT 10 Radius, (2 * 3.1415 * 10) Perimeter, (3.1415 * 10 * 10) Area FROM bis.Element LIMIT 1 > ``` - +> + Using **aliases** is also helpful when working with the iModel.js API. The API returns query results as JavaScript object literals where each expression of the SELECT clause becomes the member of the object. If you, for example, used the [Element Count example](#element-count) with the iModel.js API, you would get this JavaScript object literal: - ```ts - { "count(*)" : 27 } - ``` +```ts +{ "count(*)" : 27 } +``` The power of JavaScript object literals is lost here, because `count(*)` is not a valid member name. If you applied an alias to the count expression though so that the ECSQL would look like this: @@ -168,17 +190,17 @@ SELECT count(*) elementCount FROM bis.SpatialElement the JavaScript object would now look like this: ```ts - { elementCount : 27 } - ``` +{ elementCount : 27 } +``` Now the result can be consumed in TypeScript as desired: ```ts - iModelDb.withPreparedStatement("SELECT count(*) elementCount FROM bis.SpatialElement", (stmt: ECSqlStatement) => { - stmt.step(); - const row: any = stmt.getRow(); - console.log("Element count: " + row.elementCount); - }); +iModelDb.withPreparedStatement("SELECT count(*) elementCount FROM bis.SpatialElement", (stmt: ECSqlStatement) => { + stmt.step(); + const row: any = stmt.getRow(); + console.log("Element count: " + row.elementCount); +}); ``` ## Parametrizing the ECSQL @@ -192,9 +214,11 @@ To reuse the same ECSQL statement with different values, parameters can be used. > *Goal:* Return all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that do not have a user label. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.SpatialElement WHERE CodeValue=? LIMIT 5 > ``` +> As you cannot bind values to parameters in the iModelConsole, the above query returns the same as if you did the following. @@ -204,15 +228,17 @@ As you cannot bind values to parameters in the iModelConsole, the above query re > *Goal:* Return all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that do not have a user label. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.SpatialElement WHERE CodeValue = NULL LIMIT 5 > ``` +> > *Result* ## Comparing to NULL -The above example can be used to mention SQLite's semantics of comparing to NULL (see also https://www.sqlite.org/nulls.html ). The rule in SQLite is: +The above example can be used to mention SQLite's semantics of comparing to NULL (see also ). The rule in SQLite is: > SQLite evaluates the expression `myProp = NULL` always to `false`, even if the property is unset. @@ -223,9 +249,11 @@ If you want to check whether a property is NULL, i.e. unset, use the `IS NULL` o > *Goal:* Return all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that do not have a user label. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.SpatialElement WHERE UserLabel IS NULL LIMIT 5 > ``` +> And to illustrate the difference, the same query using = NULL does not return any rows. @@ -235,9 +263,11 @@ And to illustrate the difference, the same query using = NULL does not return an > *Goal:* Illustrate that expressions like `= NULL` are always false. > > *ECSQL* +> > ```sql > SELECT ECInstanceId,ECClassId FROM bis.SpatialElement WHERE UserLabel = NULL LIMIT 5 > ``` +> ## SQL Functions @@ -249,9 +279,11 @@ Any SQL function can be used in ECSQL. This includes functions built into SQLite > *Goal:* For all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s whose userlabel contains the string 'Fabric', return a more descriptive form of the label by replacing 'Fabric' with 'ExpensiveFabric'. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, UserLabel, replace(UserLabel,'Fabric','ExpensiveFabric') ModifiedLabel FROM bis.Element WHERE instr(UserLabel,'Fabric') > ``` +> The example uses the SQLite functions [replace](https://www.sqlite.org/lang_corefunc.html#replace) to replace the substring 'Plant' in the code and @@ -264,9 +296,11 @@ Note, that the `instr` function can be replaced by using the standard SQL `LIKE` > *Goal:* For all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s whose userlabel contains the string 'Fabric', return a more descriptive form of the label by replacing 'Fabric' with 'ExpensiveFabric'. > > *ECSQL* +> > ```sql > SELECT ECInstanceId, UserLabel, replace(UserLabel,'Fabric','ExpensiveFabric') ModifiedLabel FROM bis.Element WHERE UserLabel LIKE '%Fabric%' > ``` +> --- diff --git a/docs/learning/ECSQLTutorial/Joins.md b/docs/learning/ECSQLTutorial/Joins.md index db0164f90a63..98a6da485a34 100644 --- a/docs/learning/ECSQLTutorial/Joins.md +++ b/docs/learning/ECSQLTutorial/Joins.md @@ -16,9 +16,11 @@ Property | Description > *Goal:* Return the child [Element](../../bis/domains/BisCore.ecschema.md#element)s (id and class id) of the parent [Element](../../bis/domains/BisCore.ecschema.md#element) 0x30000000048 > > *ECSQL* +> > ```sql > SELECT TargetECInstanceId ChildId, TargetECClassId ChildClassId FROM bis.ElementOwnsChildElements WHERE SourceECInstanceId=0x200000000c7 > ``` +> Like any ECClass, ECRelationshipClasses abstract away how they are actually persisted in the database. When working with plain database and SQL you need to know that. This usually depends on the cardinality of the relationship. For example M:N relationships (also known as *many to many*) require a separate link table which persists the pairs of related instances. For 1:N relationhips (also known as *one to many*) though, the id of the related instance is usually persisted as foreign key in the child table directly. **For ECRelationshipClasses you do not need to know that.** @@ -70,9 +72,11 @@ As explained above using navigation properties instead of joins is preferred. So > *Goal:* Return the [Model](../../bis/domains/BisCore.ecschema.md#model) that contains the [Element](../../bis/domains/BisCore.ecschema.md#element) with code 'Sheets'. > > *ECSQL* +> > ```sql > SELECT CodeValue, Model FROM bis.Element WHERE CodeValue = 'Sheets' > ``` +> Note that the above ECSQL implies to navigate from the [Element](../../bis/domains/BisCore.ecschema.md#element) to the [Model](../../bis/domains/BisCore.ecschema.md#model) ECClass using the ECRelationshipClass [ModelContainsElements](../../bis/domains/BisCore.ecschema.md#modelcontainselements). But none of that has to be expressed in the ECSQL. It is all hidden behind the navigation property and makes the ECSQL straight-forward. @@ -84,9 +88,11 @@ The following ECSQL is the same as above but uses joins instead of the navigatio > *Goal:* Return the [Model](../../bis/domains/BisCore.ecschema.md#model) that contains the [Element](../../bis/domains/BisCore.ecschema.md#element) with code containing 'Sheets'. > > *ECSQL* +> > ```sql > SELECT rel.SourceECInstanceId ModelId FROM bis.ModelContainsElements rel JOIN bis.Element ON rel.TargetECInstanceId=Element.ECInstanceId WHERE Element.CodeValue='Sheets' > ``` +> If you want to return something else than just the id of the related instance, you can still use the navigation property but you need a join to bring in the related instance's class. @@ -96,9 +102,11 @@ If you want to return something else than just the id of the related instance, y > *Goal:* Return the id, the modeled element and the parent model of the [Model](../../bis/domains/BisCore.ecschema.md#model) that contains the [Element](../../bis/domains/BisCore.ecschema.md#element) with code 'Cut'. > > *ECSQL* +> > ```sql > SELECT Model.ECInstanceId,Model.ModeledElement.Id ModeledElementId,Model.ParentModel.Id ParentModelId FROM bis.Model JOIN bis.Element ON Element.Model.Id=Model.ECInstanceId WHERE Element.CodeValue='Cut' > ``` +> Again for the purpose of learning, the same ECSQL expressed with relationship classes instead of navigation properties looks like this. @@ -108,11 +116,13 @@ Again for the purpose of learning, the same ECSQL expressed with relationship cl > *Goal:* Return the id, the modeled element and the parent model of the [Model](../../bis/domains/BisCore.ecschema.md#model) that contains the [Element](../../bis/domains/BisCore.ecschema.md#element) with code 'Cut'. > > *ECSQL* +> > ```sql > SELECT Model.ECInstanceId,Model.ModeledElement.Id ModeledElementId,Model.ParentModel.Id ParentModelId FROM bis.Element JOIN bis.ModelContainsElements rel ON Element.ECInstanceId=rel.TargetECInstanceId JOIN bis.Model ON rel.SourceECInstanceId=Model.ECInstanceId WHERE Element.CodeValue='Cut' > ``` +> --- -[**< Previous**](./ECSQLDataTypes.md)   |   [**Next >**](./PolymorphicQueries.md) \ No newline at end of file +[**< Previous**](./ECSQLDataTypes.md)   |   [**Next >**](./PolymorphicQueries.md) diff --git a/docs/learning/ECSQLTutorial/KeyToECSQL.md b/docs/learning/ECSQLTutorial/KeyToECSQL.md index 5705298e841a..e9c202511dd0 100644 --- a/docs/learning/ECSQLTutorial/KeyToECSQL.md +++ b/docs/learning/ECSQLTutorial/KeyToECSQL.md @@ -27,9 +27,11 @@ As you can see, there is **no syntactical difference** between ECSQL and SQL in > *Goal:* Find out how many [Element](../../bis/domains/BisCore.ecschema.md#element)s there are in the iModel. > > *ECSQL* +> > ```sql > SELECT count(*) FROM bis.Element > ``` +> There is a **semantic** difference however: ECSQL targets the **business data model**, i.e. your domain's ECSchema, whereas SQL targets the **database's schema**. diff --git a/docs/learning/ECSQLTutorial/MetaQueries.md b/docs/learning/ECSQLTutorial/MetaQueries.md index 850f86187339..49b1586552e6 100644 --- a/docs/learning/ECSQLTutorial/MetaQueries.md +++ b/docs/learning/ECSQLTutorial/MetaQueries.md @@ -7,9 +7,11 @@ Every iModel includes the [ECDbMeta](../ECDbMeta.ecschema.md) ECSchema. It expos > *Goal:* Return the name, alias and version of all [schemas](../ECDbMeta.ecschema.md#ecschemadef) in the iModel > > *ECSQL* +> > ```sql > SELECT Name, Alias, VersionMajor, VersionWrite, VersionMinor FROM meta.ECSchemaDef ORDER BY Name > ``` +> --- @@ -19,9 +21,11 @@ Every iModel includes the [ECDbMeta](../ECDbMeta.ecschema.md) ECSchema. It expos > *Goal:* Return the properties and their types for the [Element](../../bis/domains/BisCore.ecschema.md#element) class > > *ECSQL* +> > ```sql > SELECT p.Name from meta.ECPropertyDef p JOIN meta.ECClassDef c ON c.ECInstanceId=p.Class.Id WHERE c.Name='Element' ORDER BY p.Ordinal > ``` +> Note the `ORDER BY` clause in the previous example. The property `Ordinal` of the [ECPropertyDef](../ECDbMeta.ecschema.md#ecpropertydef) class contains the position of the property in the class as it was originally defined. @@ -33,9 +37,11 @@ Another advantage of accessing the schemas via ECSQL is that you can combine tha > *Goal:* Return only [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s in the iModel which are of the subclass 'PhysicalObject' or 'LightLocation'. > > *ECSQL* +> > ```sql > SELECT class.Name ClassName, element.ECInstanceId ElementId, element.UserLabel FROM bis.SpatialElement element JOIN meta.ECClassDef class ON element.ECClassId=class.ECInstanceId WHERE class.Name IN ('PhysicalObject','LightLocation') > ``` +> Of course, the ECSQL is not precise yet because the class names are only unique within a schema. If there @@ -46,11 +52,13 @@ were a `Building` subclass in another schema, those instances would also be retu > *Goal:* Return only [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s in the iModel which are of the subclass 'PhysicalObject' from the schema 'Generic'. > > *ECSQL* +> > ```sql > SELECT class.Name ClassName, element.ECInstanceId ElementId, element.UserLabel FROM bis.SpatialElement element JOIN meta.ECClassDef class ON element.ECClassId=class.ECInstanceId JOIN meta.ECSchemaDef schema ON schema.ECInstanceId=class.Schema.Id WHERE schema.Name = 'Generic' AND class.Name IN ('PhysicalObject') > ``` +> --- -[**< Previous**](./SpatialQueries.md)   |   [**Next >**](./ChangeSummaryQueries.md) \ No newline at end of file +[**< Previous**](./SpatialQueries.md)   |   [**Next >**](./ChangeSummaryQueries.md) diff --git a/docs/learning/ECSQLTutorial/PolymorphicQueries.md b/docs/learning/ECSQLTutorial/PolymorphicQueries.md index b6e5a57187aa..33076c8302b4 100644 --- a/docs/learning/ECSQLTutorial/PolymorphicQueries.md +++ b/docs/learning/ECSQLTutorial/PolymorphicQueries.md @@ -11,9 +11,11 @@ We begin the lesson by using a simple ECSQL similar to the ones used at the begi > *Goal:* Return the UserLabel and class id of all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s. > > *ECSQL* +> > ```sql > SELECT UserLabel, ECClassId FROM bis.SpatialElement > ``` +> This example illustrates that polymorphism is pretty obvious. All examples throughout the tutorial up to here were polymorphic queries, and we did not have to mention or even explain it. It has worked intuitively. If we now take a closer look at what the ECSQL does, you can notice this: @@ -29,9 +31,11 @@ Now let's turn the query into a non-polymorphic one. > *Goal:* Return the code and class id of instances of only the [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement) class > > *ECSQL* +> > ```sql > SELECT CodeValue, ECClassId FROM ONLY bis.SpatialElement > ``` +> As expected the query does not return anything, because [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement) is an abstract class, and hence cannot have any instances. It is more meaningful to query against a non-abstract class. @@ -41,9 +45,11 @@ As expected the query does not return anything, because [SpatialElement](../../b > *Goal:* Return the UserLabel of instances of only the Generic.PhysicalObject class (which is a subclass of [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)) > > *ECSQL* +> > ```sql > SELECT ECInstanceid, UserLabel FROM ONLY Generic.PhysicalObject > ``` +> Let's go back to explore more how to work with the ECClassId to tell between subclasses of a polymorphic query. @@ -53,9 +59,11 @@ Let's go back to explore more how to work with the ECClassId to tell between sub > *Goal:* Return the userlabel and class id of all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that are either between ecclassid 0 and 200. > > *ECSQL* +> > ```sql > SELECT UserLabel, ECClassId FROM bis.SpatialElement WHERE ECClassId BETWEEN 0 AND 200 > ``` +> As usually the class ids are not known, you need to look them up first. You can do so by joining to the [ECDbMeta ECSchema](../ECDbMeta.ecschema.md). This allows you to specify the subclasses by name rather than by id. The [ECDbMeta ECSchema](../ECDbMeta.ecschema.md) is covered in more detail in the advanced lesson about [Meta queries](./MetaQueries.md). @@ -65,9 +73,11 @@ As usually the class ids are not known, you need to look them up first. You can > *Goal:* Return the UserLabel and class id of all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that are either 'LightLocation' or 'PhysicalObject' classes. > > *ECSQL* +> > ```sql > SELECT SpatialElement.UserLabel, SpatialElement.ECClassId, ECClassDef.Name FROM bis.SpatialElement JOIN meta.ECClassDef ON SpatialElement.ECClassId=ECClassDef.ECInstanceId WHERE ECClassDef.Name IN ('LightLocation','PhysicalObject') > ``` +> The following shows how you can perform simple statistics on the distribution of instances across the [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement) subclasses. @@ -77,11 +87,13 @@ The following shows how you can perform simple statistics on the distribution of > *Goal:* Return Element count per [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement) subclass for all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s in the iModel. > > *ECSQL* +> > ```sql > SELECT ECClassId, count(*) ElementCount FROM bis.SpatialElement GROUP BY ECClassId > ``` +> --- -[**< Previous**](./Joins.md)   |   [**Next >**](./SpatialQueries.md) \ No newline at end of file +[**< Previous**](./Joins.md)   |   [**Next >**](./SpatialQueries.md) diff --git a/docs/learning/ECSQLTutorial/SpatialQueries.md b/docs/learning/ECSQLTutorial/SpatialQueries.md index b1ece737e8f3..3c2feae55e26 100644 --- a/docs/learning/ECSQLTutorial/SpatialQueries.md +++ b/docs/learning/ECSQLTutorial/SpatialQueries.md @@ -9,9 +9,11 @@ The index is exposed to ECSQL via the ECClass [BisCore.SpatialIndex](../../bis/d > *Goal:* Return all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s that are contained or overlap a cube defined by the minimum coordinate (0, 0, 0) and maximum coordinate (415|120|15). > > *ECSQL* +> > ```sql > SELECT e.ECInstanceId, e.UserLabel, i.MinX, i.MinY, i.MinZ, i.MaxX, i.MaxY, i.MaxZ FROM bis.SpatialElement e JOIN bis.SpatialIndex i ON e.ECInstanceId=i.ECInstanceId WHERE i.MinX<=415 AND i.MinY<=120 AND i.MinZ<=15 AND i.MaxX >= 0 AND i.MaxY >= 0 AND i.MaxZ >= 0 > ``` +> For more complex spatial criteria the `MATCH` keyword together with the special built-in spatial index matching function `iModel_spatial_overlap_aabb` is used. The MATCH clause acts like a sub-selection that generates a set of ECInstanceIds, which it gathers from the spatial index rows that match the specified criteria. @@ -25,10 +27,13 @@ See also other [ECSQL built-in geometry functions](../GeometrySqlFuncs.md) which > *Goal:* Return all [SpatialElement](../../bis/domains/BisCore.ecschema.md#spatialelement)s which overlap the [Space](./MyDomain.ecschema.md#space) with id 0x1000000001f and which are in the [Category](../../bis/domains/BisCore.ecschema.md#category) with id 0x1000000000a. > > *ECSQL* +> > ```sql > SELECT e.ECInstanceId, e.CodeValue FROM bis.SpatialElement e JOIN bis.SpatialIndex i ON e.ECInstanceId=i.ECInstanceId WHERE i.ECInstanceId MATCH iModel_spatial_overlap_aabb(?) AND e.Category.Id=0x1000000000a > ``` +> > *Sample code* +> > ```ts > const spaceElement: SpatialElement = iModelDb.elements.getElement("0x1000000001f") as SpatialElement; > @@ -43,6 +48,7 @@ See also other [ECSQL built-in geometry functions](../GeometrySqlFuncs.md) which >``` > > *Result* +> > ```ts > { id : "0x1000000001e", className: "MyDomain.Story", codeValue: "A-G" } > { id : "0x10000000023", className: "MyDomain.Story", codeValue: "A-1" } @@ -50,4 +56,4 @@ See also other [ECSQL built-in geometry functions](../GeometrySqlFuncs.md) which --- -[**< Previous**](./PolymorphicQueries.md)   |   [**Next >**](./MetaQueries.md) \ No newline at end of file +[**< Previous**](./PolymorphicQueries.md)   |   [**Next >**](./MetaQueries.md) diff --git a/docs/learning/ECSQLTutorial/TypeFilter.md b/docs/learning/ECSQLTutorial/TypeFilter.md index 88ae9e538877..249d34bed285 100644 --- a/docs/learning/ECSQLTutorial/TypeFilter.md +++ b/docs/learning/ECSQLTutorial/TypeFilter.md @@ -14,9 +14,11 @@ ECSQL allows filters by type > *Goal:* Returns elements only if it's either of type GeometricElement3d, GeometricElement2d, or any of their sub-classes > > *ECSQL* +> > ```sql > SELECT * FROM bis.Element WHERE ECClassId IS (bis.GeometricElement3d, bis.GeometricElement2d > ``` +> --- @@ -26,9 +28,11 @@ ECSQL allows filters by type > *Goal:* Returns elements only if it's exactly of the specified types - sub-classes are not included > > *ECSQL* +> > ```sql > SELECT * FROM bis.Element WHERE ECClassId IS (ONLY Generic.PhysicalObject, ONLY BisCore.LightLocation) > ``` +> --- @@ -38,9 +42,11 @@ ECSQL allows filters by type > *Goal:* Inverts the selection set > > *ECSQL* +> > ```sql > SELECT * FROM bis.Element WHERE ECClassId IS NOT (ONLY Generic.PhysicalObject, ONLY BisCore.LightLocation) > ``` +> --- diff --git a/docs/learning/ECSQLTutorial/index.md b/docs/learning/ECSQLTutorial/index.md index b82db436058c..c6bf54c7f1a1 100644 --- a/docs/learning/ECSQLTutorial/index.md +++ b/docs/learning/ECSQLTutorial/index.md @@ -39,7 +39,7 @@ This also enables you to experiment more with ECSQL by modifying the tutorial's If you want to follow along with your own iModel: -1. Launch the console at https://imodelconsole.bentley.com +1. Launch the console at 2. Authenticate with your iTwin credentials. 3. Open your iModel by clicking on the iModels in the table @@ -56,6 +56,7 @@ Or simply use the provided sample below: > **Try it yourself** > > *ECSQL* +> > ```sql > SELECT * FROM bis.Element > ``` @@ -64,18 +65,18 @@ Or simply use the provided sample below: ## Tutorial Overview -* [Lesson 1: Key to ECSQL](./KeyToECSQL.md) -* [Lesson 2: The first examples](./FirstExamples.md) -* [Lesson 3: ECSQL Data Types](./ECSQLDataTypes.md) -* [Lesson 4: Relationships and Joins](./Joins.md) -* [Lesson 5: Class Polymorphism](./PolymorphicQueries.md) -* [Lesson 6: Spatial Queries](./SpatialQueries.md) -* [Lesson 7: Meta Queries - Querying ECSchemas](./MetaQueries.md) -* [Lesson 8: Querying Change Summaries](./ChangeSummaryQueries.md) -* [Lesson 9: Type Filter](./TypeFilter.md) -* [Lesson 10: Conditional Expressions](./ConditionalExpr.md) -* [Lesson 11: Built-In functions](./BuiltInFunctions.md) +- [Lesson 1: Key to ECSQL](./KeyToECSQL.md) +- [Lesson 2: The first examples](./FirstExamples.md) +- [Lesson 3: ECSQL Data Types](./ECSQLDataTypes.md) +- [Lesson 4: Relationships and Joins](./Joins.md) +- [Lesson 5: Class Polymorphism](./PolymorphicQueries.md) +- [Lesson 6: Spatial Queries](./SpatialQueries.md) +- [Lesson 7: Meta Queries - Querying ECSchemas](./MetaQueries.md) +- [Lesson 8: Querying Change Summaries](./ChangeSummaryQueries.md) +- [Lesson 9: Type Filter](./TypeFilter.md) +- [Lesson 10: Conditional Expressions](./ConditionalExpr.md) +- [Lesson 11: Built-In functions](./BuiltInFunctions.md) --- -[**Next >**](./KeyToECSQL.md) \ No newline at end of file +[**Next >**](./KeyToECSQL.md) diff --git a/docs/learning/PackageAndDeployToTheWeb.md b/docs/learning/PackageAndDeployToTheWeb.md index 6092c177d864..4a851808a39d 100644 --- a/docs/learning/PackageAndDeployToTheWeb.md +++ b/docs/learning/PackageAndDeployToTheWeb.md @@ -2,7 +2,7 @@ An iModel.js Web app is based on standard Web technology, and so you can use any Web or cloud tools to package, deploy, and administer it. iModel.js applications can be: -* hosted on any cloud service -* deployed using any [cloud deployment model](https://en.wikipedia.org/wiki/Cloud_computing#Deployment_models) -* packaged with any container tool (e.g. [Docker](https://www.docker.com/)) -* managed with any orchestration system (e.g. [Kubernetes](https://kubernetes.io/)) +- hosted on any cloud service +- deployed using any [cloud deployment model](https://en.wikipedia.org/wiki/Cloud_computing#Deployment_models) +- packaged with any container tool (e.g. [Docker](https://www.docker.com/)) +- managed with any orchestration system (e.g. [Kubernetes](https://kubernetes.io/)) diff --git a/docs/learning/RpcInterface.md b/docs/learning/RpcInterface.md index 4fd46b1560d2..4b1e46d55271 100644 --- a/docs/learning/RpcInterface.md +++ b/docs/learning/RpcInterface.md @@ -4,19 +4,19 @@ This article discusses RPC communication in iModel.js. See also [RPC vs IPC](./R Table of Contents: -* [Overview](#overview) -* Implementing RpcInterfaces - * [RpcInterfaces are Typescript Classes](#rpcinterfaces-are-typescript-classes) - * [RpcInterface Performance](#rpcinterface-performance) - * [Define the Interface](#define-the-interface) - * [Client Stub](#client-stub) - * [Server Implementation](#server-implementation) -* Configuring RpcInterfaces - * [Server-side Configuration](#server-side-configuration) - * [Client-side Configuration](#client-side-configuration) -* [Serve the Interfaces](#serve-the-interfaces) -* [Asynchronous Nature of RpcInterfaces](#asynchronous-nature-of-rpcinterfaces) -* [Logging and ActivityIds](#logging-and-activityids) +- [Overview](#overview) +- Implementing RpcInterfaces + - [RpcInterfaces are Typescript Classes](#rpcinterfaces-are-typescript-classes) + - [RpcInterface Performance](#rpcinterface-performance) + - [Define the Interface](#define-the-interface) + - [Client Stub](#client-stub) + - [Server Implementation](#server-implementation) +- Configuring RpcInterfaces + - [Server-side Configuration](#server-side-configuration) + - [Client-side Configuration](#client-side-configuration) +- [Serve the Interfaces](#serve-the-interfaces) +- [Asynchronous Nature of RpcInterfaces](#asynchronous-nature-of-rpcinterfaces) +- [Logging and ActivityIds](#logging-and-activityids) ## Overview @@ -26,9 +26,9 @@ As described in the [software architecture overview](./SoftwareArchitecture.md), The diagram above shows an app frontend requesting operations from some backend. The terms *client* and *server* specify the two *roles* of an RpcInterface: -* *client* -- the code that runs on the frontend, and calls methods on an RpcInterface. +- *client* -- the code that runs on the frontend, and calls methods on an RpcInterface. -* *server* -- the code that runs on the backend, and implements the RpcInterface. +- *server* -- the code that runs on the backend, and implements the RpcInterface. Classes that derive from [RpcInterface]($common) define a set of operations implemented by a server, callable from a client. diff --git a/docs/learning/WriteAWebAgent.md b/docs/learning/WriteAWebAgent.md index 484074a84ec7..11c8d1354e34 100644 --- a/docs/learning/WriteAWebAgent.md +++ b/docs/learning/WriteAWebAgent.md @@ -10,5 +10,5 @@ Typically, a Web Agent will not implement and expose RpcInterfaces, although it To develop a Web Agent, you will also: -* Register for iModelHub events -* [Package and deploy to the Web](./PackageAndDeployToTheWeb.md) +- Register for iModelHub events +- [Package and deploy to the Web](./PackageAndDeployToTheWeb.md) diff --git a/docs/learning/WriteAWebService.md b/docs/learning/WriteAWebService.md index 72cc113bb2d8..766b94ffa93a 100644 --- a/docs/learning/WriteAWebService.md +++ b/docs/learning/WriteAWebService.md @@ -6,7 +6,7 @@ See [how to write backend code](./backend/index.md). To develop a Web Service, you will also: -* [Write a simple Web server](./RpcInterface.md#serve-the-interfaces) -* [Package and deploy to the Web](./PackageAndDeployToTheWeb.md) +- [Write a simple Web server](./RpcInterface.md#serve-the-interfaces) +- [Package and deploy to the Web](./PackageAndDeployToTheWeb.md) Note that a service typically does not open an iModel on its own initiative. Instead, normally, a client of the service will ask the service to open an iModel, and then the client will pass the resulting [IModelRpcProps]($common) to methods of the service. The service should therefore always initialize the [IModelReadRpcInterface]($common). diff --git a/docs/learning/WriteAnInteractiveDesktopApp.md b/docs/learning/WriteAnInteractiveDesktopApp.md index b547a379cf35..b86dc95f56d8 100644 --- a/docs/learning/WriteAnInteractiveDesktopApp.md +++ b/docs/learning/WriteAnInteractiveDesktopApp.md @@ -12,9 +12,9 @@ Any interactive app can be configured as a desktop app. A small additional effor You must write an [Electron-specific main](../learning/AppTailoring.md) to do the following: -* [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) for Electron. -* Integrate with Electron IPC -* Identify the main html page. +- [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) for Electron. +- Integrate with Electron IPC +- Identify the main html page. ## 3. Package and Deploy diff --git a/docs/learning/WriteAnInteractiveMobileApp.md b/docs/learning/WriteAnInteractiveMobileApp.md index 03dbf8985f59..0a33d1be7255 100644 --- a/docs/learning/WriteAnInteractiveMobileApp.md +++ b/docs/learning/WriteAnInteractiveMobileApp.md @@ -10,9 +10,9 @@ Any interactive app can be configured as a mobile app. A small additional effort You must write a [mobile-specific main](../learning/AppTailoring.md) to do the following: -* [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) for mobile. -* [Tailor the GUI](../learning/AppTailoring.md#change-the-gui) to suit the target mobile devices. -* [Detect and integrate platform-specific mobile functionality](../learning/AppTailoring.md#use-platform-specific-modules). +- [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) for mobile. +- [Tailor the GUI](../learning/AppTailoring.md#change-the-gui) to suit the target mobile devices. +- [Detect and integrate platform-specific mobile functionality](../learning/AppTailoring.md#use-platform-specific-modules). ## 3. Package and Deploy diff --git a/docs/learning/WriteAnInteractiveWebApp.md b/docs/learning/WriteAnInteractiveWebApp.md index 9a06694c7611..d09533265af8 100644 --- a/docs/learning/WriteAnInteractiveWebApp.md +++ b/docs/learning/WriteAnInteractiveWebApp.md @@ -16,16 +16,16 @@ You must write a [Web-specific main](../learning/AppTailoring.md). That is where The Web-specific main must [configure RpcInterfaces](./RpcInterface.md#client-side-configuration) in order to access backends and services over the Web. There are several options, depending on how you design and deploy your app: -* *Frontend-only app* - This style of app uses only pre-existing backends and services. A `uriPrefix` is required for configuring each server. -* *Simple app* - This style of app has its own backend, and the backend serves the frontend. No uriPrefix is required when configuring the app's own backend server. A uriPrefix is required for any other, remote backend server that the app may use. -* Frontend and backend deployed separately - This style of app has its own backend, but the backend and frontend are deployed separately. A `uriPrefix` is required for configuring the app's own backend server and for any other server that it may use. +- *Frontend-only app* - This style of app uses only pre-existing backends and services. A `uriPrefix` is required for configuring each server. +- *Simple app* - This style of app has its own backend, and the backend serves the frontend. No uriPrefix is required when configuring the app's own backend server. A uriPrefix is required for any other, remote backend server that the app may use. +- Frontend and backend deployed separately - This style of app has its own backend, but the backend and frontend are deployed separately. A `uriPrefix` is required for configuring the app's own backend server and for any other server that it may use. ### Backend If the app has a custom backend, you must write a [Web-specific main](../learning/AppTailoring.md) to do the following: -* [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) to serve clients over the Web. -* [Write a simple Web server](./RpcInterface.md#serve-the-interfaces) to serve the backend interfaces. +- [Configure the backend interfaces](./RpcInterface.md#configure-interfaces) to serve clients over the Web. +- [Write a simple Web server](./RpcInterface.md#serve-the-interfaces) to serve the backend interfaces. ## 3. Package and Deploy diff --git a/docs/learning/backend/ConcurrencyControl.md b/docs/learning/backend/ConcurrencyControl.md index 111e7e8ce63b..92fac663fb2e 100644 --- a/docs/learning/backend/ConcurrencyControl.md +++ b/docs/learning/backend/ConcurrencyControl.md @@ -156,10 +156,10 @@ Call [ConcurrencyControl.CodesManager.reserve]($backend) to reserve Codes before ### Acquiring locks and/or codes pessimistically -1. Call [ConcurrencyControl.LocksManager.lockModels]($backend) to lock models preemptively, if you wish. -1. Call [ConcurrencyControl.requestResources]($backend) on the elements and/or models that you intend to insert, update, of delete. This method will request the locks and/or codes that the planned local operations will require. It may send a request to iModelHub. -1. If the request fails, cancel the local operation. -1. If the request succeeds, go ahead with the local operation, make the planned local changes, and then call [IModelDb.saveChanges]($backend). +1. Call [ConcurrencyControl.LocksManager.lockModels]($backend) to lock models preemptively, if you wish. +1. Call [ConcurrencyControl.requestResources]($backend) on the elements and/or models that you intend to insert, update, of delete. This method will request the locks and/or codes that the planned local operations will require. It may send a request to iModelHub. +1. If the request fails, cancel the local operation. +1. If the request succeeds, go ahead with the local operation, make the planned local changes, and then call [IModelDb.saveChanges]($backend). This approach is the safest way to avoid conflicts. It requires that the app must plan ahead before making local changes. @@ -170,10 +170,10 @@ Note that sending a request to iModelHub is a relatively expensive operation. Th ### Acquiring locks and/or codes optimistically or in bulk mode -1. Insert or update models and elements. -1. Call [ConcurrencyControl.request]($backend) to request the codes that those local operations require. -1. If the request fails, call [IModelDb.abandonChanges]($backend) to roll back the local transaction. -1. If the request succeeds, call [IModelDb.saveChanges]($backend) to commit the local transaction. +1. Insert or update models and elements. +1. Call [ConcurrencyControl.request]($backend) to request the codes that those local operations require. +1. If the request fails, call [IModelDb.abandonChanges]($backend) to roll back the local transaction. +1. If the request succeeds, call [IModelDb.saveChanges]($backend) to commit the local transaction. The optimistic approach is simpler than using the pessimistic approach, but it carries the risk that you must abandon all of your changes in case of a locking or code-reservation conflict. Use this approach only if you know that your changes are isolated such that conflicts are unlikely. diff --git a/docs/learning/backend/CrashReporting.md b/docs/learning/backend/CrashReporting.md index b8583306e225..55cea96f6db7 100644 --- a/docs/learning/backend/CrashReporting.md +++ b/docs/learning/backend/CrashReporting.md @@ -25,7 +25,7 @@ To opt into crash dumps, the backend program must: ## Unhandled Exceptions and Other Fatal Errors -An unhandled exception or a fatal error such as running out of memory will cause the backend program to terminate prematurely. The backend program can enable the "node-report" module to generate a report in case of these events. A node-report file is a human-readable text file that includes native-code and Javascript call stacks, plus other information about the state of the session. See https://www.npmjs.com/package/node-report for details. +An unhandled exception or a fatal error such as running out of memory will cause the backend program to terminate prematurely. The backend program can enable the "node-report" module to generate a report in case of these events. A node-report file is a human-readable text file that includes native-code and Javascript call stacks, plus other information about the state of the session. See for details. To opt into node-report, the backend program must: @@ -45,12 +45,12 @@ If you set [IModelHostConfiguration]($backend).crashReportingConfig.uploadToBent ## Example Code ```ts - // Enable both crash dumps and node-report. Write reports to d://customdumpdir on Windows - hostConfig.crashReportingConfig = { - crashDir: (process.platform == "win32")? "d:\\customdumpdir": "/tmp"; - writeDumpsToCrashDir: true, - writeNodeReportsToCrashDir: true, - }; - - IModelHost.startup(hostConfig); +// Enable both crash dumps and node-report. Write reports to d://customdumpdir on Windows +hostConfig.crashReportingConfig = { + crashDir: (process.platform == "win32")? "d:\\customdumpdir": "/tmp"; + writeDumpsToCrashDir: true, + writeNodeReportsToCrashDir: true, +}; + +IModelHost.startup(hostConfig); ``` diff --git a/docs/learning/backend/ECSQL-queries.md b/docs/learning/backend/ECSQL-queries.md index 3b5dadbaff79..f29973cb2e1b 100644 --- a/docs/learning/backend/ECSQL-queries.md +++ b/docs/learning/backend/ECSQL-queries.md @@ -4,25 +4,25 @@ The following ECSQL select statements are examples of useful queries that an app ## Select Elements in a particular Model -``` ts +```ts [[include:ECSQL-backend-queries.select-elements-in-model]] ``` ## Select Top-Level Elements in a particular Model -``` ts +```ts [[include:ECSQL-backend-queries.select-top-level-elements-in-model]] ``` ## Select Child Elements -``` ts +```ts [[include:ECSQL-backend-queries.select-child-elements]] ``` ## Look up element by code value -``` ts +```ts [[include:ECSQL-backend-queries.select-element-by-code-value]] ``` diff --git a/docs/learning/backend/IModelDb.md b/docs/learning/backend/IModelDb.md index df412a9f1fea..37fc56a606fd 100644 --- a/docs/learning/backend/IModelDb.md +++ b/docs/learning/backend/IModelDb.md @@ -27,13 +27,15 @@ Use [SnapshotDb.close]($backend) to close the *snapshot* iModel. Every now and then the schemas in the iModel may become incompatible with newer versions of the software. In these cases it may be recommended, and sometimes even mandatory to upgrade the schemas in the iModel before it can be opened. Note that whether an upgrade is mandatory may depend on if the model is to be opened ReadOnly or ReadWrite - the requirements for the latter are more stringent. There are two kinds of schemas that typically get upgraded: -* [Domain schemas](../../bis/intro/schemas-domains) - the ECSchema-s that define the information for specific [Domains](../../bis/intro/glossary/#domain) -* *Profile schemas* - the Schemas of database tables that are either not mapped to domain schemas, or are otherwise used to store meta-data about the mapping of database tables to domain schemas. + +- [Domain schemas](../../bis/intro/schemas-domains) - the ECSchema-s that define the information for specific [Domains](../../bis/intro/glossary/#domain) +- *Profile schemas* - the Schemas of database tables that are either not mapped to domain schemas, or are otherwise used to store meta-data about the mapping of database tables to domain schemas. The iModel.js API provides for a way to validate (check compatibility) and upgrade all the schemas in the iModel. To upgrade - -* Download a local copy of the iModel as a briefcase with [BriefcaseManager.downloadBriefcase]($backend) -* Call [BriefcaseDb.validateSchemas]($backend) to validate the schemas in the iModel. -* Call [BriefcaseDb.upgradeSchemas]($backend) to upgrade schemas - the upgrade process involves the following steps first for the profile upgrade, and then for the domain schema upgrade: + +- Download a local copy of the iModel as a briefcase with [BriefcaseManager.downloadBriefcase]($backend) +- Call [BriefcaseDb.validateSchemas]($backend) to validate the schemas in the iModel. +- Call [BriefcaseDb.upgradeSchemas]($backend) to upgrade schemas - the upgrade process involves the following steps first for the profile upgrade, and then for the domain schema upgrade: - acquiring a schema lock to avoid concurrent schema changes by different users - opening the local briefcase - making the necessary schema changes to the briefcase diff --git a/docs/learning/backend/IModelDbReadwrite.md b/docs/learning/backend/IModelDbReadwrite.md index e13260d0bb6b..fb3518a2fc9b 100644 --- a/docs/learning/backend/IModelDbReadwrite.md +++ b/docs/learning/backend/IModelDbReadwrite.md @@ -4,9 +4,9 @@ An IModelDb also serves as a staging area where a [backend](../Glossary.md#backe A backend can make the following kinds of changes: -* [Create or update Elements](./CreateElements.md) -* [Create or update Models](./CreateModels.md) -* [Reserve Codes](./ReserveCodes.md) +- [Create or update Elements](./CreateElements.md) +- [Create or update Models](./CreateModels.md) +- [Reserve Codes](./ReserveCodes.md) Use [IModelDb.saveChanges]($backend) to commit changes locally. [IModelDb.txns]($backend) manages local transactions, it supports local undo/redo. diff --git a/docs/learning/backend/IModelHost.md b/docs/learning/backend/IModelHost.md index 43474e9f8a3b..e722b3cc7aac 100644 --- a/docs/learning/backend/IModelHost.md +++ b/docs/learning/backend/IModelHost.md @@ -8,6 +8,6 @@ A backend may need to set [IModelHostConfiguration.appAssetsDir]($backend) to id *Example:* - ```ts - [[include:IModelHost.startup]] - ``` +```ts +[[include:IModelHost.startup]] +``` diff --git a/docs/learning/backend/ManagingClientRequestContext.md b/docs/learning/backend/ManagingClientRequestContext.md index adc67304beed..6cd0984667a1 100644 --- a/docs/learning/backend/ManagingClientRequestContext.md +++ b/docs/learning/backend/ManagingClientRequestContext.md @@ -6,13 +6,13 @@ Asynchronous backend methods must cooperate to propagate a request's [ActivityId Every `Promise`-returning functions *must*: -* Take an argument of type [ClientRequestContext]($bentley). -* Pass the input ClientRequestContext object to each Promise-returning method that it calls. -* Call the [ClientRequestContext.enter]($bentley) method on the input ClientRequestContext object: - * On its first line. - * Immediately following each call to `await`. - * Immediately upon catching an Error thrown by a rejected `await`. - * On the first line of a `.then` or a `.catch` callback that is invoked by a Promise. +- Take an argument of type [ClientRequestContext]($bentley). +- Pass the input ClientRequestContext object to each Promise-returning method that it calls. +- Call the [ClientRequestContext.enter]($bentley) method on the input ClientRequestContext object: + - On its first line. + - Immediately following each call to `await`. + - Immediately upon catching an Error thrown by a rejected `await`. + - On the first line of a `.then` or a `.catch` callback that is invoked by a Promise. A Promise-returning function must *not* call ClientRequestContext.current. @@ -32,14 +32,14 @@ There is one exception to the above rule for Promise-returning functions. An [Rp Examples of asynchronous functions that invoke callbacks are: -* setTimeout and setInterval -* XmlHttpRequest (if called in the backend) -* fs async functions (called only in non-portable backend code) +- setTimeout and setInterval +- XmlHttpRequest (if called in the backend) +- fs async functions (called only in non-portable backend code) If a callback does any logging or calls functions that do: -* Before invoking an asynchronous function, an app must ensure that the correct ClientRequestContext is assigned to a local variable in the scope that encloses the callback. -* The callback must, on its first line, call the ClientRequestContext.enter method on that local variable in the enclosing scope. +- Before invoking an asynchronous function, an app must ensure that the correct ClientRequestContext is assigned to a local variable in the scope that encloses the callback. +- The callback must, on its first line, call the ClientRequestContext.enter method on that local variable in the enclosing scope. There are two possible cases: diff --git a/docs/learning/backend/index.md b/docs/learning/backend/index.md index a1dc5fdfae0a..6a9cb2fcab2c 100644 --- a/docs/learning/backend/index.md +++ b/docs/learning/backend/index.md @@ -2,63 +2,62 @@ Backend code is the portion of an app that: -* Runs on a computer with a copy of an iModel -* Has access to the local file system -* Can use native libraries +- Runs on a computer with a copy of an iModel +- Has access to the local file system +- Can use native libraries A backend package can be a [service](../../learning/App.md#agents-and-services), an [agent](../../learning/App.md#agents-and-services), or an [app-specific backend](../../learning/App.md#app-backend). -* See the [app architecture overview](../../learning/SoftwareArchitecture.md) for how iModel.js apps are structured. -* See [iModel contents](./iModelContents.md) for guidance on whether a data type belongs in the iModel or should be stored in a separate repository. -* See [best practices](./BestPractices.md) for writing backend code. +- See the [app architecture overview](../../learning/SoftwareArchitecture.md) for how iModel.js apps are structured. +- See [iModel contents](./iModelContents.md) for guidance on whether a data type belongs in the iModel or should be stored in a separate repository. +- See [best practices](./BestPractices.md) for writing backend code. App backends require the `@bentley/imodeljs-backend` npm package. The [common packages](../common/index.md) will also be required. Please also note the [supported platforms](../SupportedPlatforms.md). These packages provide the following functions to support backend operations: -* Administration - * [IModelHost](./IModelHost.md) - * [Initialize Logging](../common/Logging.md) +- Administration + - [IModelHost](./IModelHost.md) + - [Initialize Logging](../common/Logging.md) -* IModelDb - * [Open an IModelDb](./IModelDb.md) - * [Synchronizing with iModelHub](./IModelDbSync.md) - * [Writing to an IModelDb](./IModelDbReadwrite.md) - * [Concurrency control](./ConcurrencyControl.md) - * [iModel Transformation and Data Exchange](./IModelTransformation.md) +- IModelDb + - [Open an IModelDb](./IModelDb.md) + - [Synchronizing with iModelHub](./IModelDbSync.md) + - [Writing to an IModelDb](./IModelDbReadwrite.md) + - [Concurrency control](./ConcurrencyControl.md) + - [iModel Transformation and Data Exchange](./IModelTransformation.md) -* Working with Schemas and Elements in TypeScript - * [Working with Schemas and Elements in TypeScript](./SchemasAndElementsInTypeScript.md) +- Working with Schemas and Elements in TypeScript + - [Working with Schemas and Elements in TypeScript](./SchemasAndElementsInTypeScript.md) -* Loading and Creating Elements, ElementAspects, and Models - * [Access Elements](./AccessElements.md) - * [Create Elements](./CreateElements.md) - * [Access ElementAspects](./AccessElementAspects.md) - * [Create ElementAspects](./CreateElementAspects.md) - * [Access Models](./AccessModels.md) - * [Create Models](./CreateModels.md) +- Loading and Creating Elements, ElementAspects, and Models + - [Access Elements](./AccessElements.md) + - [Create Elements](./CreateElements.md) + - [Access ElementAspects](./AccessElementAspects.md) + - [Create ElementAspects](./CreateElementAspects.md) + - [Access Models](./AccessModels.md) + - [Create Models](./CreateModels.md) -* ECSQL +- ECSQL + - [What is ECSQL?](../ECSQL.md) + - [Executing ECSQL statements](./ExecutingECSQL.md) + - [Code Examples](./ECSQLCodeExamples.md) + - [Frequently used ECSQL queries](./ECSQL-queries.md) - * [What is ECSQL?](../ECSQL.md) - * [Executing ECSQL statements](./ExecutingECSQL.md) - * [Code Examples](./ECSQLCodeExamples.md) - * [Frequently used ECSQL queries](./ECSQL-queries.md) +- Dealing with Codes + - [Reserve Codes](./ReserveCodes.md) -* Dealing with Codes - * [Reserve Codes](./ReserveCodes.md) - -* Change Summary - * [Change Summary Overview](../ChangeSummaries) +- Change Summary + - [Change Summary Overview](../ChangeSummaries) For services and app backends: -* Correlating backend operations with frontend Requests - * [Manage the ClientRequestContext](./ManagingClientRequestContext.md). +- Correlating backend operations with frontend Requests + - [Manage the ClientRequestContext](./ManagingClientRequestContext.md). -* Exposing the operations of the backend as RpcInterfaces - * [Define](../RpcInterface.md#define-the-interface) one or more RpcInterfaces. - * [Implement](../RpcInterface.md#server-implementation) the RpcInterfaces. - * [Configure](../RpcInterface.md#configure-interfaces) the RpcInterfaces. - * [Serve](../RpcInterface.md#serve-the-interfaces) the RpcInterfaces to clients. +- Exposing the operations of the backend as RpcInterfaces + - [Define](../RpcInterface.md#define-the-interface) one or more RpcInterfaces. + - [Implement](../RpcInterface.md#server-implementation) the RpcInterfaces. + - [Configure](../RpcInterface.md#configure-interfaces) the RpcInterfaces. + - [Serve](../RpcInterface.md#serve-the-interfaces) the RpcInterfaces to clients. diff --git a/docs/learning/clients/index.md b/docs/learning/clients/index.md index ca67fc300208..701218de02e5 100644 --- a/docs/learning/clients/index.md +++ b/docs/learning/clients/index.md @@ -4,15 +4,15 @@ The iModel.js library contains a set of packages that provide Typescript APIs fo The current iTwin Service client APIs are available in the following npm packages: -* [@bentley/context-registry-client](https://www.npmjs.com/package/@bentley/context-registry-client) - * ($context-registry-client) -* [@bentley/extension-client](https://www.npmjs.com/package/@bentley/extension-client) - * ($extension-client) -* [@bentley/imodelhub-client](https://www.npmjs.com/package/@bentley/imodelhub-client) - * ($imodelhub-client) -* [@bentley/itwin-client](https://www.npmjs.com/package/@bentley/itwin-client) - * ($itwin-client) -* [@bentley/product-settings-client](https://www.npmjs.com/package/@bentley/product-settings-client) - * ($product-settings-client) -* [@bentley/usage-logging-client](https://www.npmjs.com/package/@bentley/usage-logging-client) - * ($usage-logging-client) +- [@bentley/context-registry-client](https://www.npmjs.com/package/@bentley/context-registry-client) + - ($context-registry-client) +- [@bentley/extension-client](https://www.npmjs.com/package/@bentley/extension-client) + - ($extension-client) +- [@bentley/imodelhub-client](https://www.npmjs.com/package/@bentley/imodelhub-client) + - ($imodelhub-client) +- [@bentley/itwin-client](https://www.npmjs.com/package/@bentley/itwin-client) + - ($itwin-client) +- [@bentley/product-settings-client](https://www.npmjs.com/package/@bentley/product-settings-client) + - ($product-settings-client) +- [@bentley/usage-logging-client](https://www.npmjs.com/package/@bentley/usage-logging-client) + - ($usage-logging-client) diff --git a/docs/learning/common/GeometryStream.md b/docs/learning/common/GeometryStream.md index 15030a689726..328b77c2c3e5 100644 --- a/docs/learning/common/GeometryStream.md +++ b/docs/learning/common/GeometryStream.md @@ -6,35 +6,35 @@ Appearance related entries are all completely optional. The recommended approach Some appearance entries override the default SubCategoryAppearance, while others are for supplying additional appearance information that is not generally applicable to all geometry types and isn't represented in SubCategoryAppearance. The following entries are specific to setting the appearance of graphics in the GeometryStream: -* [GeometryAppearanceProps]($common) - * The presence of a GeometryAppearanceProps entry in the GeometryStreamProps array always signifies clearing all SubCategoryAppearance overrides, even when all values are undefined. - * Defined values, with the exception of GeometryAppearanceProps.geometryClass, override a corresponding SubCategoryAppearance value. - * The SubCategoryAppearance used for geometry entries that follow in the GeometryStreamProps array is determined by [GeometryAppearanceProps.subCategory]($common). Default SubCategory for GeometricElement's Category is used when undefined. +- [GeometryAppearanceProps]($common) + - The presence of a GeometryAppearanceProps entry in the GeometryStreamProps array always signifies clearing all SubCategoryAppearance overrides, even when all values are undefined. + - Defined values, with the exception of GeometryAppearanceProps.geometryClass, override a corresponding SubCategoryAppearance value. + - The SubCategoryAppearance used for geometry entries that follow in the GeometryStreamProps array is determined by [GeometryAppearanceProps.subCategory]($common). Default SubCategory for GeometricElement's Category is used when undefined. -* [LineStyle.ModifierProps]($common) - * Modifies the default appearance from the [LineStyle]($backend) definition element identified by [GeometryAppearanceProps.style]($common) or [SubCategoryAppearance.styleId]($common). +- [LineStyle.ModifierProps]($common) + - Modifies the default appearance from the [LineStyle]($backend) definition element identified by [GeometryAppearanceProps.style]($common) or [SubCategoryAppearance.styleId]($common). ![Linestyle](./stroked_ls.png "Example of stroked line styles") - * Add instance specific overrides (ex. defining up direction for style in 3d) for stroked line styles. Override stroke lengths, gap lengths, and stroke widths. - * Stroked line styles are only applicable to [IModelJson.CurvePrimitiveProps]($geometry) and [IModelJson.CurveCollectionProps]($geometry) entries; it does not apply to edges of non-region surfaces or solids. + - Add instance specific overrides (ex. defining up direction for style in 3d) for stroked line styles. Override stroke lengths, gap lengths, and stroke widths. + - Stroked line styles are only applicable to [IModelJson.CurvePrimitiveProps]($geometry) and [IModelJson.CurveCollectionProps]($geometry) entries; it does not apply to edges of non-region surfaces or solids. -* [AreaFillProps]($common) - * Add a gradient, background, opaque, or outline fill to the display of [IModelJson.PlanarRegionProps]($geometry) entries. Opaque fill can also be added to a [IModelJson.IndexedMeshProps]($geometry) entry. +- [AreaFillProps]($common) + - Add a gradient, background, opaque, or outline fill to the display of [IModelJson.PlanarRegionProps]($geometry) entries. Opaque fill can also be added to a [IModelJson.IndexedMeshProps]($geometry) entry. ![Fill](./fill_types.png "Example of types of fill") - * Fill is only applicable to views that have [ViewFlags.renderMode]($common) set to [RenderMode.Wireframe]($common). - * To be considered filled, [AreaFillProps.display]($common) must be defined to something other than [FillDisplay.Never]($common). - * If [AreaFillProps.display]($common) is defined as [FillDisplay.ByView]($common), the view's [ViewFlags.fill]($common) determines whether the geometry displays as filled. - * Planar regions always display as surfaces in non-Wireframe views regardless of the value for [FillDisplay]($common); they will however use the fill color as opposed to the line color when fill is specified. + - Fill is only applicable to views that have [ViewFlags.renderMode]($common) set to [RenderMode.Wireframe]($common). + - To be considered filled, [AreaFillProps.display]($common) must be defined to something other than [FillDisplay.Never]($common). + - If [AreaFillProps.display]($common) is defined as [FillDisplay.ByView]($common), the view's [ViewFlags.fill]($common) determines whether the geometry displays as filled. + - Planar regions always display as surfaces in non-Wireframe views regardless of the value for [FillDisplay]($common); they will however use the fill color as opposed to the line color when fill is specified. -* [AreaPattern.ParamsProps]($common) - * Add a hatch, crosshatch, area pattern, or hatch definition to the display of [IModelJson.PlanarRegionProps]($geometry) entries. +- [AreaPattern.ParamsProps]($common) + - Add a hatch, crosshatch, area pattern, or hatch definition to the display of [IModelJson.PlanarRegionProps]($geometry) entries. ![Pattern](./pattern_types.png "Example of types of pattern") - * A planar region can have both fill and pattern. - * Pattern display is controlled by [ViewFlags.patterns]($common) for the view. + - A planar region can have both fill and pattern. + - Pattern display is controlled by [ViewFlags.patterns]($common) for the view. -* [MaterialProps]($common) - * Override for [SubCategoryAppearance.materialId]($common). Can be used to add or remove material for the display of surface and solid geometry. +- [MaterialProps]($common) + - Override for [SubCategoryAppearance.materialId]($common). Can be used to add or remove material for the display of surface and solid geometry. ![Materials](./materials.png "Example of materials") - * Material is only applicable to views that have [ViewFlags.renderMode]($common) set to [RenderMode.SmoothShade]($common). + - Material is only applicable to views that have [ViewFlags.renderMode]($common) set to [RenderMode.SmoothShade]($common). Geometry entries should *always* be inserted into the GeometryStreamProps array unrotated with a basis point of 0,0,0 (local coordinate frame). The world location and orientation of the geometry is determined by the GeometricElement's placement origin and angle(s), [GeometricElement3dProps.placement]($common) and [GeometricElement2dProps.placement]($common). @@ -46,42 +46,42 @@ The element aligned bounding box that is part of the placement is computed autom ![Incorrect Example](./placement_bad.png "Example of incorrectly defined GeometryStream") - * [IModelJson.GeometryProps]($geometry) - * Geometric primitive types: points, curves, paths, planar regions, bspline surfaces, surface primitives, solid primitives, linear sweeps of paths and regions, rotational sweeps of paths and regions, ruled sweeps of paths and regions, and index meshes. +- [IModelJson.GeometryProps]($geometry) + - Geometric primitive types: points, curves, paths, planar regions, bspline surfaces, surface primitives, solid primitives, linear sweeps of paths and regions, rotational sweeps of paths and regions, ruled sweeps of paths and regions, and index meshes. ![Geometry](./geom_types.png "Examples of curve, surface, solid, and mesh geometry") - * [GeometryPartInstanceProps]($common) - * Add a reference to a [GeometryPart]($backend) from the GeometryStream of a [GeometricElement]($backend). Used to instance repeated geometry; the part geometry is defined once and then shared by multiple GeometricElements or referenced multiple times by a single GeometricElement. - * The [GeometryPartInstanceProps.origin]($common) and [GeometryPartInstanceProps.rotation]($common) specify the relative location from the basis point (typically 0,0,0) used for the GeometricElement's geometry. +- [GeometryPartInstanceProps]($common) + - Add a reference to a [GeometryPart]($backend) from the GeometryStream of a [GeometricElement]($backend). Used to instance repeated geometry; the part geometry is defined once and then shared by multiple GeometricElements or referenced multiple times by a single GeometricElement. + - The [GeometryPartInstanceProps.origin]($common) and [GeometryPartInstanceProps.rotation]($common) specify the relative location from the basis point (typically 0,0,0) used for the GeometricElement's geometry. ![Geometry](./part_refs.png "Example of GeometricElement with GeometryPart references") - * Not valid when creating a [GeometryPart]($backend), nesting of GeometryParts is not supported. - * As the GeometryPart does not specify a Category, and its GeometryStream does not support SubCategory changes; Category and SubCategory is established by the GeometricElement prior to adding a GeometryPartInstanceProps to the GeometryStreamProps array. - * [TextStringProps]($common) - * Add a single line of text to the GeometryStream for a GeometricElement or GeometryPart. - * The [TextStringProps.origin]($common) and [TextStringProps.rotation]($common) specify the relative location from the basis point (typically 0,0,0) used for the GeometricElement's geometry. - * [BRepEntity.DataProps]($common) - * Raw BRep data, not generally useful outside of a geometry export scenario. - * The BRep data must be specifically requested using [ElementLoadProps.wantBRepData]($common). - * The body type, body to local transform, and any face material attachments are returned when requested using [ElementLoadProps.wantGeometry]($common). - * [LowAndHighXYZ]($geometry) - * Store range of each geometric primitive to allow efficient filtering on range criteria without having to instantiate the geometry. - * Useful for GeometryStreams containing more than one geometric primitive; for a single geometric primitive, the geometry range is the placement's bounding box. - * Not necessary for [GeometryPartInstanceProps]($common) entries, a [GeometryPart]($backend) stores its bounding box in [GeometryPart.bbox]($backend). - * To include sub-ranges when creating a new GeometryStream, just add this entry to the GeometryStreamProps array before adding geometry. The low and high values will be computed automatically and will be ignored. + - Not valid when creating a [GeometryPart]($backend), nesting of GeometryParts is not supported. + - As the GeometryPart does not specify a Category, and its GeometryStream does not support SubCategory changes; Category and SubCategory is established by the GeometricElement prior to adding a GeometryPartInstanceProps to the GeometryStreamProps array. +- [TextStringProps]($common) + - Add a single line of text to the GeometryStream for a GeometricElement or GeometryPart. + - The [TextStringProps.origin]($common) and [TextStringProps.rotation]($common) specify the relative location from the basis point (typically 0,0,0) used for the GeometricElement's geometry. +- [BRepEntity.DataProps]($common) + - Raw BRep data, not generally useful outside of a geometry export scenario. + - The BRep data must be specifically requested using [ElementLoadProps.wantBRepData]($common). + - The body type, body to local transform, and any face material attachments are returned when requested using [ElementLoadProps.wantGeometry]($common). +- [LowAndHighXYZ]($geometry) + - Store range of each geometric primitive to allow efficient filtering on range criteria without having to instantiate the geometry. + - Useful for GeometryStreams containing more than one geometric primitive; for a single geometric primitive, the geometry range is the placement's bounding box. + - Not necessary for [GeometryPartInstanceProps]($common) entries, a [GeometryPart]($backend) stores its bounding box in [GeometryPart.bbox]($backend). + - To include sub-ranges when creating a new GeometryStream, just add this entry to the GeometryStreamProps array before adding geometry. The low and high values will be computed automatically and will be ignored. ## Creating a GeometryStream To help with the creation of the GeometryStream for a new GeometricElement or GeometryPart, [GeometryStreamBuilder]($common) is provided. - * Appearance information can be specified by a [GeometryParams]($common) object that will append all relevant wire format entries to the GeometryStreamProps array. - * Geometric primitives can be specified by a [GeometryQuery]($geometry) object that will append the appropriate wire format geometry entry. - * Supports supplying entries in world coordinates, such as from an [InteractiveTool]($frontend), and transforms them to placement relative local coordinate entries. +- Appearance information can be specified by a [GeometryParams]($common) object that will append all relevant wire format entries to the GeometryStreamProps array. +- Geometric primitives can be specified by a [GeometryQuery]($geometry) object that will append the appropriate wire format geometry entry. +- Supports supplying entries in world coordinates, such as from an [InteractiveTool]($frontend), and transforms them to placement relative local coordinate entries. ## Iterating a GeometryStream To help with inspecting the GeometryStream of an existing GeometricElement or GeometryPart, [GeometryStreamIterator]($common) is provided. - * Appearance related wire format entries are accumulated in a single [GeometryParams]($common) object. - * Iterator stops when it encounters a geometric entry: [GeometryQuery]($geometry), [TextString]($common), or a [GeometryPart]($backend) reference. - * Current iterator provides the [GeometryParams]($common) that determines the appearance of the geometry entry as well as the [GeometryStreamIteratorEntry.localToWorld]($common) transform. - * Supports returning entries in world coordinates when supplied the GeometricElement's placement. - * Supports iterating the GeometryStream of a GeometryPart in the context of a GeometricElement's GeometryStream. +- Appearance related wire format entries are accumulated in a single [GeometryParams]($common) object. +- Iterator stops when it encounters a geometric entry: [GeometryQuery]($geometry), [TextString]($common), or a [GeometryPart]($backend) reference. +- Current iterator provides the [GeometryParams]($common) that determines the appearance of the geometry entry as well as the [GeometryStreamIteratorEntry.localToWorld]($common) transform. +- Supports returning entries in world coordinates when supplied the GeometricElement's placement. +- Supports iterating the GeometryStream of a GeometryPart in the context of a GeometricElement's GeometryStream. diff --git a/docs/learning/common/Id64.md b/docs/learning/common/Id64.md index b5c83560eefb..c5ec00380694 100644 --- a/docs/learning/common/Id64.md +++ b/docs/learning/common/Id64.md @@ -6,8 +6,8 @@ Ids are particularly important in communication between the front-end and the ba The 64 bits of an Id are divided into two parts: -* The upper 24 bits contain the [BriefcaseId]($backend) identifying the briefcase that originally created the entity. -* The lower 40 bits contain the entity's *local Id*, unique and sequentially assigned within a single BriefcaseId. A local Id of 0 is illegal. +- The upper 24 bits contain the [BriefcaseId]($backend) identifying the briefcase that originally created the entity. +- The lower 40 bits contain the entity's *local Id*, unique and sequentially assigned within a single BriefcaseId. A local Id of 0 is illegal. An Id is considered either "valid" (identifies an existing entity) or "invalid" (does not identify any existing entity). The latter is represented by the 64-bit value `0`. An invalid Id does not necessarily indicate an error - for example, an [Element]($backend) that has no parent element stores an invalid Id as its parentId. @@ -17,17 +17,17 @@ A BriefcaseId of 0xffffff indicates "no briefcase". It is used instead to produc A `string` must meet either of the following criteria to be considered a well-formed (i.e. normalized) representation of an Id: -* It holds the **exact** string "0", indicating an invalid Id (note, no leading "0x"); or -* It holds a well-formed hexadecimal representation of a non-zero 64-bit integer, indicating a valid Id. +- It holds the **exact** string "0", indicating an invalid Id (note, no leading "0x"); or +- It holds a well-formed hexadecimal representation of a non-zero 64-bit integer, indicating a valid Id. A well-formed *valid* Id string meets the following criteria: -* Contains no uppercase letters. -* Contains no spaces. -* Begins with the prefix "0x". -* The first hexadecimal digit following the prefix is a *non-zero* hexadecimal digit (i.e., in the range [a-z1-9] (no leading zeros). -* If no briefcase Id is present, the remainder of the string consists of no more than 9 hexadecimal digits. -* If a briefcase Id is present, the remainder of the string consists of the briefcase Id as no more than 5 hexadecimal digits, followed by exactly 10 hexadecimal digits representing the local Id, of which one must be non-zero. +- Contains no uppercase letters. +- Contains no spaces. +- Begins with the prefix "0x". +- The first hexadecimal digit following the prefix is a *non-zero* hexadecimal digit (i.e., in the range [a-z1-9] (no leading zeros). +- If no briefcase Id is present, the remainder of the string consists of no more than 9 hexadecimal digits. +- If a briefcase Id is present, the remainder of the string consists of the briefcase Id as no more than 5 hexadecimal digits, followed by exactly 10 hexadecimal digits representing the local Id, of which one must be non-zero. ## Id64String @@ -37,25 +37,25 @@ The [Id64]($bentley) namespace supplies functions for working with `Id64String`s The following `Id64` functions can produce well-formed Id64Strings: -* [Id64.fromJSON]($bentley) produces an Id64String from its JSON representation. -* [Id64.fromString]($bentley) normalizes a string value into a well-formed Id64String. -* [Id64.fromLocalAndBriefcaseIds]($bentley) concatenates integer briefcase and local Ids into an Id64String. -* [Id64.fromUint32Pair]($bentley) concatenates a pair of 32-bit integers into an Id64String. +- [Id64.fromJSON]($bentley) produces an Id64String from its JSON representation. +- [Id64.fromString]($bentley) normalizes a string value into a well-formed Id64String. +- [Id64.fromLocalAndBriefcaseIds]($bentley) concatenates integer briefcase and local Ids into an Id64String. +- [Id64.fromUint32Pair]($bentley) concatenates a pair of 32-bit integers into an Id64String. `Id64.fromJSON` and `Id64.fromString` should be used when your code has a string value that may represent an Id but may not be well-formed - e.g., it may contain uppercase hexadecimal digits, leading or trailing whitespace, and so on. Examples include strings originating from user input or from some web service. Ids originating from calls to the back-end can be expected to be well-formed. `Id64` also provides functions for interrogating Id strings: -* [Id64.isValid]($bentley), [Id64.isInvalid]($bentley), and [Id64.isTransient]($bentley) determine the type of Id represented by a well-formed Id string. -* [Id64.isId64]($bentley) determines whether an arbitrary string value contains a well-formed Id string. -* [Id64.getLocalId]($bentley) and [Id64.getBriefcaseId]($bentley) extract the local and briefcase Ids from a well-formed Id string. +- [Id64.isValid]($bentley), [Id64.isInvalid]($bentley), and [Id64.isTransient]($bentley) determine the type of Id represented by a well-formed Id string. +- [Id64.isId64]($bentley) determines whether an arbitrary string value contains a well-formed Id string. +- [Id64.getLocalId]($bentley) and [Id64.getBriefcaseId]($bentley) extract the local and briefcase Ids from a well-formed Id string. ## Id64Set, Id64Array, and Id64Arg It is often necessary to refer to a group of Ids. There are two type aliases for this purpose: -* [Id64Set]($bentley) -* [Id64Array]($bentley) +- [Id64Set]($bentley) +- [Id64Array]($bentley) An Id64Array is more efficient memory-wise and insertion-wise, but does not enforce uniqueness (i.e. the same entry may appear multiple times in the group.) Id64Set enforces uniqueness and is more efficient for searching. diff --git a/docs/learning/common/index.md b/docs/learning/common/index.md index 55f7d4f834dd..209f1eff0772 100644 --- a/docs/learning/common/index.md +++ b/docs/learning/common/index.md @@ -5,16 +5,16 @@ These packages adhere to the frontend constraints of running within a web browse The iModel.js common libraries are contained in the following npm packages: -* [@bentley/bentleyjs-core](https://www.npmjs.com/package/@bentley/bentleyjs-core) - * ($bentley) -* [@bentley/ecschema-metadata](https://www.npmjs.com/package/@bentley/ecschema-metadata) - * ($ecschema-metadata) -* [@bentley/geometry-core](https://www.npmjs.com/package/@bentley/geometry-core) - * ($geometry) -* [@bentley/imodeljs-common](https://www.npmjs.com/package/@bentley/imodeljs-common) - * ($common) +- [@bentley/bentleyjs-core](https://www.npmjs.com/package/@bentley/bentleyjs-core) + - ($bentley) +- [@bentley/ecschema-metadata](https://www.npmjs.com/package/@bentley/ecschema-metadata) + - ($ecschema-metadata) +- [@bentley/geometry-core](https://www.npmjs.com/package/@bentley/geometry-core) + - ($geometry) +- [@bentley/imodeljs-common](https://www.npmjs.com/package/@bentley/imodeljs-common) + - ($common) Topics: -* [Logging](./Logging) -* [GeometryStream](./GeometryStream.md) +- [Logging](./Logging) +- [GeometryStream](./GeometryStream.md) diff --git a/docs/learning/frontend/BlankConnection.md b/docs/learning/frontend/BlankConnection.md index 9ed0d92e4362..26d042c94a28 100644 --- a/docs/learning/frontend/BlankConnection.md +++ b/docs/learning/frontend/BlankConnection.md @@ -27,9 +27,9 @@ You can test whether an IModelConnection is blank, by using [IModelConnection.is To open a new blank connection, you can do something like this: - ```ts - [[include:BlankConnection.open]] - ``` +```ts +[[include:BlankConnection.open]] +``` then, to create a blank spatial view to show data from sources other than iModels, do something like this: diff --git a/docs/learning/frontend/DrawingAids.md b/docs/learning/frontend/DrawingAids.md index aa5b08792637..f54914140288 100644 --- a/docs/learning/frontend/DrawingAids.md +++ b/docs/learning/frontend/DrawingAids.md @@ -2,9 +2,9 @@ Drawing Aids include: -* [AccuDrawHintBuilder]($frontend) -* [AccuSnap]($frontend) -* [ElementLocateManager]($frontend) -* [TentativePoint]($frontend) +- [AccuDrawHintBuilder]($frontend) +- [AccuSnap]($frontend) +- [ElementLocateManager]($frontend) +- [TentativePoint]($frontend) These are accessed via [IModelApp]($frontend). diff --git a/docs/learning/frontend/IModelApp.md b/docs/learning/frontend/IModelApp.md index 1f0f437e9402..d36b90c450d6 100644 --- a/docs/learning/frontend/IModelApp.md +++ b/docs/learning/frontend/IModelApp.md @@ -2,12 +2,12 @@ An instance of [IModelApp]($frontend) provides the services needed by the [frontend](../../learning/App.md#app-frontend) in an [interactive](../WriteAnInteractiveApp.md) iModel.js app. Services include: -* Management of graphical views using [ViewManager](./Views.md) -* [Tools](./Tools.md) and [Drawing aids](./DrawingAids.md) -* Access to iModelHub using [IModelClient]($imodelhub-client) -* [Notifications]($frontend:Notifications) -* [Localization support](./Localization.md) -* User settings using [Settings](./Settings.md) +- Management of graphical views using [ViewManager](./Views.md) +- [Tools](./Tools.md) and [Drawing aids](./DrawingAids.md) +- Access to iModelHub using [IModelClient]($imodelhub-client) +- [Notifications]($frontend:Notifications) +- [Localization support](./Localization.md) +- User settings using [Settings](./Settings.md) Applications may customize the behavior of the IModelApp services by providing an [IModelAppOptions]($frontend) and supplying different implementations of them. diff --git a/docs/learning/frontend/Localization.md b/docs/learning/frontend/Localization.md index fa1e7d0635e2..686a216f6827 100644 --- a/docs/learning/frontend/Localization.md +++ b/docs/learning/frontend/Localization.md @@ -10,26 +10,26 @@ For that to work, the localization system needs a dictionary of key-to-string su For example, suppose you are developing an application called SafetyBase and you want to group information, warning, and error messages into a localization namespace. Name the JSON file SafetyBaseMessages.json, put it into the public/locales/en directory, and put the following JSON in it: - ```json - { - "info": { - "login": { - "notLoggedIn": "You are not currently logged in.", - "loggedIn": "You are logged in as {{userName}}." - } - }, - "warning": { - "login": { - "mustLogin": "That feature is unavailable unless you log.", - "notAuthorized": "You are not authorized to access that resource." - } - }, - "error": { - "loginIncorrect": "The username / password combination is not valid.", - "offline": "Network connection not available." - } - } - ``` +```json +{ + "info": { + "login": { + "notLoggedIn": "You are not currently logged in.", + "loggedIn": "You are logged in as {{userName}}." + } + }, + "warning": { + "login": { + "mustLogin": "That feature is unavailable unless you log.", + "notAuthorized": "You are not authorized to access that resource." + } + }, + "error": { + "loginIncorrect": "The username / password combination is not valid.", + "offline": "Network connection not available." + } +} +``` The messages can now be accessed by first registering the namespace, and then using the translate method: @@ -69,28 +69,28 @@ PlaceSprinkler.register(toyToolsNS); Then the appropriate entry in the english version of SafetyBaseTools.json file might look like this: ```json - { - "tools": { - "Place": { - "Sprinkler": { - "keyin": "Place Sprinkler", - "flyover": "Place Sprinkler Component.", - "description": "Puts a new Sprinkler Component in the SafetyBase System.", - "prompt1": "Enter Sprinkler origin.", - "prompt2": "Rotate Sprinkler to desired position.", - "successStatus": "Sprinkler successfully placed." - } - } - } - } - ``` +{ + "tools": { + "Place": { + "Sprinkler": { + "keyin": "Place Sprinkler", + "flyover": "Place Sprinkler Component.", + "description": "Puts a new Sprinkler Component in the SafetyBase System.", + "prompt1": "Enter Sprinkler origin.", + "prompt2": "Rotate Sprinkler to desired position.", + "successStatus": "Sprinkler successfully placed." + } + } + } +} +``` If you omit the "flyover" key, the keyin property is used for the flyover text. Similarly, if "description" key is not found, the fallback is the value of the flyover property. In this example, the prompt1 and prompt2 keys are not used by the system - they could be used by your application during the operation of the Place Sprinkler command. They would be retrieved using this code: ```ts - const firstPrompt: string = IModelApp.i18n.translate ("SafetyBaseTools:Place.Sprinkler.prompt1"); +const firstPrompt: string = IModelApp.i18n.translate ("SafetyBaseTools:Place.Sprinkler.prompt1"); ``` Since your code retrieves those localized strings, they do not have to be subkeys of "tools.Place.Sprinkler". They could be separate keys in the same JSON file, or could even be in a different JSON file (in which case the namespace would be different). The convention demonstrated in the example above has the advantage of keeping the localizable strings associated with a particular tool all together, but the disadvantage that prompts or messages that might be usable for multiple tools would be duplicated in each tool. diff --git a/docs/learning/frontend/LogoCards.md b/docs/learning/frontend/LogoCards.md index 1877e1f5d282..80fcf5a38041 100644 --- a/docs/learning/frontend/LogoCards.md +++ b/docs/learning/frontend/LogoCards.md @@ -49,6 +49,6 @@ Sometimes it may be desirable to hide the logo in specialized viewports, particu Please keep in mind: -* The icon may not be replaced with anything other than the iModel.js logo. Place your logo on a Logo Card. -* The icon may be positioned anywhere in the view where it is least obtrusive, but the opacity should not be set below 40% and its size should not be smaller than 24 pixels. -* The icon **may not** be removed entirely in views that may show maps, terrain, point clouds, or other copyrighted material, since it is required to show the copyright attribution of data suppliers. +- The icon may not be replaced with anything other than the iModel.js logo. Place your logo on a Logo Card. +- The icon may be positioned anywhere in the view where it is least obtrusive, but the opacity should not be set below 40% and its size should not be smaller than 24 pixels. +- The icon **may not** be removed entirely in views that may show maps, terrain, point clouds, or other copyrighted material, since it is required to show the copyright attribution of data suppliers. diff --git a/docs/learning/frontend/PrimitiveTools.md b/docs/learning/frontend/PrimitiveTools.md index 58cebad4b7fc..852be86f387c 100644 --- a/docs/learning/frontend/PrimitiveTools.md +++ b/docs/learning/frontend/PrimitiveTools.md @@ -8,9 +8,9 @@ Because Primitive tools often target a specific type of element, it may be undes When [ToolRegistry.run]($frontend) is called for a Primitive tool, the following sequence of tool methods are called: -* [isCompatibleViewport](#iscompatibleviewport) -* [onInstall](#oninstall) -* [onPostInstall](#onpostinstall) +- [isCompatibleViewport](#iscompatibleviewport) +- [onInstall](#oninstall) +- [onPostInstall](#onpostinstall) ```ts [[include:PrimitiveTool_Run]] @@ -22,9 +22,9 @@ The very first decision the tool must make is whether to continue the install or The tool is responsible for checking the viewport's compatibility with the tool operation, some examples below: -* Target isn't readonly. Checks [PrimitiveTool.requireWriteableTarget]($frontend), defaults to true; assumption is that *most* Primitive tools will insert/update elements. -* Only applicable to spatial views. -* Requires a specific GeometricModel be included in the view's [ModelSelectorState]($frontend). +- Target isn't readonly. Checks [PrimitiveTool.requireWriteableTarget]($frontend), defaults to true; assumption is that *most* Primitive tools will insert/update elements. +- Only applicable to spatial views. +- Requires a specific GeometricModel be included in the view's [ModelSelectorState]($frontend). If [InteractiveTool.isCompatibleViewport]($frontend) rejects the view, then the current tool remains active and installation of the new tool stops, if the view is accepted, then we proceed to the [onInstall](#oninstall) step. @@ -40,7 +40,7 @@ If [InteractiveTool.isCompatibleViewport]($frontend) rejects the view, then the Now that a target view has been accepted for the tool operation, [InteractiveTool.onInstall]($frontend) provides one last chance before being set as the active tool to check any remaining requirements. The type of checks to consider for onInstall as opposed to isCompatibleViewport would be one time only initial conditions that would not be appropriate or necessary to test on a motion event, such as: -* Tool requires an pre-defined [SelectionSet]($frontend) of existing elements. +- Tool requires an pre-defined [SelectionSet]($frontend) of existing elements. > Most tools don't need to override onInstall, as long as it returns true, the new tool is set as the active tool, after which [onPostInstall](#onpostinstall) will be called. @@ -54,7 +54,7 @@ Refer to [AccuSnap](#accusnap) and [AccuDraw](#accudraw) for examples showing ho A Primitive tool is required to provide an implementation for [PrimitiveTool.onRestartTool]($frontend). This method will be called to notify the tool after iModel changes made outside of the tool's purview have occurred which *may* have invalidated the current tool state. -* For example, the user requests an undo of their previous action, an element the tool is currently modifying was created in the last transaction and as such no longer exists. The tool is expected to either install a new tool instance, or exit in response to this event. +- For example, the user requests an undo of their previous action, an element the tool is currently modifying was created in the last transaction and as such no longer exists. The tool is expected to either install a new tool instance, or exit in response to this event. Example of typical implementation for onRestartTool: @@ -116,8 +116,8 @@ Example from a simple tool that locates elements and makes them the current sele Some examples of AccuDraw tool hints: -* Send AccuDraw hint to use polar mode when defining a sweep angle. -* Send AccuDraw hint to set origin to opposite end point of line segment being modified and orient to segment direction, a new line length can be now easily specified. +- Send AccuDraw hint to use polar mode when defining a sweep angle. +- Send AccuDraw hint to set origin to opposite end point of line segment being modified and orient to segment direction, a new line length can be now easily specified. Upon installing a new Primitive tool as the active tool, AccuDraw's default state is initialized to *inactive*. AccuDraw will upgrade its internal state to *active* automatically if the tool calls [InteractiveTool.beginDynamics]($frontend). Tools that won't start dynamics (might only use view decorations) but still wish to support AccuDraw can explicitly enable it using [AccuDrawHintBuilder.activate]($frontend) or [AccuDrawHintBuilder.sendHints]($frontend). Conversely, tools that show dynamics, but do not want AccuDraw, are required to explicitly disable it by calling [AccuDrawHintBuilder.deactivate]($frontend). diff --git a/docs/learning/frontend/Settings.md b/docs/learning/frontend/Settings.md index 643109cb2e53..242d339c7e84 100644 --- a/docs/learning/frontend/Settings.md +++ b/docs/learning/frontend/Settings.md @@ -12,20 +12,20 @@ The methods on SettingsAdmin allow saving and retrieving settings that are eithe User-specific settings can be: -* Specific to an application (for example, the user's particular application preferences) -* Specific to an application and Project (for example, the user's most recently opened iModel when using the application) -* Specific to an application and iModel (for example, the user's application-specific session data) -* Specific to a Project (for example, the user's list of favorite iModels in that project) -* Specific to an iModel (for example, the user's list of favorite views in that iModel) -* Specific only to the user (for example, a list of favorite applications) +- Specific to an application (for example, the user's particular application preferences) +- Specific to an application and Project (for example, the user's most recently opened iModel when using the application) +- Specific to an application and iModel (for example, the user's application-specific session data) +- Specific to a Project (for example, the user's list of favorite iModels in that project) +- Specific to an iModel (for example, the user's list of favorite views in that iModel) +- Specific only to the user (for example, a list of favorite applications) Non-user-specific settings can be: -* Specific to an application (for example, default application preferences) -* Specific to an application and Project (for example, the default iModel for the project when the application is opened) -* Specific to an application and iModel (for example, the default views for the iModel when the application is opened) -* Specific to a Project (for example, a message of the day for all users of that Project) -* Specific to an iModel (for example, default basic preferences relevant to all applications) +- Specific to an application (for example, default application preferences) +- Specific to an application and Project (for example, the default iModel for the project when the application is opened) +- Specific to an application and iModel (for example, the default views for the iModel when the application is opened) +- Specific to a Project (for example, a message of the day for all users of that Project) +- Specific to an iModel (for example, default basic preferences relevant to all applications) To save a non-user-specific setting, administrative privileges are required. That makes such settings ideal for parameters that should be fixed per-iModel or per-Project by an administrator, and used by every user. diff --git a/docs/learning/frontend/Tools.md b/docs/learning/frontend/Tools.md index 8dace67ac20f..584a983112df 100644 --- a/docs/learning/frontend/Tools.md +++ b/docs/learning/frontend/Tools.md @@ -12,17 +12,17 @@ It is important to make user actions that result in changes to your application There are three interactive Tool classifications, each of which is implemented by subclassing [InteractiveTool]($frontend) to best serve a specific purpose. -* [ViewTool]($frontend) is used to implement viewing operations such as pan, zoom, and rotate. - * Pauses the active tool while executing and resumes the active tool when finished. - * The frontend package provides a comprehensive set of View tools; most iModel.js applications do not need to implement their own. -* [InputCollector]($frontend) is used to gather input for the current Primitive tool by snapping or locating elements in the iModel. - * Pauses an active Primitive tool, can be paused by a View tool. - * Should not modify the iModel contents without being able to coordinate with the current Primitive tool. - * The frontend package includes several [AccuDrawShortcuts]($frontend) implementations. -* [PrimitiveTool]($frontend) is used for graphical interactions with an iModel. - * When invoked, they become the active tool, reacting to user input such as data points, mouse movements, touch, keystrokes, and resets. - * Primitive tools are the most common type of tool implemented by iModel.js applications. Refer [here](./PrimitiveTools) for guidelines on writing Primitive tools. - * The frontend package includes a [Select Tool](#selection-tool) to fill the role of a *default* Primitive tool. +- [ViewTool]($frontend) is used to implement viewing operations such as pan, zoom, and rotate. + - Pauses the active tool while executing and resumes the active tool when finished. + - The frontend package provides a comprehensive set of View tools; most iModel.js applications do not need to implement their own. +- [InputCollector]($frontend) is used to gather input for the current Primitive tool by snapping or locating elements in the iModel. + - Pauses an active Primitive tool, can be paused by a View tool. + - Should not modify the iModel contents without being able to coordinate with the current Primitive tool. + - The frontend package includes several [AccuDrawShortcuts]($frontend) implementations. +- [PrimitiveTool]($frontend) is used for graphical interactions with an iModel. + - When invoked, they become the active tool, reacting to user input such as data points, mouse movements, touch, keystrokes, and resets. + - Primitive tools are the most common type of tool implemented by iModel.js applications. Refer [here](./PrimitiveTools) for guidelines on writing Primitive tools. + - The frontend package includes a [Select Tool](#selection-tool) to fill the role of a *default* Primitive tool. iModel.js provides some specializations of [InteractiveTool]($frontend) to make it easier to implement certain types of interactions, ex. creating new elements vs. modifying existing elements. @@ -36,8 +36,8 @@ The [ToolAdmin]($frontend) class supervises the collection of low-level input fr Routing of the interpreted, high-level events is as follows: -* If there is an active tool, the events are directed to it. The active tool can either handle a particular event or ignore it. -* If the active tool does not handle a particular event, it *may* be directed to the [Idle Tool](#idle-tool). +- If there is an active tool, the events are directed to it. The active tool can either handle a particular event or ignore it. +- If the active tool does not handle a particular event, it *may* be directed to the [Idle Tool](#idle-tool). As mentioned above a View tool or Input Collector can temporarily interrupt a Primitive tool. The ToolAdmin handles that sequence transparently such that the Primitive tool does not have to be aware of the interruption. @@ -49,19 +49,19 @@ The standard iModel.js [IdleTool]($frontend) is a subclass of [InteractiveTool]( For desktop computers, viewing operations are associated with the middle button, which is not typically handled by the active tool. Additionally, if the application chooses to not have a default tool, when no tool is active, data and reset events will also be directed to the Idle tool. Default mouse event handling is as follows: -* Press and hold middle button to pan the view -* Press and hold shift-middle button to rotate the view (uses geometry under cursor as pivot point) -* Double click of middle button to fit the view -* Roll the wheel to zoom the view in and out -* Press and hold data button to rotate the view (only when no active tool) -* Press and hold reset button to pan the view (only when no active tool) +- Press and hold middle button to pan the view +- Press and hold shift-middle button to rotate the view (uses geometry under cursor as pivot point) +- Double click of middle button to fit the view +- Roll the wheel to zoom the view in and out +- Press and hold data button to rotate the view (only when no active tool) +- Press and hold reset button to pan the view (only when no active tool) For touch devices, the Idle tool associates the following touch events with viewing operations: -* Single finger drag to rotate the view -* Two-finger drag to pan the view -* Double tap to fit the view -* Pinch to zoom the view in and out +- Single finger drag to rotate the view +- Two-finger drag to pan the view +- Double tap to fit the view +- Pinch to zoom the view in and out ## Selection Tool diff --git a/docs/learning/frontend/Views.md b/docs/learning/frontend/Views.md index 13d436dfc793..b901cd0a3b53 100644 --- a/docs/learning/frontend/Views.md +++ b/docs/learning/frontend/Views.md @@ -32,10 +32,10 @@ There are subclasses of `ViewDefinition` to show different types of Models in va Here are several significant subclasses: -* `ViewDefinition` - * `SpatialViewDefinition` - shows a view of one or more 3d SpatialModels - * `DrawingViewDefinition` - shows a view of a *single* 2d DrawingModel - * `SheetViewDefinition` - shows a view of a *single* 2d SheetModel +- `ViewDefinition` + - `SpatialViewDefinition` - shows a view of one or more 3d SpatialModels + - `DrawingViewDefinition` - shows a view of a *single* 2d DrawingModel + - `SheetViewDefinition` - shows a view of a *single* 2d SheetModel For each subclass of `xxxViewDefinition`, there is a corresponding `xxxViewState` class in the frontend. @@ -130,12 +130,12 @@ DisplayStyles describe the *styling* that should be applied to the contents of a This includes the: -* [ViewFlags]($common) -* [SubCategoryAppearance]($common) visibility and overrides -* Background color -* [RenderMode]($common) -* [Environment]($frontend) -* Other view-specific parameters +- [ViewFlags]($common) +- [SubCategoryAppearance]($common) visibility and overrides +- Background color +- [RenderMode]($common) +- [Environment]($frontend) +- Other view-specific parameters They are loaded in memory in the frontend with the [DisplayStyleState]($frontend) class. @@ -191,11 +191,11 @@ Every view may have a thumbnail that shows an approximation of what it contains. ### Notes -* The view origin is in world coordinates. It is the point at the lower left of the rectangle at the focus plane, projected onto the back plane. +- The view origin is in world coordinates. It is the point at the lower left of the rectangle at the focus plane, projected onto the back plane. -* `[delta.x,delta.y]` are on the focus plane and `delta.z` is from the back plane to the front plane. +- `[delta.x,delta.y]` are on the focus plane and `delta.z` is from the back plane to the front plane. -* The three view vectors come from: +- The three view vectors come from: ```cmd {vector from eyePoint->targetPoint} : -Z (positive view Z points towards negative world Z) @@ -205,17 +205,17 @@ Every view may have a thumbnail that shows an approximation of what it contains. these three vectors form the rows of the view's [Matrix3d]($geometry) -* Objects in space in front of the front plane or behind the back plane are not displayed. +- Objects in space in front of the front plane or behind the back plane are not displayed. -* The focus plane is not necessarily centered between the front plane and back plane (though it often is.) +- The focus plane is not necessarily centered between the front plane and back plane (though it often is.) It should generally be between the front plane and the back plane. -* targetPoint is not stored in the view parameters. Instead it may be derived from `{origin},{eyePoint},[Matrix3d]` and `focusDist`. +- targetPoint is not stored in the view parameters. Instead it may be derived from `{origin},{eyePoint},[Matrix3d]` and `focusDist`. -* The ViewState holds the parameters: `{origin}{delta}[Matrix3d]` from which the View frustum is derived. +- The ViewState holds the parameters: `{origin}{delta}[Matrix3d]` from which the View frustum is derived. -* Cameras hold a "lens angle" value which is defines the field-of-view for the camera in radians. +- Cameras hold a "lens angle" value which is defines the field-of-view for the camera in radians. The lens angle value is not used to compute the perspective transform for a view. Instead, the lens angle value can be used to reposition `{eyePoint}` when the view volume or target changes. -* View volumes where one dimension is very small or large relative to the other dimensions (e.g. "long skinny telescope" views, or "wide and shallow slices", etc.) are problematic and disallowed based on ratio limits. +- View volumes where one dimension is very small or large relative to the other dimensions (e.g. "long skinny telescope" views, or "wide and shallow slices", etc.) are problematic and disallowed based on ratio limits. diff --git a/docs/learning/frontend/extensions/GettingStarted.md b/docs/learning/frontend/extensions/GettingStarted.md index 68b30ad8b265..5099631f6699 100644 --- a/docs/learning/frontend/extensions/GettingStarted.md +++ b/docs/learning/frontend/extensions/GettingStarted.md @@ -21,23 +21,23 @@ npm init --yes Next, add the required dependencies for an Extension, ```json - "devDependencies": { - "@bentley/build-tools": "^2.0.0", - "@bentley/extension-webpack-tools": "^2.0.0", - "typescript": "~3.7.4" - }, - "dependencies": { - "@bentley/bentleyjs-core": "^2.0.0", - "@bentley/geometry-core": "^2.0.0", - "@bentley/imodeljs-common": "^2.0.0", - "@bentley/imodeljs-i18n": "^2.0.0", - "@bentley/imodeljs-frontend": "^2.0.0", - "@bentley/imodeljs-quantity": "^2.0.0", - "@bentley/product-settings-client": "^2.0.0", - "@bentley/orbitgt-core": "^2.0.0", - "@bentley/ui-abstract": "^2.0.0", - "@bentley/webgl-compatibility": "^2.0.0" - } +"devDependencies": { + "@bentley/build-tools": "^2.0.0", + "@bentley/extension-webpack-tools": "^2.0.0", + "typescript": "~3.7.4" +}, +"dependencies": { + "@bentley/bentleyjs-core": "^2.0.0", + "@bentley/geometry-core": "^2.0.0", + "@bentley/imodeljs-common": "^2.0.0", + "@bentley/imodeljs-i18n": "^2.0.0", + "@bentley/imodeljs-frontend": "^2.0.0", + "@bentley/imodeljs-quantity": "^2.0.0", + "@bentley/product-settings-client": "^2.0.0", + "@bentley/orbitgt-core": "^2.0.0", + "@bentley/ui-abstract": "^2.0.0", + "@bentley/webgl-compatibility": "^2.0.0" +} ``` Since the Extension will be written using Typescript, a basic tsconfig.json file needs to be setup. Create a new `tsconfig.json` file next to the `package.json` with the following contents, or download the file from [here](https://raw.githubusercontent.com/imodeljs/extension-sample/master/tsconfig.json). @@ -58,8 +58,8 @@ Since the Extension will be written using Typescript, a basic tsconfig.json file The final setup step is to add a basic [npm script](https://docs.npmjs.com/misc/scripts) to build the Extension. The example below is split into two different scripts. One for building the typescript and the second webpack the Extension into the correct bundle. Copy this into the "scripts" section of the `package.json`, ```json - "build": "tsc 1>&2 && npm run build:extension", - "build:extension": "extension-webpack-tools build -s ./src/MyExtension.ts -o ./lib/extension", +"build": "tsc 1>&2 && npm run build:extension", +"build:extension": "extension-webpack-tools build -s ./src/MyExtension.ts -o ./lib/extension", ``` Great! Now we're setup to start writing the Extension. diff --git a/docs/learning/frontend/index.md b/docs/learning/frontend/index.md index 64b5f2388b4f..dfa9ad3c797e 100644 --- a/docs/learning/frontend/index.md +++ b/docs/learning/frontend/index.md @@ -2,14 +2,14 @@ The frontend of an app is concerned mainly with data display and user interaction. Frontend code: -* Always runs in a web browser. -* Gets access to the data in an iModel by making requests on a [backend](../backend/index.md). +- Always runs in a web browser. +- Gets access to the data in an iModel by making requests on a [backend](../backend/index.md). The following app configurations are supported: -* [Web app](../App.md#web-apps) - See [browser compatibility](#web-browser-compatibility) -* [Desktop app](../App.md#desktop-apps) -* [Mobile app](../App.md#mobile-apps) +- [Web app](../App.md#web-apps) - See [browser compatibility](#web-browser-compatibility) +- [Desktop app](../App.md#desktop-apps) +- [Mobile app](../App.md#mobile-apps) See the [app architecture overview](../SoftwareArchitecture.md) for more on app structure. @@ -22,16 +22,16 @@ The [common packages](../common/index.md) will also be required. These packages provide the following functions that a frontend requires: -* [Login and obtain AccessTokens](../common/AccessToken.md) -* [Open a "connection" to an iModel](./IModelConnection.md) -* [Adminstration](./IModelApp.md) via the IModelApp class -* [Localization](./Localization.md) of strings and user interface -* Writing [Tools](./Tools.md) for handling events from users -* Communicating with the Backend via an [RpcInterface](../RpcInterface.md) -* Displaying [Views](./Views.md) of iModels -* Executing [ECSQL queries](./ExecutingECSQL.md) on iModels -* Storing [Settings](./Settings.md) for Applications, Projects, and iModels. -* Implementing [Extensions](./Extensions.md) +- [Login and obtain AccessTokens](../common/AccessToken.md) +- [Open a "connection" to an iModel](./IModelConnection.md) +- [Adminstration](./IModelApp.md) via the IModelApp class +- [Localization](./Localization.md) of strings and user interface +- Writing [Tools](./Tools.md) for handling events from users +- Communicating with the Backend via an [RpcInterface](../RpcInterface.md) +- Displaying [Views](./Views.md) of iModels +- Executing [ECSQL queries](./ExecutingECSQL.md) on iModels +- Storing [Settings](./Settings.md) for Applications, Projects, and iModels. +- Implementing [Extensions](./Extensions.md) ## Web browser compatibility diff --git a/docs/learning/geometry/CurveCollection.md b/docs/learning/geometry/CurveCollection.md index 956476916ffd..4854741571ab 100644 --- a/docs/learning/geometry/CurveCollection.md +++ b/docs/learning/geometry/CurveCollection.md @@ -4,10 +4,10 @@ A [CurveCollection]($geometry-core) is a an abstract base class for various coll There are 5 concrete derived types: -* [Path]($geometry-core) - curve primitives joining head to tail -* [Loop]($geometry-core) - curve primitives joining head to tail and closing to form a loop -* [ParityRegion]($geometry-core) - `Loop`s that bound a planar area by parity rules. -* [UnionRegion]($geometry-core) - boolean union of areas of `Loop`s and/or `ParityRegion`s +- [Path]($geometry-core) - curve primitives joining head to tail +- [Loop]($geometry-core) - curve primitives joining head to tail and closing to form a loop +- [ParityRegion]($geometry-core) - `Loop`s that bound a planar area by parity rules. +- [UnionRegion]($geometry-core) - boolean union of areas of `Loop`s and/or `ParityRegion`s ![>](./figs/CurveCollections/CurveCollectionClasses.png) @@ -15,66 +15,66 @@ There are 5 concrete derived types: `Path` and `Loop` are collections for which -* All members of the collection must be derived from [CurvePrimitive]($geometry-core), i.e. be one of - * [LineSegment3d]($geometry-core) - * [Arc3d]($geometry-core) - * [BSplineCurve3d]($geometry-core) - * [TransitionSpiral3d]($geometry-core) -* Successive `CurvePrimitive` members must match "head to tail". -* In a `Loop`, the last member's head must match the first member's tail. -* Throughout the library, a `Loop` is expected to be a "filled" planar region. -* A `Path` is usually does _not_ return to its start point. - * If a `Path` _does_ return to its start point, it is _not_ interpreted as enclosing area. The path is still just a wire that happens to come back to its start. +- All members of the collection must be derived from [CurvePrimitive]($geometry-core), i.e. be one of + - [LineSegment3d]($geometry-core) + - [Arc3d]($geometry-core) + - [BSplineCurve3d]($geometry-core) + - [TransitionSpiral3d]($geometry-core) +- Successive `CurvePrimitive` members must match "head to tail". +- In a `Loop`, the last member's head must match the first member's tail. +- Throughout the library, a `Loop` is expected to be a "filled" planar region. +- A `Path` is usually does _not_ return to its start point. + - If a `Path` _does_ return to its start point, it is _not_ interpreted as enclosing area. The path is still just a wire that happens to come back to its start. The immediate base class for both `Path` and `Loop` is `CurveChain`. The `CurveChain` base class implements various methods that depend on the internal head-to-tail matching but _not_ on the closure of a `Loop`. ### Special `Loop` properties -* The purpose of a `Loop` is to act as the boundary of a planar region. - * Unless specifically indicated by names or comments for various methods that at on `Loop`s, The containing plane will be determine "on demand" using the `FrameBuilder` class. -* A point is "inside" a loop if a line (within the `Loop`'s plane) from the point "to infinity" crosses the loop an odd number of times. -* The crossing count rule may be applied (and mathematically always produces the same result) for: - * Any line direction -- horizontal, vertical, or any other direction. - * Any curved path that starts at the and gets to infinity. +- The purpose of a `Loop` is to act as the boundary of a planar region. + - Unless specifically indicated by names or comments for various methods that at on `Loop`s, The containing plane will be determine "on demand" using the `FrameBuilder` class. +- A point is "inside" a loop if a line (within the `Loop`'s plane) from the point "to infinity" crosses the loop an odd number of times. +- The crossing count rule may be applied (and mathematically always produces the same result) for: + - Any line direction -- horizontal, vertical, or any other direction. + - Any curved path that starts at the and gets to infinity. ## `ParityRegion` A `ParityRegion` is a curve collection whose immediate children are -* _all_ of type `Loop` (i.e. array of `CurvePrimitive` joined head-to-tail both internally an from last to first. -* all coplanar. +- _all_ of type `Loop` (i.e. array of `CurvePrimitive` joined head-to-tail both internally an from last to first. +- all coplanar. "Inside" and "Outside" of a parity region is determined by the rule commonly called "even/odd", "exclusive or" or "parity": -* A point is "inside" the parity region if and only if it is classified as "inside" of an odd number of its `Loop`s. -* A point is "inside" if and only if performing "exclusive or" among the (boolean) "inside" classification of all of its `Loop`s. +- A point is "inside" the parity region if and only if it is classified as "inside" of an odd number of its `Loop`s. +- A point is "inside" if and only if performing "exclusive or" among the (boolean) "inside" classification of all of its `Loop`s. In nearly all uses, the various loops in a `ParityRegion` -* have no intersections among any pair of loops. -* have exactly one that can be called `outer` -* all other than the `outer` +- have no intersections among any pair of loops. +- have exactly one that can be called `outer` +- all other than the `outer` ## `UnionRegion` A `UnionRegion` is a curve collection whose immediate children are -* limited to the two types `Loop` and `ParityRegion`. -* all coplanar. +- limited to the two types `Loop` and `ParityRegion`. +- all coplanar. "Inside" and "Outside" of a parity region is determined by the boolean "union" or "OR" rule: -* A point is "inside" the union region if it is "inside" _one or more_ of the members. -* A point is "inside" if and only if performing "union" among the (boolean) "inside" classification of all of its `Loop` and `ParityRegion`. +- A point is "inside" the union region if it is "inside" _one or more_ of the members. +- A point is "inside" if and only if performing "union" among the (boolean) "inside" classification of all of its `Loop` and `ParityRegion`. ## Tips for Processing `CurveCollection`s Processing all 5 subtypes of `CurveCollection` initially appears quite complex. However, within each of the cases of a top level switch statement or sequence of `if` tests, the number of possibilities drops quickly: -* A `Path` or `Loop` can _only_ contain true `CurvePrimitive`. -* A `ParityRegion` may only contain `Loop`s. -* A `UnionRegion` may contain only `Loop`, `ParityRegion`, or further `UnionRegion`. -* A `BagOfCurves` is the only one with free mixture of both `CurveCollection` and `CurvePrimitive`. +- A `Path` or `Loop` can _only_ contain true `CurvePrimitive`. +- A `ParityRegion` may only contain `Loop`s. +- A `UnionRegion` may contain only `Loop`, `ParityRegion`, or further `UnionRegion`. +- A `BagOfCurves` is the only one with free mixture of both `CurveCollection` and `CurvePrimitive`. ## IModelJson Examples diff --git a/docs/learning/geometry/CurveFactory.md b/docs/learning/geometry/CurveFactory.md index ba32819d5aeb..75e0bfcc726c 100644 --- a/docs/learning/geometry/CurveFactory.md +++ b/docs/learning/geometry/CurveFactory.md @@ -9,8 +9,9 @@ Given a linestring and fillet radius, this constructs fillet arcs at each interi Radius may be given as a single value or as an array of radius per point of the linestring. A parameter `allowBackupAlongEdge` indicates how to handle edges where the incoming and outgoing fillets overlap. - * if `false` the edge can be output full length, without the arcs. - * if `true` the arcs are constructed and the output edge moves in reverse to connect the overlapped arcs. + +- if `false` the edge can be output full length, without the arcs. +- if `true` the arcs are constructed and the output edge moves in reverse to connect the overlapped arcs. The arc constructions are full 3D -- each arc is in the plane of its two line segments. (In the figures below, the linestring is slightly out-of-plane, and the visible fillets appear slightly elliptic because of being viewed at an angle.) @@ -23,12 +24,11 @@ The arc constructions are full 3D -- each arc is in the plane of its two line se | large fillet, no backup | ![>](./figs/CurveFactory/FilletLineStringD.png) | | varying size fillets | ![>](./figs/CurveFactory/FilletLineStringE.png) | - Unit Test - * source: imodeljs/core/geometry/src/test/curve/CurveFactory.test.ts - * test name: "FilletsInLinestring" - * output: imodeljs/core/geometry/src/test/output/CurveFactory/FilletsInLineString.imjs +- source: imodeljs/core/geometry/src/test/curve/CurveFactory.test.ts +- test name: "FilletsInLinestring" +- output: imodeljs/core/geometry/src/test/output/CurveFactory/FilletsInLineString.imjs ## `CurveFactory.createPipeSegments(centerline, radius)` @@ -39,8 +39,9 @@ This is usually used with centerline created by `CurveFactory.createFilletsInLin The `centerline` parameter can be either a single curve primitive or a chain in a `Path` or `Loop`. The pipe creation according to centerline segment is - * `LineSegment3d`: simple cylinder (`Cone` object with constant radius) with axis from the line segment start to end. - * `Arc3d`: `TorusPipe` primitive with the arc as its major arc. + +- `LineSegment3d`: simple cylinder (`Cone` object with constant radius) with axis from the line segment start to end. +- `Arc3d`: `TorusPipe` primitive with the arc as its major arc. | | | |-----|-----| @@ -48,6 +49,7 @@ The pipe creation according to centerline segment is | output of createPipeSegments | ![>](./figs/CurveFactory/PipeConstructionB.png) Unit Test - * source: imodeljs/core/geometry/src/test/curve/PipePath.test.ts - * test name: "KeyPointPath" - * output: imodeljs/core/geometry/src/test/output/PipePath/KeyPointPath.imjs \ No newline at end of file + +- source: imodeljs/core/geometry/src/test/curve/PipePath.test.ts +- test name: "KeyPointPath" +- output: imodeljs/core/geometry/src/test/output/PipePath/KeyPointPath.imjs diff --git a/docs/learning/geometry/CurvePrimitive.md b/docs/learning/geometry/CurvePrimitive.md index b2097eedb044..cba42d501fe9 100644 --- a/docs/learning/geometry/CurvePrimitive.md +++ b/docs/learning/geometry/CurvePrimitive.md @@ -1,36 +1,39 @@ # Curve Primitives -* A CurvePrimitive is a bounded continuous curve. -* All curves implement methods (e.g. `fractionToPoint` to refer to "fraction" position along the curve. - * `fraction=0` is the start of the primitive - * `fraction=1` is the end of the primitive - * increasing fractions always move forward along the primitive. - * curves implement their equations with the fraction representing the parameter in their most natural equations. -* All curves also support methods to deal with _true distance_ along the curve. These include - * `curve.curveLengthBetweenFractions (startFraction, endFraction)` - * `curve.moveByDistanceFromFraction (startFraction, distance)` - * Fraction position along the curve is strictly proportional to true distance along the curve only for a limited number of curve types: - * LineSegment3d - * Arc3d - * TransitionSpiral -* Other curve types that have more complicated (non-proportional) fraction-to-distance relations are - * elliptic arcs - * bspline curves - * linestrings -* When movement "by distance" along a chain of curves (of varying types) is required, the `CurveChainWithDistanceIndex` will act like a single curve (starting and ending at fractions 0 and 1), with the fraction mapped to true distance along the chain. +- A CurvePrimitive is a bounded continuous curve. +- All curves implement methods (e.g. `fractionToPoint` to refer to "fraction" position along the curve. + - `fraction=0` is the start of the primitive + - `fraction=1` is the end of the primitive + - increasing fractions always move forward along the primitive. + - curves implement their equations with the fraction representing the parameter in their most natural equations. +- All curves also support methods to deal with _true distance_ along the curve. These include + - `curve.curveLengthBetweenFractions (startFraction, endFraction)` + - `curve.moveByDistanceFromFraction (startFraction, distance)` + - Fraction position along the curve is strictly proportional to true distance along the curve only for a limited number of curve types: + - LineSegment3d + - Arc3d + - TransitionSpiral +- Other curve types that have more complicated (non-proportional) fraction-to-distance relations are + - elliptic arcs + - bspline curves + - linestrings +- When movement "by distance" along a chain of curves (of varying types) is required, the `CurveChainWithDistanceIndex` will act like a single curve (starting and ending at fractions 0 and 1), with the fraction mapped to true distance along the chain. ## lineSegment -* A line segment is a portion of an infinite line. -* Json Fragment: `[{"lineSegment":[[0,0,0], [3,0,0]]}` -* typescript object: +- A line segment is a portion of an infinite line. +- Json Fragment: `[{"lineSegment":[[0,0,0], [3,0,0]]}` +- typescript object: + ``` const myLineSegment = LineSegment.create (Point3d.create (1,2,3), Point3d.create(6,4,2)); ``` + ![>](./figs/CurvePrimitives/LineSegment.png) - * Fractional Parameterization: +- Fractional Parameterization: + ``` A = start point B = end point @@ -40,23 +43,26 @@ const myLineSegment = LineSegment.create (Point3d.create (1,2,3), Point3d.create ``` ## lineString -* A LineString is an array of points that are to be connected by straight lines. -* Json Fragment: + +- A LineString is an array of points that are to be connected by straight lines. +- Json Fragment: ![>](./figs/CurvePrimitives/LineString.png) -* Typescript object: +- Typescript object: + ``` const myLineString = LineString.create ([point0, point1, point2 ....]); ``` -* Fractional Parameterization + +- Fractional Parameterization Having both individual line segments and the composite linestring complicates parameterization. -* As with all CurvePrimitives, the fractional parameterization for the complete linestring must have `fraction=0` at the start and `fraction=1` at the end. -* The fractional positions of each interior vertex are then defined at _equal intervals in the fraction space_. -* ![>](./figs/CurvePrimitives/LineStringFractions.png) -* Hence in the example, with 4 segments the vertex fractions increment by one quarter. -* Within each segment, the fraction interval is mapped as if it were a line segment. -* Note that having uniform vertex-to-vertex fraction means that the distance-along-the-linestring is _not proportional to fraction-along-entire-linestring_. Fraction and distance changes are only proportional within individual segments. +- As with all CurvePrimitives, the fractional parameterization for the complete linestring must have `fraction=0` at the start and `fraction=1` at the end. +- The fractional positions of each interior vertex are then defined at _equal intervals in the fraction space_. +- ![>](./figs/CurvePrimitives/LineStringFractions.png) +- Hence in the example, with 4 segments the vertex fractions increment by one quarter. +- Within each segment, the fraction interval is mapped as if it were a line segment. +- Note that having uniform vertex-to-vertex fraction means that the distance-along-the-linestring is _not proportional to fraction-along-entire-linestring_. Fraction and distance changes are only proportional within individual segments. ## arcs (circular and elliptic) @@ -65,6 +71,7 @@ An arc primitive is a portion of a circular or elliptical arc. The equations f The equational forms for circular and elliptic cases are identical. Telling whether a given arc is true circular requires examination of the vector coordinates. The stroking equation that maps an angle to a coordinates to points around a (full) elliptic (or circular) arc is + ``` C = center point U = vector from center point to 0-degree point @@ -75,11 +82,11 @@ X(theta) = C + cos (theta * U + sin(theta) * V ### True Circles -* If the `U` and `V` vectors are (both) _perpendicular_ and _the same length_, this is a true circle. -* In the both circles below, the `U` and `V` are identical length and perpendicular to each other. -* For the left circle, `U` and `V` happen to be in the global x and y directions. -* For the right circle, `U` and `V` are still identical length and perpendicular, but are both rotated away from global x and y. This still traces a circle, but the "0 degree" point is moved around the circle. -* When the circular arc conditions are true, the angle used _in the equations_ is an the actual physical angle between the `U` vector and the vector from the center to `X(theta)`. +- If the `U` and `V` vectors are (both) _perpendicular_ and _the same length_, this is a true circle. +- In the both circles below, the `U` and `V` are identical length and perpendicular to each other. +- For the left circle, `U` and `V` happen to be in the global x and y directions. +- For the right circle, `U` and `V` are still identical length and perpendicular, but are both rotated away from global x and y. This still traces a circle, but the "0 degree" point is moved around the circle. +- When the circular arc conditions are true, the angle used _in the equations_ is an the actual physical angle between the `U` vector and the vector from the center to `X(theta)`. ![>](./figs/CurvePrimitives/FullCircles.png) @@ -103,9 +110,8 @@ theta(f) = (1-f) * theta0 + f * theta1 X(f) = C + cos (theta(f)) * U + sin(theta(f)) * V ``` - -* Angles theta0 and theta1 can be negative and can be outside of 360 degrees. -* Angle theta1 can be less than theta0 +- Angles theta0 and theta1 can be negative and can be outside of 360 degrees. +- Angle theta1 can be less than theta0 Examples of arc sweep @@ -130,44 +136,45 @@ Internally, the curve is a is a sequence of polynomial curves that join together The "control point" structure has remarkable properties for computation: -* The curve never leaves the overall xyz range of the control points. -* This bounding property applies "from any viewpoint", not just in the coordinate system where they are given. -* Even tighter, the curve is contained within the convex hull of the control points. -* No plane can intersect the curve more often than it intersects the control polygon. - * that is, the polygon may overestimate the number of intersections, (i.e. suggest false intersections), but it never underestimates. -* Inspection of the control polygon gives similar "never underestimate" statements about other properties such as - * the number of inflections. - * the number of minima and maxima of the curve and its derivatives. -* The use of "weights" on the control points allows a bspline curve to exactly trace circular and elliptic arcs without use of trig functions. +- The curve never leaves the overall xyz range of the control points. +- This bounding property applies "from any viewpoint", not just in the coordinate system where they are given. +- Even tighter, the curve is contained within the convex hull of the control points. +- No plane can intersect the curve more often than it intersects the control polygon. + - that is, the polygon may overestimate the number of intersections, (i.e. suggest false intersections), but it never underestimates. +- Inspection of the control polygon gives similar "never underestimate" statements about other properties such as + - the number of inflections. + - the number of minima and maxima of the curve and its derivatives. +- The use of "weights" on the control points allows a bspline curve to exactly trace circular and elliptic arcs without use of trig functions. ## References There are innumerable books and web pages explaining splines. There is a high level of consistency of the concepts -- control points, basis functions, knots, and order. But be very careful about subtle details of indexing. Correct presentations may superficially appear to differ depending on whether the writer has considers `n` indices to run -* C-style, `0 <= i < n` (with index `n` _not_ part of the sequence) -* Fortran style , `1<=i +- +- Be especially careful about the number of knot counts, which can differ by 2 as described in the "over-clamping" section. The `order` of the bspline is the number of control points that are "in effect" over an individual span. -* The first span is controlled by the first `order` control points, i.e. those indexed `0, 1, .. (order-1)`. -* The next span is controlled by control points indexed `1,2,..order`. - * That is, there is a "moving window" of `order` points that control successive spans. - * When moving from one cluster of `order` control points to the next, the first (left) point of the first cluster is dropped and a new one is added at the right. -* The sharing of control points provide the critical properties for the curve: - * No matter how many control points there are (think dozens to hundreds), each individual span is controlled by only `order` points. - * this "local control" prevents changes "far away" in the control points from causing unexpected global changes in the curve. - * The sharing of `order-1` points works into the formulas to guarantee smoothness of the curve. - * Specifically, for a bspline of given `order`: - * If the knots are strictly increasing (no duplicates) the curve has `order-2` (i.e. `degree-1`) continuous derivatives. - * Introducing repeated knots reduces the continuity. In particular, with `order-1` repeated knots there is a cusp (abrupt slope change) at that knot. +- The first span is controlled by the first `order` control points, i.e. those indexed `0, 1, .. (order-1)`. +- The next span is controlled by control points indexed `1,2,..order`. + - That is, there is a "moving window" of `order` points that control successive spans. + - When moving from one cluster of `order` control points to the next, the first (left) point of the first cluster is dropped and a new one is added at the right. +- The sharing of control points provide the critical properties for the curve: + - No matter how many control points there are (think dozens to hundreds), each individual span is controlled by only `order` points. + - this "local control" prevents changes "far away" in the control points from causing unexpected global changes in the curve. + - The sharing of `order-1` points works into the formulas to guarantee smoothness of the curve. + - Specifically, for a bspline of given `order`: + - If the knots are strictly increasing (no duplicates) the curve has `order-2` (i.e. `degree-1`) continuous derivatives. + - Introducing repeated knots reduces the continuity. In particular, with `order-1` repeated knots there is a cusp (abrupt slope change) at that knot. ## Summary @@ -182,108 +189,109 @@ The required data for a bspline curve is: | | |or 4 (cubic curve, degree 3) | | knots | array of `(N + order - 2)` numbers | See knot paragraph | - ## order -* The `order` is the number of control points that affect each span of the curve. -* Bspline equations hypothetically allow any integer `order`. -* For practical use the common orders are quite low - 2,3,4, with occasional 5 through 8 - * `order=2` - the Bspline is a collection of straight lines (degree 1) - * `order=3` - the Bspline is a collection of quadratic curves. (degree = 2) (Quadratic curves with weights can exactly trace circular and elliptic arcs) - * `order=4` - the Bspline is a collection of cubic spans. These can have inflections within a span. - * many graphics systems focus on cubic (`order=4, degree=3` bsplines. These are a good balance of curve flexibility and computational cost. -* Conversationally, if one is thinking of "quadratic" cubic "curves", it is common to refer to the `degree`, which is one less than the order - * the `degree` is the highest power appearing in the polynomial - * A conventional polynomial form would have coefficients of terms with power 1,2, through `degree`. - * That polynomial would also include a constant term that does not multiply a power of x. - * Hence there is _one more coefficient_ than the degree. - * textbook algebra discussions prefer reference to the highest power (`degree`) because that is short indicator of complexity - * Bspline discussion prefers reference to `order` rather than `degree` because all of the internal matrix manipulations must account for that many coefficients. +- The `order` is the number of control points that affect each span of the curve. +- Bspline equations hypothetically allow any integer `order`. +- For practical use the common orders are quite low - 2,3,4, with occasional 5 through 8 + - `order=2` - the Bspline is a collection of straight lines (degree 1) + - `order=3` - the Bspline is a collection of quadratic curves. (degree = 2) (Quadratic curves with weights can exactly trace circular and elliptic arcs) + - `order=4` - the Bspline is a collection of cubic spans. These can have inflections within a span. + - many graphics systems focus on cubic (`order=4, degree=3` bsplines. These are a good balance of curve flexibility and computational cost. +- Conversationally, if one is thinking of "quadratic" cubic "curves", it is common to refer to the `degree`, which is one less than the order + - the `degree` is the highest power appearing in the polynomial + - A conventional polynomial form would have coefficients of terms with power 1,2, through `degree`. + - That polynomial would also include a constant term that does not multiply a power of x. + - Hence there is _one more coefficient_ than the degree. + - textbook algebra discussions prefer reference to the highest power (`degree`) because that is short indicator of complexity + - Bspline discussion prefers reference to `order` rather than `degree` because all of the internal matrix manipulations must account for that many coefficients. ## knots -* The knots are an array of sorted numbers. -* If there are K knots: - * Each cluster of `2*order-2` knots (i.e. `2*degree` knots affects a single span - * The knots index at `knots[i]` through `knots[i+2*order-3]` (inclusive) affect span `i`. - * That knot values for that span are from `knots[i+order-2]` through `knots[i+2*order-2]`. -* Within the knots sequence, the values must never go down. +- The knots are an array of sorted numbers. +- If there are K knots: + - Each cluster of `2*order-2` knots (i.e. `2*degree` knots affects a single span + - The knots index at `knots[i]` through `knots[i+2*order-3]` (inclusive) affect span `i`. + - That knot values for that span are from `knots[i+order-2]` through `knots[i+2*order-2]`. +- Within the knots sequence, the values must never go down. ### Clamping -* If knot values are strictly increasing -- e.g. 1,2,3,4,5, -- all the way to the end, the curve does _not_ pass through the first and last control points. -* Having the right number of identical knot values "at the ends" makes the curve (a) pass through the end control points and (b) have tangent direction towards the immediate neighbor. -* Specifically, for a curve of given `degree`, exactly that number of repeated knots creates the usual "clamped" effects. - * For instance, for a cubic curve, the knots `[0,0,0,0.25,0.5,0.75,1.1.1]` will - * Pass through both end points, with tangent along the end segment of the polygon - * have interior knot breaks at 0.25, 0.5 and 0.75. + +- If knot values are strictly increasing -- e.g. 1,2,3,4,5, -- all the way to the end, the curve does _not_ pass through the first and last control points. +- Having the right number of identical knot values "at the ends" makes the curve (a) pass through the end control points and (b) have tangent direction towards the immediate neighbor. +- Specifically, for a curve of given `degree`, exactly that number of repeated knots creates the usual "clamped" effects. + - For instance, for a cubic curve, the knots `[0,0,0,0.25,0.5,0.75,1.1.1]` will + - Pass through both end points, with tangent along the end segment of the polygon + - have interior knot breaks at 0.25, 0.5 and 0.75. #### OverClamping -* An important point for exchanging knots with legacy graphics systems (including Microstation and Parasolid) is that there is a long-established (an unnecessary) practice of having _one extra (unused) knot at each end_. -* That is, the _overclamped_ cubic knot sequence with breaks at 0.25, 0.5, and 0.75 would be `[0,0,0,0,0.25,0.5,0.75,1.1.1,1]`. -* The equations for the bspline will never reference the extra knots at the beginning and end. -* In the overClamping convention, the relation of counts of control points (N) and (overClamped) knots is + +- An important point for exchanging knots with legacy graphics systems (including Microstation and Parasolid) is that there is a long-established (an unnecessary) practice of having _one extra (unused) knot at each end_. +- That is, the _overclamped_ cubic knot sequence with breaks at 0.25, 0.5, and 0.75 would be `[0,0,0,0,0.25,0.5,0.75,1.1.1,1]`. +- The equations for the bspline will never reference the extra knots at the beginning and end. +- In the overClamping convention, the relation of counts of control points (N) and (overClamped) knots is ... numberOfKnotsWithOverClamping = N + order = numberOfControlPoints + order ... In `imodeljs` -* the spline classes (`BsplineCurve3d`, `BSplineCurve3dH` and surface partners) _internally_ do _not_ over-clamp. -* The API for constructing splines accepts both styles of input. The order, knot count, and control point counts distinguish which style is being used. - * If `numberOfControlPoints === numberOfKnots + order` the curve is overclamped, so the first and last knot values are not saved in the bspline curve object - * If `numberOfControlPoints === numberOfKnots + order - 2` the knots are all used. -* The curve objects have method + +- the spline classes (`BsplineCurve3d`, `BSplineCurve3dH` and surface partners) _internally_ do _not_ over-clamp. +- The API for constructing splines accepts both styles of input. The order, knot count, and control point counts distinguish which style is being used. + - If `numberOfControlPoints === numberOfKnots + order` the curve is overclamped, so the first and last knot values are not saved in the bspline curve object + - If `numberOfControlPoints === numberOfKnots + order - 2` the knots are all used. +- The curve objects have method ... curve.copyKnots(includeExtraEndKnot: boolean) ... to extract knots. The caller can indicate if they prefer overclamped knots by passing `true` for the `includeExtraEndKnot` parameter. -* When knots are written in `iModelJson ` objects, they are written with overclamp. - +- When knots are written in `iModelJson` objects, they are written with overclamp. ## Example: Order 2 (linear) bspline curve -* An order 2 bspline curve has degree 1, i.e. is straight lines -* The circles in the figure for order 2 bspline are both control points and span breaks. - * This is the only order for which the span breaks occur at the control points. -* The direction (first derivative) changes at control point -* Hence there are sharp corners exactly at the control points. +- An order 2 bspline curve has degree 1, i.e. is straight lines +- The circles in the figure for order 2 bspline are both control points and span breaks. + - This is the only order for which the span breaks occur at the control points. +- The direction (first derivative) changes at control point +- Hence there are sharp corners exactly at the control points. ![>](./figs/BCurves/order2.png) ## Example: Order 3 (quadratic) bspline curve -* An order 3 bspline curve has degree 2, i.e. is piecewise quadratic -* The curve does _not_ pass through the control points (dark) -* There are (for uniform interior knots) span breaks (circles) at midpoints of interior edges. -* Span changes (circles) are exactly at the midpoints of polygon edges. -* Direction (slope, first derivative) is continuous at each span change (circles) -* The concavity (second derivative) changes abruptly at each span change (circles) - * This concavity change is not always visually obvious. - * These curves are not as smooth as your eye thinks. -* There are no concavity changes within any single span. -* Clamping (2 identical knots at start, 2 identical knots at end) makes the curve pass through the end control points and point at neighbors. +- An order 3 bspline curve has degree 2, i.e. is piecewise quadratic +- The curve does _not_ pass through the control points (dark) +- There are (for uniform interior knots) span breaks (circles) at midpoints of interior edges. +- Span changes (circles) are exactly at the midpoints of polygon edges. +- Direction (slope, first derivative) is continuous at each span change (circles) +- The concavity (second derivative) changes abruptly at each span change (circles) + - This concavity change is not always visually obvious. + - These curves are not as smooth as your eye thinks. +- There are no concavity changes within any single span. +- Clamping (2 identical knots at start, 2 identical knots at end) makes the curve pass through the end control points and point at neighbors. ![>](./figs/BCurves/order3.png) ## Example: Order 4 (cubic) bspline curve -* An order 4 bspline curve has degree 3, i.e. is piecewise cubic -* The curve does _not_ pass through the control points (dark). -* The curve does _not_ pass through particular points of the polygon edges. -* Span changes (circles) are generally "off the polygon" -* Direction and concavity are both continuous at span changes. -* There can be one concavity change within a span. -* Clamping (3 identical knots at start, 3 identical knots at end) makes the curve pass through the end control points and point at neighbors. +- An order 4 bspline curve has degree 3, i.e. is piecewise cubic +- The curve does _not_ pass through the control points (dark). +- The curve does _not_ pass through particular points of the polygon edges. +- Span changes (circles) are generally "off the polygon" +- Direction and concavity are both continuous at span changes. +- There can be one concavity change within a span. +- Clamping (3 identical knots at start, 3 identical knots at end) makes the curve pass through the end control points and point at neighbors. ![>](./figs/BCurves/order4.png) ## Example: Order 5 (quartic) bspline curve -* An order 5 bspline curve has degree 4, i.e. is piecewise quartic -* The curve does _not_ pass through the control points (dark). -* The curve does _not_ pass through particular points of the polygon edges. -* Span changes (circles) are generally "off the polygon" -* Direction, concavity, and one more derivative are all continuous at span changes. -* There can be two concavity change within a span. -* Clamping (4 identical knots at start, 4 identical knots at end) makes the curve pass the end control points and point at neighbors. +- An order 5 bspline curve has degree 4, i.e. is piecewise quartic +- The curve does _not_ pass through the control points (dark). +- The curve does _not_ pass through particular points of the polygon edges. +- Span changes (circles) are generally "off the polygon" +- Direction, concavity, and one more derivative are all continuous at span changes. +- There can be two concavity change within a span. +- Clamping (4 identical knots at start, 4 identical knots at end) makes the curve pass the end control points and point at neighbors. ![>](./figs/BCurves/order5.png) diff --git a/docs/learning/geometry/EllipsoidPaths.md b/docs/learning/geometry/EllipsoidPaths.md index 45ffc0bacbfe..9fdb069cd27d 100644 --- a/docs/learning/geometry/EllipsoidPaths.md +++ b/docs/learning/geometry/EllipsoidPaths.md @@ -5,19 +5,20 @@ |---|---|---| | Surface with paths | ![>](./figs/Ellipsoid/PerfectSphereWith7Paths.png) | ![>](./figs/Ellipsoid/4x4x1EllipsoidWithPaths.png) | | Closeup | ![>](./figs/Ellipsoid/PerfectSphereCloseup.png) | ![>](./figs/Ellipsoid/4x4x1Closeup.png) | -| The _red_ Arc is intersection of the sphere with
a plane passing through the two endpoints and through the sphere or ellipsoid center.| On the _sphere_
* this is a "great circle"
* its radius equals the sphere radius
the red arc is the shortest path between its on-sphere points. | On the _ellipsoid_
* the intersection is elliptic (not circular)
it is _not_ the _shortest_ path between its endpoints. | -| blue and yellow arcs are intersections of planes containing the two endpoints but _not_ the sphere or ellipse center. | Side arcs are
* always longer paths than the red arc
always _circular_ | Side arcs
can be shorter than the red arc
If the plane is not perpendicular to the principal axes of the ellipsoid, these are _ellipses_ rather than circles | +| The _red_ Arc is intersection of the sphere with
a plane passing through the two endpoints and through the sphere or ellipsoid center.| On the _sphere_
- this is a "great circle"
- its radius equals the sphere radius
the red arc is the shortest path between its on-sphere points. | On the _ellipsoid_
- the intersection is elliptic (not circular)
it is _not_ the _shortest_ path between its endpoints. | +| blue and yellow arcs are intersections of planes containing the two endpoints but _not_ the sphere or ellipse center. | Side arcs are
- always longer paths than the red arc
- always _circular_ | Side arcs
can be shorter than the red arc
If the plane is not perpendicular to the principal axes of the ellipsoid, these are _ellipses_ rather than circles | | | | ## True shortest paths on an ellipsoid -As described in https://en.wikipedia.org/wiki/Geodesic, true shortest paths on an _ellipsoid_ are more complex than on a sphere: -* The section cut by a plane through the center of the ellipsoid is an ellipse. -* Section cuts by slightly other planes (slightly tipped from that central section) can be shorter. - * Among these section cut arcs, an "almost optimal" shortest such arc can be determined by trial and error search. -* The true shortest path is _not_ a planar section cut. - * The true shortest path is the solution of a differential equation (see the wiki link), and does not have an exact parametric curve form. - * Smoothly spaced points along an approximate shortest path can be computed efficiently. +As described in , true shortest paths on an _ellipsoid_ are more complex than on a sphere: + +- The section cut by a plane through the center of the ellipsoid is an ellipse. +- Section cuts by slightly other planes (slightly tipped from that central section) can be shorter. + - Among these section cut arcs, an "almost optimal" shortest such arc can be determined by trial and error search. +- The true shortest path is _not_ a planar section cut. + - The true shortest path is the solution of a differential equation (see the wiki link), and does not have an exact parametric curve form. + - Smoothly spaced points along an approximate shortest path can be computed efficiently. ## API for plane sections @@ -29,29 +30,32 @@ As described in https://en.wikipedia.org/wiki/Geodesic, true shortest paths on a | myArc = ellipsoid.constantLatitudeArc (longitudeSweep, latitudeRadians) | create an arc at constant latitude, with given extent of arc given as longitudeSweep. | | myArc = ellipsoid.constantLongitudeArc (longitudeRadians, latitudeSweep) | create an arc at constant longitude (meridian), with given latitudeSweep | -## API for points on shortest path. +## API for points on shortest path This figure shows a two paths -* starting at the equator to the left -* moving 70 degrees eastward and 10 northward, and (c) move 50 degrees further east and 48 north + +- starting at the equator to the left +- moving 70 degrees eastward and 10 northward, and (c) move 50 degrees further east and 48 north ![>](./figs/Ellipsoid/ShortestPathApproximation.png) The ellipsoid has equator and pole radii of the earth: 6378136.6952 at the equator, 6356751.9952 to the poles. At this level of resolution, it is difficult to discern that there are three nearly overlapping draw components on each portion of the path. -* A (single, yellow) "great arc" of intersection with the plane defined by start and end points and ellipsoid center. - * This is computed by `ellipsoid.radiansPairToGreatArc` -* Alternating red and green arcs that span about 2 degrees each. The endpoints are computed by an approximation algorithm that produces the joints at 2-degree separation. - * The points on this path are computed by `GeodesicPathSolver.createGeodesicPath` -* Almost coincident with the alternating red and green, another, non-central plane intersection, this time with a plane defined by the two endpoints and a true surface normal somwhere along the way, chosen by sampling among about 40 candidates to get the smallest length. - * candidate planes to create section arcs are computed by `ellipsoid.createSectionArcPointPointVectorInPlane` with 40 candidate "in plane" vectors computed based on endpoint surface normals + +- A (single, yellow) "great arc" of intersection with the plane defined by start and end points and ellipsoid center. + - This is computed by `ellipsoid.radiansPairToGreatArc` +- Alternating red and green arcs that span about 2 degrees each. The endpoints are computed by an approximation algorithm that produces the joints at 2-degree separation. + - The points on this path are computed by `GeodesicPathSolver.createGeodesicPath` +- Almost coincident with the alternating red and green, another, non-central plane intersection, this time with a plane defined by the two endpoints and a true surface normal somewhere along the way, chosen by sampling among about 40 candidates to get the smallest length. + - candidate planes to create section arcs are computed by `ellipsoid.createSectionArcPointPointVectorInPlane` with 40 candidate "in plane" vectors computed based on endpoint surface normals This figure is a deep zoom to a portion of the first path section: ![>](./figs/Ellipsoid/EarthPathsCloseup.png) The lines correspond to those noted just above: -* The yellow line is the "great arc" in the plane through the ellipse center -* The alternating red and green arcs are from the approximation. -* The black dashed arc is the arc arc-on-non-central plane. + +- The yellow line is the "great arc" in the plane through the ellipse center +- The alternating red and green arcs are from the approximation. +- The black dashed arc is the arc arc-on-non-central plane. The lengths of the three options are: diff --git a/docs/learning/geometry/FacetNormals.md b/docs/learning/geometry/FacetNormals.md index 94e41db9da59..84bc60e8892d 100644 --- a/docs/learning/geometry/FacetNormals.md +++ b/docs/learning/geometry/FacetNormals.md @@ -1,5 +1,5 @@ -# Using Surface normals to make coarse facets looks smooth. +# Using Surface normals to make coarse facets looks smooth ## Coarse facets on a smooth surface @@ -29,21 +29,20 @@ Here is the same number of facets, with the same grid structure, but with the up Here are three images without the edges drawn. From left to right they have: - * (left) blocky display, with clearly visible breaks between facets - * (middle) smooth display throughout. - * This is good in the portions where the original surface was curved - * This is _not_ good in at the sharp fold edge. It appears to be a roll rather than a crisp edge, and the roll seems to continue into the 4 coplanar facets beyond the fold. - * (right) correct display that is smooth in the curved section, a crisp fold, and then flat within the coplanar facets. +- (left) blocky display, with clearly visible breaks between facets +- (middle) smooth display throughout. + - This is good in the portions where the original surface was curved + - This is _not_ good in at the sharp fold edge. It appears to be a roll rather than a crisp edge, and the roll seems to continue into the 4 coplanar facets beyond the fold. +- (right) correct display that is smooth in the curved section, a crisp fold, and then flat within the coplanar facets. ![>](./figs/GriddedSurfaceExample/FoldedShadingVariants.png) Once again, the display variation is due to how surface normal is presented at each corner of each facet. - * On the left, each facet's corners get the normal of that facets own plane, which of course has a significant angle from those other facets at that vertex. - * In the middle, all the corners near each vertex get a single average normal from all of the (2 or 4) incident facets. Within the smooth part this is good. But at the fold edge, the single normal is not really right for either side. - * On the right, the normals are correctly pulled from either the fold plane or the curved surface. Hence there are multiple distinct normal values _at each vertex along the fold_. + +- On the left, each facet's corners get the normal of that facets own plane, which of course has a significant angle from those other facets at that vertex. +- In the middle, all the corners near each vertex get a single average normal from all of the (2 or 4) incident facets. Within the smooth part this is good. But at the fold edge, the single normal is not really right for either side. +- On the right, the normals are correctly pulled from either the fold plane or the curved surface. Hence there are multiple distinct normal values _at each vertex along the fold_. ![>](./figs/GriddedSurfaceExample/FoldedWithNormals.png) This mixing of smooth patches sharing common edges is pervasive in realistic mechanical models. - - diff --git a/docs/learning/geometry/IModelJsonGeometrySchema.md b/docs/learning/geometry/IModelJsonGeometrySchema.md index 05d7e52bd76b..df9f52cff472 100644 --- a/docs/learning/geometry/IModelJsonGeometrySchema.md +++ b/docs/learning/geometry/IModelJsonGeometrySchema.md @@ -3,31 +3,31 @@ |constructor | remarks | json | |----|----|---| -| LineSegment3d.create | Simple line segment | ` {"lineSegment":[[0,0,0],[4,0,0]]}`| -| LineString3d.create | linestring by points | ` {"lineString":[[0,0,0],[4,0,0],[4,4,0],[0,4,0]]}`| -| Arc3d.createCircularStartMiddleEnd | arc passing through 3 points | ` {"arc":{"center":[2,2.000000000000001,0],"vectorX":[-2,-2.000000000000001,0],"vectorY":[2.000000000000001,-2,0],"sweepStartEnd":[0,179.99999999999997]}}`| -| Arc3d.create | circular arc | ` {"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[-45,90]}}`| -| Arc3d.create | elliptic arc | ` {"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,12,0],"sweepStartEnd":[-45,190]}}`| -| BSplineCurve3d.create | curve by poles | ` {"bcurve":{"points":[[0,0,0],[4,0,0],[4,4,0],[0,4,0]],"knots":[0,0,0,0,1,1,1,1],"closed":false,"order":4}}`| +| LineSegment3d.create | Simple line segment | `{"lineSegment":[[0,0,0],[4,0,0]]}`| +| LineString3d.create | linestring by points | `{"lineString":[[0,0,0],[4,0,0],[4,4,0],[0,4,0]]}`| +| Arc3d.createCircularStartMiddleEnd | arc passing through 3 points | `{"arc":{"center":[2,2.000000000000001,0],"vectorX":[-2,-2.000000000000001,0],"vectorY":[2.000000000000001,-2,0],"sweepStartEnd":[0,179.99999999999997]}}`| +| Arc3d.create | circular arc | `{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[-45,90]}}`| +| Arc3d.create | elliptic arc | `{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,12,0],"sweepStartEnd":[-45,190]}}`| +| BSplineCurve3d.create | curve by poles | `{"bcurve":{"points":[[0,0,0],[4,0,0],[4,4,0],[0,4,0]],"knots":[0,0,0,0,1,1,1,1],"closed":false,"order":4}}`| ## CurveCollections |constructor | remarks | json | |----|----|---| -| Path.create | path with line, arc, line | ` {"path":[{"lineSegment":[[4,4,0],[4,0,0]]},{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[0,0,0]]}]}`| -| Loop.create | loop with semicircle and diameter segment | ` {"loop":[{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[4,0,0]]}]}`| -| ParityRegion.create | rectangle with semicirular hole | ` {"parityRegion":[{"loop":[{"lineString":[[-4.5,-4.5,0],[4.5,-4.5,0],[4.5,4.5,0],[-4.5,4.5,0],[-4.5,-4.5,0]]}]},{"loop":[{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[4,0,0]]}]}]}`| +| Path.create | path with line, arc, line | `{"path":[{"lineSegment":[[4,4,0],[4,0,0]]},{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[0,0,0]]}]}`| +| Loop.create | loop with semicircle and diameter segment | `{"loop":[{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[4,0,0]]}]}`| +| ParityRegion.create | rectangle with semicirular hole | `{"parityRegion":[{"loop":[{"lineString":[[-4.5,-4.5,0],[4.5,-4.5,0],[4.5,4.5,0],[-4.5,4.5,0],[-4.5,-4.5,0]]}]},{"loop":[{"arc":{"center":[0,0,0],"vectorX":[4,0,0],"vectorY":[0,4,0],"sweepStartEnd":[0,180]}},{"lineSegment":[[-4,4.898587196589413e-16,0],[4,0,0]]}]}]}`| ## SolidPrimitive types |constructor | remarks | json | |----|----|---| -| Sphere.createCenterRadius(center, radius) | full sphere | ` {"sphere":{"center":[1,1,0],"radius":3}}`| -| Cone.createAxisPoints(centerA, centerB, radiusA, radiusB, capped) | full sphere | ` {"cone":{"capped":true,"start":[-1,1,0],"end":[3,2,0],"startRadius":1.5,"endRadius":2,"xyVectors":[[-0.24253562503633297,0.9701425001453319,0],[0,0,1]]}}`| -| Box.createDgnBox(cornerA, xVector, yVector, baseX, baseY, topX, topY, capped) | box with sides slanting inward | ` {"box":{"baseOrigin":[-1,1,0],"baseX":4,"baseY":3,"capped":true,"topOrigin":[-1,2,4],"topY":2}}`| -| TorusPipe.createInFrame(frame, majorRadius, minorRadius, sweep, capped) | 90 degree elbos | ` {"torusPipe":{"center":[1,1,1],"majorRadius":3,"minorRadius":1,"xyVectors":[[0,1,0],[-0.8320502943378437,0,0.5547001962252291]],"sweepAngle":90,"capped":true}}`| -| LinearSweep.create(contour, sweepVector, capped) | swept hexagon | ` {"linearSweep":{"contour":{"loop":[{"lineString":[[2,0,0],[1.5,0.8660254037844386,0],[0.5,0.8660254037844387,0],[0,0,0],[0.5,-0.8660254037844385,0],[1.5,-0.866025403784439,0],[2,0,0]]}]},"capped":true,"vector":[0,0,4]}}`| -| RotationalSweep.create(contour, axisOfRotation, sweepAngle, capped) | hexagon rotated | ` {"rotationalSweep":{"axis":[0,1,0],"contour":{"loop":[{"lineString":[[2,0,0],[1.5,0.8660254037844386,0],[0.5,0.8660254037844387,0],[0,0,0],[0.5,-0.8660254037844385,0],[1.5,-0.866025403784439,0],[2,0,0]]}]},"capped":true,"center":[-1,0,0],"sweepAngle":135}}`| +| Sphere.createCenterRadius(center, radius) | full sphere | `{"sphere":{"center":[1,1,0],"radius":3}}`| +| Cone.createAxisPoints(centerA, centerB, radiusA, radiusB, capped) | full sphere | `{"cone":{"capped":true,"start":[-1,1,0],"end":[3,2,0],"startRadius":1.5,"endRadius":2,"xyVectors":[[-0.24253562503633297,0.9701425001453319,0],[0,0,1]]}}`| +| Box.createDgnBox(cornerA, xVector, yVector, baseX, baseY, topX, topY, capped) | box with sides slanting inward | `{"box":{"baseOrigin":[-1,1,0],"baseX":4,"baseY":3,"capped":true,"topOrigin":[-1,2,4],"topY":2}}`| +| TorusPipe.createInFrame(frame, majorRadius, minorRadius, sweep, capped) | 90 degree elbos | `{"torusPipe":{"center":[1,1,1],"majorRadius":3,"minorRadius":1,"xyVectors":[[0,1,0],[-0.8320502943378437,0,0.5547001962252291]],"sweepAngle":90,"capped":true}}`| +| LinearSweep.create(contour, sweepVector, capped) | swept hexagon | `{"linearSweep":{"contour":{"loop":[{"lineString":[[2,0,0],[1.5,0.8660254037844386,0],[0.5,0.8660254037844387,0],[0,0,0],[0.5,-0.8660254037844385,0],[1.5,-0.866025403784439,0],[2,0,0]]}]},"capped":true,"vector":[0,0,4]}}`| +| RotationalSweep.create(contour, axisOfRotation, sweepAngle, capped) | hexagon rotated | `{"rotationalSweep":{"axis":[0,1,0],"contour":{"loop":[{"lineString":[[2,0,0],[1.5,0.8660254037844386,0],[0.5,0.8660254037844387,0],[0,0,0],[0.5,-0.8660254037844385,0],[1.5,-0.866025403784439,0],[2,0,0]]}]},"capped":true,"center":[-1,0,0],"sweepAngle":135}}`| |||| ## Isolated point diff --git a/docs/learning/geometry/PlanarSubdivision.md b/docs/learning/geometry/PlanarSubdivision.md index c2252787a1ff..a3ca7e0b13ac 100644 --- a/docs/learning/geometry/PlanarSubdivision.md +++ b/docs/learning/geometry/PlanarSubdivision.md @@ -1,21 +1,23 @@ # PlanarSubdivisions -## `RegionOps.constructAllXYRegionLoops(candidates: BagOfCurves | AnyCurve[]): SignedLoops`; +## `RegionOps.constructAllXYRegionLoops(candidates: BagOfCurves | AnyCurve[]): SignedLoops` In the input - * there can be many curves - * the curves can be present as (a mixture of) (a) isolated curve primitives, (b) structured paths, loops, etc. - * no assumptions are made about the about structure of the curves. The analysis considers on the leaf level primitives. + +- there can be many curves +- the curves can be present as (a mixture of) (a) isolated curve primitives, (b) structured paths, loops, etc. +- no assumptions are made about the about structure of the curves. The analysis considers on the leaf level primitives. The method will -* Find all intersections among (planar xy) curve primitives in the `candidates`. -* From the fragments of curves as split by the intersections, constructs loops. -* Return as 3 sets of `Loops`: positive area loops, negative area loops - * Among these loops, the positive area loops collectively cover the entire interior - * Among these loops, the negative area loops traverse the outer boundary if each connected component of curves. +- Find all intersections among (planar xy) curve primitives in the `candidates`. +- From the fragments of curves as split by the intersections, constructs loops. +- Return as 3 sets of `Loops`: positive area loops, negative area loops + - Among these loops, the positive area loops collectively cover the entire interior + - Among these loops, the negative area loops traverse the outer boundary if each connected component of curves. The region is a `SignedLoops` object containing various loops identified by constructAllXYRegionLoops: -``` + +```ts export interface SignedLoops { /** Array of loops that have positive area sign. (i.e. counterclockwise loops) */ positiveAreaLoops: Loop[]; @@ -26,7 +28,6 @@ export interface SignedLoops { } ``` - | | | |---|---| | Input: various lines and arcs that crisscross.
Note that the various intersections among curves are NOT endpoints in the input | ![>](./figs/PlanarSubdivision/CrossingLinesInput.png) | @@ -34,7 +35,8 @@ export interface SignedLoops { | Output: `negativeAreaLoops` geometry for the various separated regions | ![>](./figs/PlanarSubdivision/CrossingLineNegativeAreaLoops.png) | Unit Test - * source: imodeljs\core\geometry\src\test\curve\Region.test.ts + +- source: imodeljs\core\geometry\src\test\curve\Region.test.ts | | | | | |---|---|---|---| @@ -54,6 +56,7 @@ This illustrates using `RegionOps.constructAllXYRegionLoops` to unscramble inter | Output: `ParityRegion` using the outermost (negative) areas of the two components | ![>](./figs/PlanarSubdivision/MultiComponentParityOut.png) | Unit Test - * source: imodeljs\core\geometry\src\test\curve\Region.test.ts - * test name: "RegionBoolean.Holes - * output file: imodeljs/core/geometry/src/test/output/Holes.imjs + +- source: imodeljs\core\geometry\src\test\curve\Region.test.ts +- test name: "RegionBoolean.Holes +- output file: imodeljs/core/geometry/src/test/output/Holes.imjs diff --git a/docs/learning/geometry/PointVector.md b/docs/learning/geometry/PointVector.md index cb4e1feed084..6a7073e400f2 100644 --- a/docs/learning/geometry/PointVector.md +++ b/docs/learning/geometry/PointVector.md @@ -1,13 +1,13 @@ # Point and Vector operations -# Notes on compact table notation +## Notes on compact table notation -* Many arguments which might be strongly typed as `Point3d`, `Vector3d`, `Point3d`, `Vector3d` are weakly typed as `XYandZ` or `XandY`. - * These allow any object that has `x` and `y` properties to be passed as inputs. -* Many methods have optional result args. - * The optional arg is NOT indicated here. - * If the caller supplies the optional arg, that preexisting object will be reinitialized. - * If a method is being called many times in a loop, reusing a result can give a significant performance benefit. +- Many arguments which might be strongly typed as `Point3d`, `Vector3d`, `Point3d`, `Vector3d` are weakly typed as `XYandZ` or `XandY`. + - These allow any object that has `x` and `y` properties to be passed as inputs. +- Many methods have optional result args. + - The optional arg is NOT indicated here. + - If the caller supplies the optional arg, that preexisting object will be reinitialized. + - If a method is being called many times in a loop, reusing a result can give a significant performance benefit. Typical names in the tables are: @@ -123,8 +123,8 @@ Typical names in the tables are: ## Angles between vectors -* Methods that return bare radians have *radians* in the method name. -* Methods without specific *radians* indication return a (strongly typed) `Angle` object that can be queried for `degrees` or `radians`. +- Methods that return bare radians have *radians* in the method name. +- Methods without specific *radians* indication return a (strongly typed) `Angle` object that can be queried for `degrees` or `radians`. | category | Point3d | Vector3d | Point2d | Vector2d | |---|---|---|---|---| diff --git a/docs/learning/geometry/PolyfaceAuxData.md b/docs/learning/geometry/PolyfaceAuxData.md index 2095a839b28c..ece37559386e 100644 --- a/docs/learning/geometry/PolyfaceAuxData.md +++ b/docs/learning/geometry/PolyfaceAuxData.md @@ -16,8 +16,8 @@ Display Styles and Analysis Style. In iModel.js [DisplayStyleSettings]($common) contains a group of display settings. A single [DisplayStyleSettings]($common) can be shared by on or more views. The [AnalysisStyle]($common) member of [DisplayStyleSettings]($common) contains settings that control the display of [PolyfaceAuxData]($geometry). An [AnalysisStyle]($common) may include: -* A single displacement channel. A displacementScale may be included to exaggerate or attenuate the displacement. -* A single scalar channel, the scalar channel range and the thematic gradient to display the scalar data (`ThematicGradientSettings`). In the images below the same mesh is displayed with two different [AnalysisStyle]($common)s. +- A single displacement channel. A displacementScale may be included to exaggerate or attenuate the displacement. +- A single scalar channel, the scalar channel range and the thematic gradient to display the scalar data (`ThematicGradientSettings`). In the images below the same mesh is displayed with two different [AnalysisStyle]($common)s. ___ @@ -25,91 +25,90 @@ ___ ![>](./figs/PolyfaceAuxData/RadialWaveHeight.gif) ![>](./figs/PolyfaceAuxData/RadialWaveSlope.gif) - Example ---- An example creating a fictitious analytical mesh is included in the "analysis-importer" test application. The application begins by creating the flat rectangular [Polyface]($geometry) with 100 rows and columns... ```ts - const options = StrokeOptions.createForFacets(); - options.shouldTriangulate = true; - const builder = PolyfaceBuilder.create(options); - const nDimensions = 100; - const spacing = 1.0; - - /** Create a simple flat mesh with 10,000 points (100x100) */ - for (let iRow = 0; iRow < nDimensions - 1; iRow++) { - for (let iColumn = 0; iColumn < nDimensions - 1; iColumn++) { - const quad = [Point3d.create(iRow * spacing, iColumn * spacing, 0.0), - Point3d.create((iRow + 1) * spacing, iColumn * spacing, 0.0), - Point3d.create((iRow + 1) * spacing, (iColumn + 1) * spacing, 0.0), - Point3d.create(iRow * spacing, (iColumn + 1) * spacing)]; - builder.addQuadFacet(quad); - } +const options = StrokeOptions.createForFacets(); +options.shouldTriangulate = true; +const builder = PolyfaceBuilder.create(options); +const nDimensions = 100; +const spacing = 1.0; + +/** Create a simple flat mesh with 10,000 points (100x100) */ +for (let iRow = 0; iRow < nDimensions - 1; iRow++) { + for (let iColumn = 0; iColumn < nDimensions - 1; iColumn++) { + const quad = [Point3d.create(iRow * spacing, iColumn * spacing, 0.0), + Point3d.create((iRow + 1) * spacing, iColumn * spacing, 0.0), + Point3d.create((iRow + 1) * spacing, (iColumn + 1) * spacing, 0.0), + Point3d.create(iRow * spacing, (iColumn + 1) * spacing)]; + builder.addQuadFacet(quad); } +} ``` Once the mesh is created the scalar and displacement data is created as number arrays. For the purpose of this example we create a zero channel so that the initial state of the mesh has no displacement and zero scalar values and then produce a scalar channels representing the displacement with a radial wave super imposed on the mesh as well as scalar channels that represent the height and slope of the mesh. Note that a single value is pushed for scalar channel data, while the displacement requires 3 values. ```ts - const zeroScalarData = [], - zeroDisplacementData = [], - radialHeightData = [], - radialSlopeData = [], - const radius = nDimensions * spacing / 2.0; - const center = new Point3d(radius, radius, 0.0); - const maxHeight = radius / 4.0; - const auxChannels = []; - - /** Create a radial wave - start and return to zero */ - for (let i = 0; i < polyface.data.point.length; i++) { - const angle = Angle.pi2Radians * polyface.data.point.distanceIndexToPoint(i, center) / radius; - const height = maxHeight * Math.sin(angle); - const slope = Math.abs(Math.cos(angle)); - - zeroScalarData.push(0.0); - zeroDisplacementData.push(0.0); - zeroDisplacementData.push(0.0); - zeroDisplacementData.push(0.0); - - radialHeightData.push(height); - radialSlopeData.push(slope); - radialDisplacementData.push(0.0); - radialDisplacementData.push(0.0); - radialDisplacementData.push(height); - } +const zeroScalarData = [], + zeroDisplacementData = [], + radialHeightData = [], + radialSlopeData = [], +const radius = nDimensions * spacing / 2.0; +const center = new Point3d(radius, radius, 0.0); +const maxHeight = radius / 4.0; +const auxChannels = []; + +/** Create a radial wave - start and return to zero */ +for (let i = 0; i < polyface.data.point.length; i++) { + const angle = Angle.pi2Radians * polyface.data.point.distanceIndexToPoint(i, center) / radius; + const height = maxHeight * Math.sin(angle); + const slope = Math.abs(Math.cos(angle)); + + zeroScalarData.push(0.0); + zeroDisplacementData.push(0.0); + zeroDisplacementData.push(0.0); + zeroDisplacementData.push(0.0); + + radialHeightData.push(height); + radialSlopeData.push(slope); + radialDisplacementData.push(0.0); + radialDisplacementData.push(0.0); + radialDisplacementData.push(height); +} ``` Next we take the channel data and create an array [AuxChannelData]($geometry) entries for aach channel. The first argument of the [AuxChannelData]($geometry) constructor is the "input" value. This represents the external input value that produces this data. This may be a quantity such as force in a stress analysis application or time in a simple animation. ```ts - const radialDisplacementDataVector = - [new AuxChannelData(0.0, zeroDisplacementData), - new AuxChannelData(1.0, radialDisplacementData), - new AuxChannelData(2.0, zeroDisplacementData)]; - const radialHeightDataVector = - [new AuxChannelData(0.0, zeroScalarData), - new AuxChannelData(1.0, radialHeightData), - new AuxChannelData(2.0, zeroScalarData)]; - const radialSlopeDataVector = - [new AuxChannelData(0.0, zeroScalarData), - new AuxChannelData(1.0, radialSlopeData), - new AuxChannelData(2.0, zeroScalarData)]; +const radialDisplacementDataVector = + [new AuxChannelData(0.0, zeroDisplacementData), + new AuxChannelData(1.0, radialDisplacementData), + new AuxChannelData(2.0, zeroDisplacementData)]; +const radialHeightDataVector = + [new AuxChannelData(0.0, zeroScalarData), + new AuxChannelData(1.0, radialHeightData), + new AuxChannelData(2.0, zeroScalarData)]; +const radialSlopeDataVector = + [new AuxChannelData(0.0, zeroScalarData), + new AuxChannelData(1.0, radialSlopeData), + new AuxChannelData(2.0, zeroScalarData)]; ``` We next create the AuxChannels. The channel names provideed in the [AuxChannel]($geometry) constructor are used to present the channel to the user as well as keys to select the channel from [AnalysisStyle]($common)s. ```ts - auxChannels.push(new AuxChannel(radialDisplacementDataVector, AuxChannelDataType.Vector, "Radial Displacement", "Radial: Time")); - auxChannels.push(new AuxChannel(radialHeightDataVector, AuxChannelDataType.Distance, "Radial Height", "Radial: Time")); - auxChannels.push(new AuxChannel(radialSlopeDataVector, AuxChannelDataType.Scalar, "Radial Slope", "Radial: Time")); +auxChannels.push(new AuxChannel(radialDisplacementDataVector, AuxChannelDataType.Vector, "Radial Displacement", "Radial: Time")); +auxChannels.push(new AuxChannel(radialHeightDataVector, AuxChannelDataType.Distance, "Radial Height", "Radial: Time")); +auxChannels.push(new AuxChannel(radialSlopeDataVector, AuxChannelDataType.Scalar, "Radial Slope", "Radial: Time")); ``` The final step is to create [PolyfaceAuxData]($geometry) and associate it to our base `Polyface'. A set of indices is required to map the channel data values into the facets. In our case, we have produced the channel data in parallel with the mesh points so that we can simply use point indices "polyface.data.pointIndex", but this is not required and alternate indexing could also be used. Not e that only a single index structure is supplied and shared by all channels and their data, therefore all channels data arrays must have same number of values and indexing. ```ts - polyface.data.auxData = new PolyfaceAuxData(auxChannels, polyface.data.pointIndex); +polyface.data.auxData = new PolyfaceAuxData(auxChannels, polyface.data.pointIndex); ``` Run the example by entering "node test-apps/analysis-importer/lib/Main.js" in a command shell with CWD set to repository root. The output is "test-apps/analysis-importer/lib/output/AnalysisExample.bim". diff --git a/docs/learning/geometry/PolyfaceBuilder.md b/docs/learning/geometry/PolyfaceBuilder.md index 60a84356e19c..38734f8ab8c2 100644 --- a/docs/learning/geometry/PolyfaceBuilder.md +++ b/docs/learning/geometry/PolyfaceBuilder.md @@ -7,14 +7,9 @@ A caller creates a builder and then calls various methods to add to the evolving There are 3 levels of detail for builder methods: - - - - | Level | Input type | Example | Actions | |---------------|-------------------|--------------|--------------| | High | GeometryQuery object | addGeometryQuery addBox addCone addSphere addTorusPipe add LinearSweep addRotationalSweep addRuledSweep addPolygon addIndexedPolyface | call mid- or low- level methods for major parts (sides, caps) of the geometry query. | | mid | Single-parameter space portions | addUVGrid addBetweenLineStrings addBetweenStroked addBetweenTransformedLineStrings addGraph | enumerate quad and triangles in the grid/circle/polygon | | single or structured facet | single facet | addIndexedQuadNormalIndexes addIndexedQuadParamIndexes addIndexedQuadPointIndexes addIndexedTriangleNormalIndexes addIndexedTriangleParamIndexes addIndexedTrianglePointIndexes addTriangleFan addTrianglesInUncheckedFan addTriangleFanFromIndex0 | multiple inserts to arrays | | array entry | single datum for array | findOrAddPoint findorAddPointInLineString findOrAddPointXYZ | | - diff --git a/docs/learning/geometry/PolyfaceClip.md b/docs/learning/geometry/PolyfaceClip.md index 4cbdf8c6bf72..b8828aec7464 100644 --- a/docs/learning/geometry/PolyfaceClip.md +++ b/docs/learning/geometry/PolyfaceClip.md @@ -7,31 +7,31 @@ |---|---| | red and green meshes | ![>](./figs/PolyfaceClip/CutFillAInput.png)
![>](./figs/PolyfaceClip/CutFillAInputTransparent.png) | | Compute "over and under" mesh parts
(red is meshA, green is meshB) | `const cutFill = PolyfaceClip.computeCutFill(meshA, meshB);` | -| `cutFill.meshAOverB` |![>](./figs/PolyfaceClip/CutFillARedOverGreen.png) ` | -| `cutFill.meshBOverA` |![>](./figs/PolyfaceClip/CutFillAGreenOverRed.png) ` | - +| `cutFill.meshAOverB` |![>](./figs/PolyfaceClip/CutFillARedOverGreen.png) `| +|`cutFill.meshBOverA` |![>](./figs/PolyfaceClip/CutFillAGreenOverRed.png) ` | Unit Test - * source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts - * test name: "CutFill" - * output: imodeljs\core\geometry\src\test\output\PolyfaceClip\CutFill.imjs +- source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts +- test name: "CutFill" +- output: imodeljs\core\geometry\src\test\output\PolyfaceClip\CutFill.imjs ## Section Cut | | | |---|---| | grey: closed volume mesh
green: section plane | ![>](./figs/PolyfaceClip/SectionCut/MeshVolumeAndPlane.png) | -| extract linework of section cut | ` const section = PolyfaceClip.sectionPolyfaceClipPlane(facets, clipPlane);` | +| extract linework of section cut | `const section = PolyfaceClip.sectionPolyfaceClipPlane(facets, clipPlane);` | | This produces an array of `LineString3d` | ![>](./figs/PolyfaceClip/SectionCut/SectionCutAsLines.png) | | Clip the facet set and produce facets on the cut plane
`insideClip` is a boolean controlling which side of the cut is kept. |` const clippedPolyface = PolyfaceClip.clipPolyfaceClipPlaneWithClosureFace(facets, clipPlane, insideClip, true);' | | Lower and upper parts | ![>](./figs/PolyfaceClip/SectionCut/LowerAndUpperParts.png) Unit Test: - * source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts - * test name: "ClosedSection" - * output: imodeljs\core\geometry\src\test\output\PolyfaceClip\ClosedSection.imjs + +- source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts +- test name: "ClosedSection" +- output: imodeljs\core\geometry\src\test\output\PolyfaceClip\ClosedSection.imjs ## Clipping with ConvexClipPlaneSet or UnionOfConvexClipPlaneSet @@ -45,8 +45,8 @@ Unit Test: | Extract the inside part | `insidePart = clipBuilders.claimPolyface(0, true);`
![>](./figs/PolyfaceClip/ClipSets/InsidePart.png)| | Extract the outside part | `insidePart = clipBuilders.claimPolyface(1, true);`
![>](./figs/PolyfaceClip/ClipSets/OutsidePart.png)| - Unit Test: - * source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts - * test name: "BoxClosureNonConvex" - * output: imodeljs\core\geometry\src\test\output\PolyfaceClip\BoxClosureNonConvex.imjs + +- source: imodeljs\core\geometry\src\test\clipping\PolyfaceClip.test.ts +- test name: "BoxClosureNonConvex" +- output: imodeljs\core\geometry\src\test\output\PolyfaceClip\BoxClosureNonConvex.imjs diff --git a/docs/learning/geometry/PolyfaceIndexPairing.md b/docs/learning/geometry/PolyfaceIndexPairing.md index 55de18b563e6..4b340524a71a 100644 --- a/docs/learning/geometry/PolyfaceIndexPairing.md +++ b/docs/learning/geometry/PolyfaceIndexPairing.md @@ -5,9 +5,10 @@ In order to act as a closed volume, facet indices must be oriented so all faces When this visual condition is met, a _necessary_ (but not complete) condition each edge must be part of exactly two facets, and the order of the edge's vertex indices must be opposite. That is, for an edge with vertices X and Y - * There must be two facets that "use" that edge - * One of the facets must have its vertices indices with "X immediately followed by Y" - * One of the facets must have its vertices indices with "Y immediately followed by X" + +- There must be two facets that "use" that edge +- One of the facets must have its vertices indices with "X immediately followed by Y" +- One of the facets must have its vertices indices with "Y immediately followed by X" If some index pair XY appears only _once_, it is a boundary edge, with a "hole" on the other side. @@ -16,25 +17,27 @@ If an index pair XY appears more than twice, there is a "non-manifold" condition If the faces close physically but have incorrect orientation, edges "between" the mismatched orientation will have XY appear in the same order in each. In the cube below: -* In the upper row, the indices are correct - * All facets are counterclockwise from the outside. -* In the lower row, the BGFC "right" facet has its order reversed to FGBC - * this is clockwise from the outside. - * Index inspection will show that BC appears (with BC order) in both front and right facets. - * The other three edges FC, FG, and GB will have the same issue. + +- In the upper row, the indices are correct + - All facets are counterclockwise from the outside. +- In the lower row, the BGFC "right" facet has its order reversed to FGBC + - this is clockwise from the outside. + - Index inspection will show that BC appears (with BC order) in both front and right facets. + - The other three edges FC, FG, and GB will have the same issue. ![>](./figs/Polyface/PolyfaceIndexPairing.png) ## Testing for closure, Extracting boundary edges The (static) method `PolyfaceQuery.isPolyfaceClosedByEdgePairing(polyface) -* Examines all facets -* tests if every facet edge has exactly one properly paired partner -* Returns true if all partners are found -* Returns false if any facet edges have either (a) not partner, (b) more than one partner with the same indices or (c) a partner with indices that are not reversed. + +- Examines all facets +- tests if every facet edge has exactly one properly paired partner +- Returns true if all partners are found +- Returns false if any facet edges have either (a) not partner, (b) more than one partner with the same indices or (c) a partner with indices that are not reversed. | | | | ---|---|---| | Geometry | ![>](./figs/Polyface/CappedCone.png) |![>](./figs/Polyface/UncappedCone.png) | | return from `PolyfaceQuery.isPolyfaceClosedByEdgePairing` | `true` | `false` | -| return from `PolyfaceQuery.boundaryEdges () ` | (none !!) | ![>](./figs/Polyface/UncappedConeBoundaryEdges.png)| +| return from `PolyfaceQuery.boundaryEdges ()` | (none !!) | ![>](./figs/Polyface/UncappedConeBoundaryEdges.png)| diff --git a/docs/learning/geometry/PolyfaceQuery.md b/docs/learning/geometry/PolyfaceQuery.md index e2c8e32c65bc..fa52b317f1ec 100644 --- a/docs/learning/geometry/PolyfaceQuery.md +++ b/docs/learning/geometry/PolyfaceQuery.md @@ -13,11 +13,11 @@ | extract as separate meshes | const fragmentPolyfaces = PolyfaceQuery.clonePartitions(polyface, facetIndexArraysWithEdgeConnectivity);| | 3 separate Polyface objects (blue, drab, magenta), each with at least edge-to-edge connectivity | ![>](./figs/PolyfaceQuery/PartitionByConnectivity/SplitByEdgeConnectivity.png)| - Unit Test - * source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts - * test name: "PartitionFacetIndicesByConnectivity" - * output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/PartitionFacetsByConnectivity.imjs + +- source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts +- test name: "PartitionFacetIndicesByConnectivity" +- output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/PartitionFacetsByConnectivity.imjs ## Fixup TVertices @@ -27,11 +27,11 @@ Unit Test | Skeletal display with circles near each vertex of each facet
The circles indicate that each facet references only its actual corners
Red highlight shows "TVertex" situations | ![>](./figs/PolyfaceQuery/TVertexFixup/AllQuadsSectorMarkup.png) | | After calling `PolyfaceQuery.cloneWithTVertexFixup` the long edges that passed through the T-Vertex
have vertices inserted
The two larger "squares" now reference (left of center) 9 and (upper right) 6 vertices | ![>](./figs/PolyfaceQuery/TVertexFixup/FixupSectorMarkup.png) | - Unit Test - * source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts - * test name: "cloneWithTVertexFixup" - * output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/cloneWithTVertexFixup.imjs + +- source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts +- test name: "cloneWithTVertexFixup" +- output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/cloneWithTVertexFixup.imjs ## Fixup Colinear Edges @@ -45,9 +45,10 @@ Unit Test Note that colinearEdgeFixup and TVertexFixup have tricky interactions. If colinearEdgeFixup is applied to the final figure (blue markup) of the TVertexFixup section (above), the locally colinear edges within the large rectangles are _not_ removed. This the colinear edge logic will notice that those vertices are incident to other facets where the vertex is a true corner, and hence should not be removed. Unit Test - * source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts - * test name: "cloneWithColinearEdgeFixup" - * output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/cloneWithColinearEdgeFixup.imjs + +- source: imodeljs/core/geometry/src/test/clipping/PolyfaceQuery.test.ts +- test name: "cloneWithColinearEdgeFixup" +- output: imodeljs/core/geometry/src/test/output/PolyfaceQuery/cloneWithColinearEdgeFixup.imjs ## Mark Edge Visibility @@ -65,14 +66,8 @@ During default construction by a `PolyfaceBuilder` all edges are marked visible | Apply `PolyfaceQuery.markPairedEdgesInvisible(mesh, Angle.createDegrees (30)));`
this hides edges with adjacent facet angle less than 30 degrees.
(Edges within the flat caps are hidden. Visibility in the torus body varies.) | ![>](./figs/PolyfaceQuery\EdgeVisibility\TorusPipeHide30.png) | | Apply `PolyfaceQuery.markPairedEdgesInvisible(mesh, Angle.createDegrees (50)));`
this hides edges with adjacent facet angle less than 50 degrees.
(Edges within the flat caps are hidden. The only visible edges are at the 90 degree angles around the caps) | ![>](./figs/PolyfaceQuery\EdgeVisibility\TorusPipeHide50.png) | - Unit Test - * source: imodeljs/core/geometry/src/test/clipping/Polyface.test.ts - * test name: "SolidPrimitiveBoundary" - * output: imodeljs/core/geometry/src/test/output/Polyface\SolidPrimitiveBoundary.imjs - - - - - +- source: imodeljs/core/geometry/src/test/clipping/Polyface.test.ts +- test name: "SolidPrimitiveBoundary" +- output: imodeljs/core/geometry/src/test/output/Polyface\SolidPrimitiveBoundary.imjs diff --git a/docs/learning/geometry/RegionOps.md b/docs/learning/geometry/RegionOps.md index 815ccb825514..555855638936 100644 --- a/docs/learning/geometry/RegionOps.md +++ b/docs/learning/geometry/RegionOps.md @@ -8,7 +8,7 @@ This splits any curve into parts in, on, and outside an xy region. | | | |---|---| | 25 points | ![>](./figs/RegionOps/splitPathsByRegionInOnOutXY/InOutSplitsInput.png) | -| split the black path into parts inside and outside the grey area | ` const splitParts = RegionOps.splitPathsByRegionInOnOutXY(path, loop);`| +| split the black path into parts inside and outside the grey area | `const splitParts = RegionOps.splitPathsByRegionInOnOutXY(path, loop);`| | (red) Path parts "inside" the region
`splitParts.insideParts`| ![>](./figs/RegionOps/splitPathsByRegionInOnOutXY/InOutSplitsInsidePart.png) | | (green) Path parts "outside" the region
`splitParts.outsideParts`| ![>](./figs/RegionOps/splitPathsByRegionInOnOutXY/InOutSplitsOutsidePart.png) | @@ -23,12 +23,11 @@ Using a closed region as the cutter is a specialized high level operation, just | (a) obtain one point on a fragment being tested |`const pointOnChild = CurveCollection.createCurveLocationDetailOnAnyCurvePrimiitive(splitPaths);` | | (b) determine if that single point is inside or outside.
since the fragments have no interior crossings, that point classifies the whole fragment | `const inOnOut = RegionOps.testPointInOnOutRegionXY(region, pointOnChild.point.x, pointOnChild.point.y);` | - - Unit Test - * source: imodeljs\core\geometry\src\test\topology\RegionOps.test.ts - * test name: "InOutSplits" - * output: imodeljs\core\geometry\src\test\output\RegionOps\InOutSplits.imjs + +- source: imodeljs\core\geometry\src\test\topology\RegionOps.test.ts +- test name: "InOutSplits" +- output: imodeljs\core\geometry\src\test\output\RegionOps\InOutSplits.imjs ## RegionOps.testPointInOnOutRegionXY @@ -38,11 +37,11 @@ This tests whether single points are in, out, or on an xy region. |---|---| | Parity region with various test points
circle is "on"
diamond is "in"
plus is "out" | ![>](./figs/RegionOps/testPointInOnOutRegionXY/ParityRegionWithSinglePointInOut.png) | - Unit Test - * source: imodeljs\core\geometry\src\test\topology\RegionOps.test.ts - * test name: "MixedInOut" - * output: imodeljs\core\geometry\src\test\output\RegionOps\MixedInOut.imjs + +- source: imodeljs\core\geometry\src\test\topology\RegionOps.test.ts +- test name: "MixedInOut" +- output: imodeljs\core\geometry\src\test\output\RegionOps\MixedInOut.imjs ## RegionOps.regionBooleanXY @@ -51,16 +50,17 @@ Compute union, intersection, and difference among area regions. The call form is `RegionOps.regionBooleanXY(regionA, regionB, opcode)` where -* Each of regionA and regionB may be - * a single Loop - * a single ParityRegion - * an array of Loop and ParityRegion - * all the loops and parity regions within each array are considered as a union. -* The operation between regionA and regionB is one of - * RegionBinaryOpType.Union - * RegionBinaryOpType.Intersection - * RegionBinaryOpType.AMinusB - * RegionBinaryOpType.BMinusA + +- Each of regionA and regionB may be + - a single Loop + - a single ParityRegion + - an array of Loop and ParityRegion + - all the loops and parity regions within each array are considered as a union. +- The operation between regionA and regionB is one of + - RegionBinaryOpType.Union + - RegionBinaryOpType.Intersection + - RegionBinaryOpType.AMinusB + - RegionBinaryOpType.BMinusA For a first example, each of regionA and regionB is a single Loop: @@ -75,19 +75,23 @@ For a first example, each of regionA and regionB is a single Loop: For a second example, each of regionA and regionB is an array of regions to be treated as a union: -* region A is constructed by -``` - const manyRoundedRectangles = []; +- region A is constructed by + + ```ts + const manyRoundedRectangles = []; for (let a = 0; a < 5; a += 1) { manyRoundedRectangles.push(CurveFactory.createRectangleXY(a, a, a + 4, a + 1.75, 0, 0.5)); } - ``` - and region B by - ``` - const splitterB0 = CurveFactory.createRectangleXY(0.5, 0.4, 6, 2.1, 0, 0); - const splitterB1 = splitterB0.cloneTransformed(Transform.createFixedPointAndMatrix({ x: 1, y: 2, z: 0 }, Matrix3d.createRotationAroundAxisIndex(2, Angle.createDegrees(40)))) as Loop; - const splitterB = [splitterB0, splitterB1]; - ``` + ``` + + and region B by + + ```ts + const splitterB0 = CurveFactory.createRectangleXY(0.5, 0.4, 6, 2.1, 0, 0); + const splitterB1 = splitterB0.cloneTransformed(Transform.createFixedPointAndMatrix({ x: 1, y: 2, z: 0 }, Matrix3d.createRotationAroundAxisIndex(2, Angle.createDegrees(40)))) as Loop; + const splitterB = [splitterB0, splitterB1]; + ``` + | | | |---|---| | region A | ![>](./figs/RegionBooleanXY/Example2/regionArrayA.png) | @@ -97,8 +101,8 @@ For a second example, each of regionA and regionB is an array of regions to be t | intersectionB = RegionOps.regionBooleanXY(manyRoundedRectangles, splitterB, RegionBinaryOpType.Intersection); |![>](./figs/RegionBooleanXY/Example2/intersection.png)| | diffB = RegionOps.regionBooleanXY(manyRoundedRectangles, splitterB, RegionBinaryOpType.AMinusB); |![>](./figs/RegionBooleanXY/Example2/AMinusB.png)| - Unit Test - * source: imodeljs\core\geometry\src\test\topology\RegionBoolean.test.ts - * test name: "DocDemo" - * output: imodeljs\core\geometry\src\test\output\sweepBooleans\DocDemo.imjs + +- source: imodeljs\core\geometry\src\test\topology\RegionBoolean.test.ts +- test name: "DocDemo" +- output: imodeljs\core\geometry\src\test\output\sweepBooleans\DocDemo.imjs diff --git a/docs/learning/geometry/SpiralConstructions.md b/docs/learning/geometry/SpiralConstructions.md index 74880b08d2cb..df5ab70c8b21 100644 --- a/docs/learning/geometry/SpiralConstructions.md +++ b/docs/learning/geometry/SpiralConstructions.md @@ -4,22 +4,14 @@ These methods take three points ABC and construct various combinations of geometry to transition from line AB to line BC. -* Method:(static) CurveFactory.createLineSpiralArcSpiralLine (A,B,C, lengthA, lengthC, radius) +- Method:(static) CurveFactory.createLineSpiralArcSpiralLine (A,B,C, lengthA, lengthC, radius) ![>](./figs/Spiral/createLineSpiralArcSpiralLine.png) -* Method:(static) CurveFactory.createLineSpiralSpiralLine (A,B,C) +- Method:(static) CurveFactory.createLineSpiralSpiralLine (A,B,C) ![>](./figs/Spiral/createLineSpiralSpiralLine.png) -* Method:(static) CurveFactory.createLineSpiralSpiralLineWithSpiralLength (A,B,C, spiralLength) +- Method:(static) CurveFactory.createLineSpiralSpiralLineWithSpiralLength (A,B,C, spiralLength) ![>](./figs/Spiral/createLineSpiralSpiralLineWithSpiralLength.png) - - - - - - - - diff --git a/docs/learning/geometry/SpiralTypes.md b/docs/learning/geometry/SpiralTypes.md index 8e7bd34c9a08..3d22c7657317 100644 --- a/docs/learning/geometry/SpiralTypes.md +++ b/docs/learning/geometry/SpiralTypes.md @@ -1,3 +1,5 @@ +# Spirals + "Spirals" are a class of curve that are used to provide smooth transition from one turning radius to another. | Description | Geometry | @@ -8,7 +10,7 @@ The geometry of a spiral is more difficult than for lines, arcs, and ellipses. There are a menagerie of spiral types with varying smoothness and equational complexity. -# "Integrated" spirals +## "Integrated" spirals The "best" spirals are those that controlled by controlling curvature -- _not xy position_ -- as a function of distance along the transition. Getting from the curvature to position requires integrals. The integrations are highly reliable to nearly full 16-digit machine precision. These spiral types are objects of type `IntegratedSpiral3d`. @@ -18,10 +20,11 @@ Each type of `IntegratedSpiral3d` has a "snap function" (implemented by a `Norma The table below shows curvature transitions and derivatives for the various integrated spiral types. The horizontal axis is "distance along the curve" and the y axis is "curvature". -* In the "curvature" column the incoming blue horizontal is the zero curvature of the incoming line in the two figures above. The outgoing green is the nonzero curvature of the outgoing arc. The red is the spiral transition. We want the thick red curvature value to move smoothly from the lower level to the upper level. -* In the "derivative" column, the incoming and outgoing green lines are both at the _zero_ level. The incoming line obviously has no changes in curvature happening. The outgoing arc has changing _direction_ but is at constant curvature, so its _derivative_ of curvature is back down at the lower level. -* The zoom column shows a closeup of the derivative at the line-to-spiral transition. (The step change clothoid is omitted -- it is clear in the derivative column.) -* The derivative plots reveal subtle differences that are extremely hard to see in the curvature plots themselves. + +- In the "curvature" column the incoming blue horizontal is the zero curvature of the incoming line in the two figures above. The outgoing green is the nonzero curvature of the outgoing arc. The red is the spiral transition. We want the thick red curvature value to move smoothly from the lower level to the upper level. +- In the "derivative" column, the incoming and outgoing green lines are both at the _zero_ level. The incoming line obviously has no changes in curvature happening. The outgoing arc has changing _direction_ but is at constant curvature, so its _derivative_ of curvature is back down at the lower level. +- The zoom column shows a closeup of the derivative at the line-to-spiral transition. (The step change clothoid is omitted -- it is clear in the derivative column.) +- The derivative plots reveal subtle differences that are extremely hard to see in the curvature plots themselves. (Curvature gets a numeric value as 1 divided by the radius of turning. Plotting radius itself is not helpful because it goes to infinity in straight sections.) @@ -47,5 +50,6 @@ Note that in the "zoomed derivative" column, there the biquadratic, bloss, and c | cosine | ![>](./figs/Spiral/cosineK.png) | ![>](./figs/Spiral/cosineKPrime.png) | ![>](./figs/Spiral/cosineKPrimeZoom.png) | | sine | ![>](./figs/Spiral/sineK.png) | ![>](./figs/Spiral/sineKPrime.png) | ![>](./figs/Spiral/sineKPrimeZoom.png) | -# "Direct" Spirals -A "Direct" spiral is one for which xy position can be computed "directly" in some equation, with no recourse to integrals of the snap functions above. The good side of this is that the code complexity to _draw_ the curve is similar to that of that of a bspline curve or elliptic arc. The bad side of this it that they only approximately match entry and exit radius conditions. \ No newline at end of file +## "Direct" Spirals + +A "Direct" spiral is one for which xy position can be computed "directly" in some equation, with no recourse to integrals of the snap functions above. The good side of this is that the code complexity to _draw_ the curve is similar to that of that of a bspline curve or elliptic arc. The bad side of this it that they only approximately match entry and exit radius conditions. diff --git a/docs/learning/geometry/StrokeOptions.md b/docs/learning/geometry/StrokeOptions.md index a2b42ac26f8e..47da479e13b4 100644 --- a/docs/learning/geometry/StrokeOptions.md +++ b/docs/learning/geometry/StrokeOptions.md @@ -1,30 +1,29 @@ # StrokeOptions - ![>](./figs/StrokeOptions/StrokeOptions.png) A StrokeOptions structure carries various tolerances applied during (a) curve stroking and (b) surface faceting. The three tolerances that are of most interest are: -* chordError is an distance measured from a curve or facet to its approximating stroke or facet. -* angle is the angle between two contiguous strokes or across a facet edge. -* maxEdgeLength is the length of a stroke or a edge of a facet. +- chordError is an distance measured from a curve or facet to its approximating stroke or facet. +- angle is the angle between two contiguous strokes or across a facet edge. +- maxEdgeLength is the length of a stroke or a edge of a facet. -It is rare for all three to be active at once. +It is rare for all three to be active at once. Facet tolerances are guidelines, not absolute rules. Facet and stroke code may ignore tolerances in awkward situations. - -* An angle tolerance is nearly always useful to ensure that circular geometry is recognizable. - * For curves, 15 degrees is typical (24 strokes on a full circle) - * For facets, 22.5 degrees is typical (16 facets around a full cylinder) - * Halving the angle tolerance will (roughly) make curves get twice as many strokes, and surfaces get 4 times as many facets. - * Angle tolerance creates predictable - * The angle tolerance has the useful property that its effect is independent of the size of geometry. If data is suddenly scaled into millimeters rather than meters, the stroke or facet counts will remain the same. - * For extremely large radius curves, angle tolerance alone will produce large chord errors. -* A chordError tolerance forces large radius curves to have more strokes, hence look smoother. -* For graphics display, a typical combination is an angle tolerance of around 15 degrees and an chord tolerance which is the size of several pixels. -* Analysis meshes (e.g. Finite Elements) commonly need to apply maxEdgeLength to facets closer to squares and well formed triangles. - * Using maxEdgeLength for graphics probably produces too many facets. For example, it causes long cylinders to get many nearly-square facets instead of the samll number of long quads usually used for graphics. -* If multiple tolerances are in effect, the actual count will usually be based on the one that demands the most strokes or facets, unless it is so high that it violates some upper limit on the number of facets on an arc or a section of a curve. + +- An angle tolerance is nearly always useful to ensure that circular geometry is recognizable. + - For curves, 15 degrees is typical (24 strokes on a full circle) + - For facets, 22.5 degrees is typical (16 facets around a full cylinder) + - Halving the angle tolerance will (roughly) make curves get twice as many strokes, and surfaces get 4 times as many facets. + - Angle tolerance creates predictable + - The angle tolerance has the useful property that its effect is independent of the size of geometry. If data is suddenly scaled into millimeters rather than meters, the stroke or facet counts will remain the same. + - For extremely large radius curves, angle tolerance alone will produce large chord errors. +- A chordError tolerance forces large radius curves to have more strokes, hence look smoother. +- For graphics display, a typical combination is an angle tolerance of around 15 degrees and an chord tolerance which is the size of several pixels. +- Analysis meshes (e.g. Finite Elements) commonly need to apply maxEdgeLength to facets closer to squares and well formed triangles. + - Using maxEdgeLength for graphics probably produces too many facets. For example, it causes long cylinders to get many nearly-square facets instead of the small number of long quads usually used for graphics. +- If multiple tolerances are in effect, the actual count will usually be based on the one that demands the most strokes or facets, unless it is so high that it violates some upper limit on the number of facets on an arc or a section of a curve. diff --git a/docs/learning/geometry/Transform.md b/docs/learning/geometry/Transform.md index 988e4e65e32d..d7e3d9017c6f 100644 --- a/docs/learning/geometry/Transform.md +++ b/docs/learning/geometry/Transform.md @@ -1,11 +1,11 @@ # Transform and Matrix3d operations ## Types -* A `Matrix3d` is a 3x3 matrix. It can be used for 3D rotation and scaling. - * A matrix _alone_ acts on xyz data, but always leaves the origin in place. - * A matrix must be bundled into a transform (which carries an additional origin/translation term) to cause scaling and rotation around a point other than the origin. -* A `Transform` is a 3x3 matrix with an additional point which is variously called "origin" or "translation". +- A `Matrix3d` is a 3x3 matrix. It can be used for 3D rotation and scaling. + - A matrix _alone_ acts on xyz data, but always leaves the origin in place. + - A matrix must be bundled into a transform (which carries an additional origin/translation term) to cause scaling and rotation around a point other than the origin. +- A `Transform` is a 3x3 matrix with an additional point which is variously called "origin" or "translation". ## Notation @@ -19,12 +19,12 @@ ## Remarks on the entries in a Matrix3d -* Some common uses of Matrix3d are for: - * Pure rotation: the matrix "picks something up" and spins it. In the final position, there is not change of distance between any two points marked on the original geometry. - * the relation of the 9 numbers in the matrix with intuitive description of the rotation is tricky. - * You cannot pull just a few numbers from the matrix and directly map them to what rotation happened. - * Uniform scaling: the matrix expands or contracts everything uniformly about the origin. - * This matrix structure is simple: the scale factor appears on the diagonal. +- Some common uses of Matrix3d are for: + - Pure rotation: the matrix "picks something up" and spins it. In the final position, there is not change of distance between any two points marked on the original geometry. + - the relation of the 9 numbers in the matrix with intuitive description of the rotation is tricky. + - You cannot pull just a few numbers from the matrix and directly map them to what rotation happened. + - Uniform scaling: the matrix expands or contracts everything uniformly about the origin. + - This matrix structure is simple: the scale factor appears on the diagonal. ![>](./figs/Equations/DiagonalScale.png) ## Constructor and full update methods @@ -57,7 +57,6 @@ | most direct rotation that moves vectorA to vectorB | newMatrix = Matrix3d.createRotationVectorToVector (vectorA, vectorB) | | | | | rotation that moves vectorA a fraction of the shortest rotation towards vectorB | newMatrix = Matrix3d.createPartialRotationVectorToVector (vectorA, fraction, vectorB) | | | | - # Simple Queries with matrix rows and columns | category | Matrix3d | @@ -91,7 +90,6 @@ | get row or column | vector = matrix.getColumn (columnIndex, result?) | | | vector= matrix.getRow (columnIndex, result) | - # Rigid Matrix constructions These methods return individual vectors with special perpendicular conditions related to the input vector and the global axes. These constructions are central to constructing a rigid axis matrix that has a "heads up" sense. @@ -109,7 +107,6 @@ These methods return individual vectors with special perpendicular conditions re # Multiplying points and vectors - | method | remarks | |---|---| | matrix.mutliplyVector(vector, result)?:Vector3d | diff --git a/docs/learning/geometry/Triangulation.md b/docs/learning/geometry/Triangulation.md index 90a536d9becc..0df6272dbd2a 100644 --- a/docs/learning/geometry/Triangulation.md +++ b/docs/learning/geometry/Triangulation.md @@ -6,32 +6,30 @@ | | | |---|---| | 25 points | ![>](./figs/Triangulation/PointTriangulation/ExampleA25Points.png) | -| compute convex hull of `points: Point3d[]` | ` const hull: Point3d[] = [];`
` const interior: Point3d[] = [];`
` Point3dArray.computeConvexHullXY(points, hull, interior, true);` | +| compute convex hull of `points: Point3d[]` | `const hull: Point3d[] = [];`
`const interior: Point3d[] = [];`
`Point3dArray.computeConvexHullXY(points, hull, interior, true);` | | | ![>](./figs/Triangulation/PointTriangulation/ExampleAConvexHullAndInsidePoints.png) | | One step `points: Point3d[]` to Polyface | `const polyface = PolyfaceBuilder.pointsToTriangulatedPolyface(points);`| | IndexedPolyface with all the points triangulated. | ![>](./figs/Triangulation/PointTriangulation/ExampleATriangulatedMesh.png) | - - - Unit Test - * source: imodeljs\core\geometry\src\test\topology\InsertAndRetriangulateContext.test.ts - * test name: "TriangulateInHull" - * output: imodeljs\core\geometry\src\test\output\InsertAndRetriangulateContext\TriangulateInHull.imjs - ## Triangulate points "between linestrings" +- source: imodeljs\core\geometry\src\test\topology\InsertAndRetriangulateContext.test.ts +- test name: "TriangulateInHull" +- output: imodeljs\core\geometry\src\test\output\InsertAndRetriangulateContext\TriangulateInHull.imjs + +## Triangulate points "between linestrings" | | | |---|---| | 4 and 6 sided polygons | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/QuadAndHex.png) | -| Same polygons displayed with `
`handles to indicate the two linestrings have edge subdivision mismatch `
` in addition to the different cornering angles | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/QuadAndHexWithHandlesA.png) | +| Same polygons displayed with `
`handles to indicate the two linestrings have edge subdivision mismatch `
` in addition to the different cornering angles | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/QuadAndHexWithHandlesA.png) | | triangles constructed "between" the polygons | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/MeshA.png) | | Same polygons, another mix of points along edges | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/QuadAndHexWithHandlesB.png) | | triangles constructed "between" the polygons | ![>](./figs/Triangulation/GreedyTriangulationBetweenLineStrings/MeshB.png) | - Unit Test - * source: imodeljs\core\geometry\src\test\Polyface\GreedyTriangulationBetweenLineStrings.test.ts - * test set: `describe("GreedyTriangulationBetweenLineStrings"` - * test name: `quadStar` - * output: imodeljs\core\geometry\src\test\output\GreedyTriangulationBetweenLineStrings\quadStar.imjs + +- source: imodeljs\core\geometry\src\test\Polyface\GreedyTriangulationBetweenLineStrings.test.ts +- test set: `describe("GreedyTriangulationBetweenLineStrings"` +- test name: `quadStar` +- output: imodeljs\core\geometry\src\test\output\GreedyTriangulationBetweenLineStrings\quadStar.imjs diff --git a/docs/learning/geometry/index.md b/docs/learning/geometry/index.md index b572b6c3be30..30b190e55f7f 100644 --- a/docs/learning/geometry/index.md +++ b/docs/learning/geometry/index.md @@ -2,26 +2,24 @@ Topics: -* [Point Vector methods](./PointVector.md) -* [Curve Primitives](./CurvePrimitive.md) -* [Curve Collections](./CurveCollection.md) -* [Sample create methods and IModelJson form](./IModelJsonGeometrySchema.md) -* [Surface Normals](./FacetNormals.md) -* [Polyface Analytical Data Visualization](./PolyfaceAuxData.md) -* [Polyface Index Pairing](./PolyfaceIndexPairing.md) -* [PolyfaceBuilder](./PolyfaceBuilder.md) -* [StrokeOptions](./StrokeOptions.md) -* [Triangulation](./Triangulation.md) -* [RegionOps class](./RegionOps.md) -* [PolyfaceClip class](./PolyfaceClip.md) - +- [Point Vector methods](./PointVector.md) +- [Curve Primitives](./CurvePrimitive.md) +- [Curve Collections](./CurveCollection.md) +- [Sample create methods and IModelJson form](./IModelJsonGeometrySchema.md) +- [Surface Normals](./FacetNormals.md) +- [Polyface Analytical Data Visualization](./PolyfaceAuxData.md) +- [Polyface Index Pairing](./PolyfaceIndexPairing.md) +- [PolyfaceBuilder](./PolyfaceBuilder.md) +- [StrokeOptions](./StrokeOptions.md) +- [Triangulation](./Triangulation.md) +- [RegionOps class](./RegionOps.md) +- [PolyfaceClip class](./PolyfaceClip.md) Web Links -* Points and Vectors - * [Cross Product of Vectors](https://en.wikipedia.org/wiki/Cross_product) - * [Dot Product of Vectors](https://en.wikipedia.org/wiki/Dot_product) - * [Triple Product of Vectors](https://en.wikipedia.org/wiki/Triple_product) -* Transformations - * [Rotation Matrix](https://en.wikipedia.org/wiki/Rotation_matrix) - +- Points and Vectors + - [Cross Product of Vectors](https://en.wikipedia.org/wiki/Cross_product) + - [Dot Product of Vectors](https://en.wikipedia.org/wiki/Dot_product) + - [Triple Product of Vectors](https://en.wikipedia.org/wiki/Triple_product) +- Transformations + - [Rotation Matrix](https://en.wikipedia.org/wiki/Rotation_matrix) diff --git a/docs/learning/guidelines/documentation-link-syntax.md b/docs/learning/guidelines/documentation-link-syntax.md index 764d31788466..f2d2d37b9615 100644 --- a/docs/learning/guidelines/documentation-link-syntax.md +++ b/docs/learning/guidelines/documentation-link-syntax.md @@ -33,8 +33,8 @@ Standard markdown rules apply: ### Notes on #section -* `#section` is optional if a filename is specified. If not present, the target is the top of the file. -* must be all lowercase. Use ‘-‘ instead of spaces. +- `#section` is optional if a filename is specified. If not present, the target is the top of the file. +- must be all lowercase. Use ‘-‘ instead of spaces. For example, if the target is: @@ -61,7 +61,6 @@ For example: * @see [label]($docs/learning/path/filename.md#section) * @see [label]($docs/learning/path/filename.md#section) */ - ``` ## Linking to external Urls diff --git a/docs/learning/guidelines/index.md b/docs/learning/guidelines/index.md index 738062276188..512d18d897e6 100644 --- a/docs/learning/guidelines/index.md +++ b/docs/learning/guidelines/index.md @@ -1,8 +1,8 @@ # Tips and Guidelines for iModel.js -* [TypeScript Coding Guideline](./typescript-coding-guidelines.md) -* [API Release Tags](./release-tags-guidelines.md) -* [Markdown Introduction](./markdown-intro.md) -* [NPM Scripts](./npm-scripts-guidelines.md) +- [TypeScript Coding Guideline](./typescript-coding-guidelines.md) +- [API Release Tags](./release-tags-guidelines.md) +- [Markdown Introduction](./markdown-intro.md) +- [NPM Scripts](./npm-scripts-guidelines.md) diff --git a/docs/learning/guidelines/markdown-intro.md b/docs/learning/guidelines/markdown-intro.md index 712de296b306..9e3837602e8e 100644 --- a/docs/learning/guidelines/markdown-intro.md +++ b/docs/learning/guidelines/markdown-intro.md @@ -31,59 +31,72 @@ Use 3 hyphens for a horizontal rule: --- -## Bullet list: +## Bullet list ```md -* apples -* oranges -* pears - * subList - * subList +- apples +- oranges +- pears + - subList + - subList ``` -* apples -* oranges -* pears - * subList - * subList + +- apples +- oranges +- pears + - subList + - subList --- -## Numbered list: + +## Numbered list ```md 1. apples - * subList - * subList + - subList + - subList 1. oranges 1. pears ``` + 1. apples - * subList - * subList + - subList + - subList 2. oranges 3. pears --- + ## Notes + ```md > Note: this is an example note. ``` + > Note: this is an example note. --- + ## HTTP Links + ```md A [link](https://en.wikipedia.org/wiki/Markdown) ``` + A [link](https://en.wikipedia.org/wiki/Markdown) --- + ## Images + ```md An image: ![alternate text](logo.png "tooltip text") ``` + An image: ![alternate text](logo.png "tooltip text") --- + ## Source Code Use backticks for inline source code: `public static myPublicStaticMethod(x: number): Promise` @@ -103,6 +116,7 @@ public static myPublicStaticMethod(x: number): Promise { ## Tables Tables are created by adding pipes as dividers between each cell, and by adding a line of dashes (also separated by bars) beneath the header. Note that the pipes do not need to be vertically aligned. + ```md Option|Description ---|--- @@ -110,6 +124,7 @@ data |path to data files that will be passed into templates. engine |engine to be used for processing templates. ext|extension to be used for destination files. ``` + Option|Description ---|--- data |path to data files that will be passed into templates. @@ -132,7 +147,6 @@ ignore: true The markdown will not be processed and will not be present in the final output. - ## LaTex-like syntax We have implemented a math typesetting library with a syntax similar to LaTex, called [KaTex](https://katex.org/). To insert an equation, add a source code snippet with the language `math` or equation. @@ -142,24 +156,31 @@ f(x) = \int_{-\infty}^\infty \hat f(\xi)\,e^{2 \pi i \xi x} \,d\xi ``` + Results in + ```equation f(x) = \int_{-\infty}^\infty \hat f(\xi)\,e^{2 \pi i \xi x} \,d\xi ``` -#### KaTex options +### KaTex options KaTex options can be customized by editing the `katexOptions` entry in docs/config/docSites.json. For example, a KaTex macro can be defined in `macros`: + ```json "\\rowXYZ": "{\\begin{bmatrix} #1 & #2 & #3\\end{bmatrix}}" ``` + Then + ```md \rowXYZ{x}{y}{z} ``` + Results in + ```math \rowXYZ{x}{y}{z} -``` \ No newline at end of file +``` diff --git a/docs/learning/guidelines/npm-scripts-guidelines.md b/docs/learning/guidelines/npm-scripts-guidelines.md index 1bfe0a0d308d..11c47e479c23 100644 --- a/docs/learning/guidelines/npm-scripts-guidelines.md +++ b/docs/learning/guidelines/npm-scripts-guidelines.md @@ -10,7 +10,7 @@ The build-tools package includes a number of preconfigured node.js scripts to ea Suggested Package: -* [TypeScript](https://www.typescriptlang.org/) +- [TypeScript](https://www.typescriptlang.org/) With a properly configured tsconfig.json file, running the TypeScript compiler with `tsc` should be enough for backend libraries and simple backend agents/services. For more information about tsconfig properties, see the [TypeScript website](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). Frontend services or applications may require the use of Webpack or another more involved build solution. @@ -18,7 +18,7 @@ With a properly configured tsconfig.json file, running the TypeScript compiler w Suggested Package: -* [rimraf](/~https://github.com/isaacs/rimraf) +- [rimraf](/~https://github.com/isaacs/rimraf) Use rimraf as a cross-platform way to remove output folders (For example: rimraf ./lib). This package functions in a similar manner to the `rm -rf` command in Unix shells. @@ -26,7 +26,7 @@ Use rimraf as a cross-platform way to remove output folders (For example: rimraf Suggested Package: -* [cpx](https://www.npmjs.com/package/cpx) +- [cpx](https://www.npmjs.com/package/cpx) cpx is a cross-platform copy utility for copying globs of files from a source to a destination directory. Useful for copying around files such as test files or assets. @@ -34,7 +34,7 @@ cpx is a cross-platform copy utility for copying globs of files from a source to Suggested Package: -* [mocha](https://mochajs.org/) +- [mocha](https://mochajs.org/) Mocha is a flexible javascript test runner that can be used to run TypeScript test code in two ways: by either running the compiled JavaScript output of the TypeScript tests, or by running the TypeScript tests/source code directly using the [ts-node](/~https://github.com/TypeStrong/ts-node). Running Mocha with ts-node allows us to generate accurate code coverage numbers for the TypeScript source files. @@ -42,18 +42,10 @@ Mocha is a flexible javascript test runner that can be used to run TypeScript te Suggested Package: -* [nyc](/~https://github.com/istanbuljs/nyc) (this is the command line utility for [Istanbul](https://istanbul.js.org/)) +- [nyc](/~https://github.com/istanbuljs/nyc) (this is the command line utility for [Istanbul](https://istanbul.js.org/)) Istanbul can be [used together with mocha](http://rundef.com/typescript-code-coverage-istanbul-nyc) (in a ts-node configuration) to provide code coverage numbers and reports based on the package's test suite. This can be accomplished by running a ts-node test command directly with nyc (ex: `nyc run npm test:tsnode`). Several types of reports are available, such as a summary of coverage in the console window or an html output that shows specifically which statements have been covered. -## Linting - -Suggested Package: - -* [tslint](https://palantir.github.io/tslint/) - -TSLint can be run separate from VS Code by using the package's CLI. This can be useful for verifying code before committing or for testing linting rules as part of a continuous integration process. - ## Other useful packages [ts-node](/~https://github.com/TypeStrong/ts-node) A typescript execution environment for code. Can be used to run Mocha tests and useful for generating code coverage percentages and reports. diff --git a/docs/learning/guidelines/release-tags-guidelines.md b/docs/learning/guidelines/release-tags-guidelines.md index 3f99f9f99709..c8360823104e 100644 --- a/docs/learning/guidelines/release-tags-guidelines.md +++ b/docs/learning/guidelines/release-tags-guidelines.md @@ -8,11 +8,11 @@ API review files can then be placed under source code control and compared to fu The supported release tags are: -* `@public` -* `@beta` -* `@alpha` -* `@internal` -* `@deprecated` +- `@public` +- `@beta` +- `@alpha` +- `@internal` +- `@deprecated` Details about each tag are below. @@ -73,14 +73,14 @@ Release Tag | Affects Package Semantic Version | Included in Public SDK Document An API Item is an **exported** TypeScript item that includes: -* Classes -* Class Members -* Namespaces -* Namespace Members -* Interfaces -* Types -* Enums -* Enum Members +- Classes +- Class Members +- Namespaces +- Namespace Members +- Interfaces +- Types +- Enums +- Enum Members Here are the guidelines for when a release tag is needed: diff --git a/docs/learning/guidelines/typescript-coding-guidelines.md b/docs/learning/guidelines/typescript-coding-guidelines.md index 0a4428f9f1f5..a2611ca42d26 100644 --- a/docs/learning/guidelines/typescript-coding-guidelines.md +++ b/docs/learning/guidelines/typescript-coding-guidelines.md @@ -27,12 +27,12 @@ Where possible, these guidelines are enforced through our TSLint configuration f ## Do not use `null` -* Use `undefined`. Do not use `null` except where external libraries require it. +- Use `undefined`. Do not use `null` except where external libraries require it. ## `===` and `!==` Operators -* Use `===` and `!==` operators whenever possible. -* The `==` and `!=` operators do type coercion, which is both inefficient and can lead to unexpected behavior. +- Use `===` and `!==` operators whenever possible. +- The `==` and `!=` operators do type coercion, which is both inefficient and can lead to unexpected behavior. ## Strings @@ -57,91 +57,91 @@ On the other hand, vertical whitespace can contribute significantly to code read 5. Don't put each import in an import statement on a separate line. If you use Visual Studio Code as your editor, use the [TypeScript Import Sorter extension](https://marketplace.visualstudio.com/items?itemName=mike-co.import-sorter) with its default settings to automatically format import statements. 6. If a function has only a single statement, it should **not** be on one line. Many debuggers refuse to allow breakpoints to be set on single-line functions. -> Note: This recommendation is now the exact opposite of the previous recommendation. + > Note: This recommendation is now the exact opposite of the previous recommendation. -```ts - // No, cannot set breakpoint !!! - public middle(): number { return this.minimum + ((this.maximum - this.minimum) / 2.0); } -``` + ```ts + // No, cannot set breakpoint !!! + public middle(): number { return this.minimum + ((this.maximum - this.minimum) / 2.0); } + ``` -```ts - // Correct, breakpoint may be set on body of function !!! - public middle(): number { - return this.minimum + ((this.maximum - this.minimum) / 2.0); - } -``` + ```ts + // Correct, breakpoint may be set on body of function !!! + public middle(): number { + return this.minimum + ((this.maximum - this.minimum) / 2.0); + } + ``` 7. The body of an `if` statement or a loop should be on a separate line, even if the body contains only a single line of code. -```ts - // No (body on same line as conditional, cannot set breakpoint) !!! - if (meow) return "cat"; -``` + ```ts + // No (body on same line as conditional, cannot set breakpoint) !!! + if (meow) return "cat"; + ``` -```ts - // Correct (body on separate line from conditional) !!! - if (meow) - return "cat"; -``` + ```ts + // Correct (body on separate line from conditional) !!! + if (meow) + return "cat"; + ``` 8. A closing curly brace should be followed by a blank line. -```ts - // No (missing blank line after closing brace) !!! - if (minimum > maximum) { - const temp = minimum; - minimum = maximum; - maximum = temp; - } - return maximum - minimum; -``` - -```ts - // Correct (blank line after closing brace) !!! - if (minimum > maximum) { - const temp = minimum; - minimum = maximum; - maximum = temp; - } + ```ts + // No (missing blank line after closing brace) !!! + if (minimum > maximum) { + const temp = minimum; + minimum = maximum; + maximum = temp; + } + return maximum - minimum; + ``` + + ```ts + // Correct (blank line after closing brace) !!! + if (minimum > maximum) { + const temp = minimum; + minimum = maximum; + maximum = temp; + } - return maximum - minimum; -``` + return maximum - minimum; + ``` 9. Omit curly braces from single-line code blocks... -```ts - // No (closing brace wastes a line) !!! - if (meow) { - return "cat"; - } -``` + ```ts + // No (closing brace wastes a line) !!! + if (meow) { + return "cat"; + } + ``` -```ts - // Correct (no braces) !!! - if (meow) - return "cat"; -``` + ```ts + // Correct (no braces) !!! + if (meow) + return "cat"; + ``` 10. ...unless related blocks require braces -```ts - // No (unbalanced braces) !!! - if (woof) { - rollover(); - animal = "dog"; - } else if (meow) - animal = "cat"; -``` - -```ts - // Correct (balanced braces) !!! - if (woof) { - rollover(); - animal = "dog"; - } else if (meow) { - animal = "cat"; - } -``` + ```ts + // No (unbalanced braces) !!! + if (woof) { + rollover(); + animal = "dog"; + } else if (meow) + animal = "cat"; + ``` + + ```ts + // Correct (balanced braces) !!! + if (woof) { + rollover(); + animal = "dog"; + } else if (meow) { + animal = "cat"; + } + ``` ## Style @@ -358,28 +358,29 @@ All comments are parsed as markdown. Additionally, you can link to other classes The following JavaDoc tags are supported by TypeDoc: -* `@param` - * The parameter name and type are automatically propagated into the generated documentation, so `@param` should only be included when more of a description is necessary. - * Use plain `@param`. Do not use `@param[in]` or `@param[out]` as this confuses TypeDoc. - * The parameter description should start with a capital letter. -* `@returns` - * The return type is automatically propagated into the generated documentation, so `@returns` should only be included when more of a description is necessary. - * The `@returns` description (when provided) should start with *Returns* for readability within the generated documentation. - * The `@return` JavaDoc tag is also supported, but `@returns` is preferred for readability and consistency with `@throws`. +- `@param` + - The parameter name and type are automatically propagated into the generated documentation, so `@param` should only be included when more of a description is necessary. + - Use plain `@param`. Do not use `@param[in]` or `@param[out]` as this confuses TypeDoc. + - The parameter description should start with a capital letter. +- `@returns` + - The return type is automatically propagated into the generated documentation, so `@returns` should only be included when more of a description is necessary. + - The `@returns` description (when provided) should start with *Returns* for readability within the generated documentation. + - The `@return` JavaDoc tag is also supported, but `@returns` is preferred for readability and consistency with `@throws`. -* `@throws` - * If a method can potentially throw an `Error`, it should be documented with `@throws` as there is no automated way that thrown errors make it into the generated documentation. - * There can be multiple `@throws` lines (one for each different `Error` class) in a method comment. - * A link to the `Error` class should be incorporated into the description. -* `@internal` - * TypeDoc will not document the class, method, or member. This is useful for internal-only utility methods that must be public, but should not be called directly by outside API users. + +- `@throws` + - If a method can potentially throw an `Error`, it should be documented with `@throws` as there is no automated way that thrown errors make it into the generated documentation. + - There can be multiple `@throws` lines (one for each different `Error` class) in a method comment. + - A link to the `Error` class should be incorporated into the description. +- `@internal` + - TypeDoc will not document the class, method, or member. This is useful for internal-only utility methods that must be public, but should not be called directly by outside API users. See below for the recommended format of documentation comments: -``` ts +```ts /** This is a valid single-line comment. */ public myMethod1(): void { } @@ -394,7 +395,6 @@ public myMethod1(): void { } public myMethod2(param1: string): number { /* ... */ } - ``` ## Defining JSON 'Wire Formats' @@ -403,9 +403,9 @@ A common pattern in JavaScript is to transfer information from one context to an For example: -* from a *backend* program to a *frontend* program, or vice-versa -* from C++ to JavaScript, or vice-versa -* saving object state to/from a persistent store, such as a database +- from a *backend* program to a *frontend* program, or vice-versa +- from C++ to JavaScript, or vice-versa +- saving object state to/from a persistent store, such as a database Since JSON strings are often sent over an internet connection, these strings are commonly referred to as "wire formats". @@ -432,8 +432,9 @@ From this we can tell that an Angle may be serialized to/from JSON as either: 1. a `number`, in which case it will be a value in degrees 2. an object that: -* has a member named `degrees` of type `number`, or -* has a member named `radians` of type `number`. + +- has a member named `degrees` of type `number`, or +- has a member named `radians` of type `number`. Likewise, in `@bentley/geometry-core`, we have a class called XYZ. This is a base class for 3d points and vectors. We define the following type: @@ -462,12 +463,11 @@ Every .ts file should have this notice as its **first lines**: * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ - ``` ## Source Code Editor -While not an absolute requirement, we recommend and optimize for [Visual Studio Code](https://code.visualstudio.com/). You will be likely be less productive if you attempt to use anything else. We recommend configuring the **TSLint** extension for Visual Studio Code and using our **tslint.json** to get real-time feedback. +While not an absolute requirement, we recommend and optimize for [Visual Studio Code](https://code.visualstudio.com/). You will be likely be less productive if you attempt to use anything else. We recommend configuring the **ESLint** extension for Visual Studio Code and using our [@bentley/eslint-plugin](https://www.npmjs.com/package/@bentley/eslint-plugin) to get real-time feedback. ## React Function Components diff --git a/docs/learning/iModelHub/Briefcases.md b/docs/learning/iModelHub/Briefcases.md index 0529f2e8771d..6d66afe71a48 100644 --- a/docs/learning/iModelHub/Briefcases.md +++ b/docs/learning/iModelHub/Briefcases.md @@ -16,9 +16,9 @@ ChangeSet id is a 40 characters SHA1 hash that is used to validate ChangeSet. Th Each Briefcase has a unique 24bit integer id. Briefcase id is written into the iModel file after download and is used to identify where changes have occurred. -* Every Element id contains the id Briefcase where it was created. -* Every ChangeSet has an id of the Briefcase that pushed it. -* [Locks and Codes](../backend/ConcurrencyControl.md) contain an id of the Briefcase that they belong to. +- Every Element id contains the id Briefcase where it was created. +- Every ChangeSet has an id of the Briefcase that pushed it. +- [Locks and Codes](../backend/ConcurrencyControl.md) contain an id of the Briefcase that they belong to. > Since Briefcase ids are limited, it is recommended to reuse briefcases instead of acquiring new ones. There are limits how many Briefcases a single user can acquire per minute/total to prevent users accidentally acquiring too many Briefcases. @@ -26,6 +26,6 @@ Each Briefcase has a unique 24bit integer id. Briefcase id is written into the i To work with Briefcases, [BriefcaseDb]($backend) methods should be used instead of calling iModelHub API directly: -* [Acquiring and opening a briefcase](../backend/IModelDb.md) -* [Pulling changes](../backend/IModelDbSync.md) -* [Creating and pushing changes](../backend/IModelDbReadwrite.md) +- [Acquiring and opening a briefcase](../backend/IModelDb.md) +- [Pulling changes](../backend/IModelDbSync.md) +- [Creating and pushing changes](../backend/IModelDbReadwrite.md) diff --git a/docs/learning/iModelHub/Client.md b/docs/learning/iModelHub/Client.md index 210f2c473d91..d16d8fcf12eb 100644 --- a/docs/learning/iModelHub/Client.md +++ b/docs/learning/iModelHub/Client.md @@ -1,12 +1,15 @@ # iModelHub Client + To work with iModelHub API directly, you have to create an instance of [IModelHubClient]($imodelhub-client). Once you have instance of the client, you can access various iModelHub class handlers through it. [IModelDb]($backend) covers most of the common functionality of iModelHub and it should be used instead of IModelHubClient when possible. > You should try to reuse [IModelHubClient]($imodelhub-client) instances, as performance sending multiple requests to iModelHub will be better on the same client instance. It's not necessary to reuse handler instances. ## iModelHub Client on backend + If you're working on a backend and require downloading and uploading files, you have to specify an implementation of [FileHandler]($itwin-client). For iModelHub that should be [AzureFileHandler]($backend-itwin-client) Example: + ```ts [[include:IModelHubClient.example-code]] ``` diff --git a/docs/learning/iModelHub/WorkingWith.md b/docs/learning/iModelHub/WorkingWith.md index 16a29ae88c20..6a8fad4c2f44 100644 --- a/docs/learning/iModelHub/WorkingWith.md +++ b/docs/learning/iModelHub/WorkingWith.md @@ -12,17 +12,17 @@ iModelHub API covers basic calls to iModelHub that are part of larger workflows. ## Before you start -* [Obtaining an AccessToken]($docs/learning/common/AccessToken.md) -* [Creating iModelHub client](./Client) -* [Permissions](./Permissions) +- [Obtaining an AccessToken]($docs/learning/common/AccessToken.md) +- [Creating iModelHub client](./Client) +- [Permissions](./Permissions) ## Working through backend classes -* [iModels](./iModels/index) -* [Briefcases](./Briefcases) -* [Codes and Locks]($docs/learning/backend/ConcurrencyControl.md) +- [iModels](./iModels/index) +- [Briefcases](./Briefcases) +- [Codes and Locks]($docs/learning/backend/ConcurrencyControl.md) ## Working through clients package -* [Named Versions](./Versions) -* [Events](./Events) +- [Named Versions](./Versions) +- [Events](./Events) diff --git a/docs/learning/iModelHub/iModels/index.md b/docs/learning/iModelHub/iModels/index.md index 534b05a3a3ca..1a594c7e7765 100644 --- a/docs/learning/iModelHub/iModels/index.md +++ b/docs/learning/iModelHub/iModels/index.md @@ -4,5 +4,5 @@ To work with iModelHub, an [iModel](../../Glossary.md#iModel) has to be created ## Working with iModels -* [Creating an iModel](./CreateiModel.md) -* [Getting an existing iModel](./GetiModel.md) +- [Creating an iModel](./CreateiModel.md) +- [Getting an existing iModel](./GetiModel.md) diff --git a/docs/learning/presentation/Content/RelatedPropertiesSpecification.md b/docs/learning/presentation/Content/RelatedPropertiesSpecification.md index 1006a250a154..9791771f5e72 100644 --- a/docs/learning/presentation/Content/RelatedPropertiesSpecification.md +++ b/docs/learning/presentation/Content/RelatedPropertiesSpecification.md @@ -27,6 +27,7 @@ In general, when properties are displayed in a property grid, this attribute pro ## Examples Pick "MyProperty1" and "MyProperty2" properties from all related aspects that have them: + ```JSON { "propertiesSource": { @@ -41,6 +42,7 @@ Pick "MyProperty1" and "MyProperty2" properties from all related aspects that ha ``` Pick all properties from related model and override label of "UserLabel" property: + ```JSON { "propertiesSource": { diff --git a/docs/learning/presentation/Customization/StyleOverride.md b/docs/learning/presentation/Customization/StyleOverride.md index dda777ed5c71..3ebbd34e169b 100644 --- a/docs/learning/presentation/Customization/StyleOverride.md +++ b/docs/learning/presentation/Customization/StyleOverride.md @@ -20,6 +20,7 @@ Name | Required? | Type | Default | Meaning ### Color Value Formats Colors in `foreColor` and `backColor` attributes may be evaluated to one of the following formats: + - color name: `Red`, `Blue`, etc. - RGB: `rgb(100, 200, 255)` - HEX: `#0f0f0f` @@ -27,6 +28,7 @@ Colors in `foreColor` and `backColor` attributes may be evaluated to one of the ### Font Styles Font style in `fontStyle` attribute may be evaluated to one of the following values: + - `Bold` - `Italic` - `Italic,Bold` diff --git a/docs/learning/presentation/ECExpressions.md b/docs/learning/presentation/ECExpressions.md index 08b21de95838..bcf2fc328e29 100644 --- a/docs/learning/presentation/ECExpressions.md +++ b/docs/learning/presentation/ECExpressions.md @@ -4,9 +4,11 @@ ECExpressions is a very basic language that allows customizing presentation rules' behavior. Symbols that can be used depend on current context. Example: + ``` this.GetContextB().ContextC.DoSomething() ``` + Here, symbol `this` returns a context which has a function symbol `GetContextB()`. This function returns a context which has a property symbol `ContextC`. And the property value is a context that contains a @@ -247,6 +249,7 @@ Symbol | Type | Value ECInstance expression context provides access to ECInstance property values. Example: + ``` this.PropertyName this.StructPropertyName.PropertyName @@ -291,9 +294,11 @@ Symbol | Type | Value Value lists in ECExpressions can be handled with lambdas. Currently the presentation rules engine supports only a single simple lambda for value lists: + ``` value_list.AnyMatch(x => x = this.PropertyValue) ``` + The above expression returns `true` if `value_list` contains the value of `this.PropertyValue`. @@ -302,6 +307,7 @@ of `this.PropertyValue`. Comparison of formatted property values in ECExpressions can be done using `GetFormattedValue` function. Specific unit system can be passed as second argument to function or omitted to use default presentation format: + ``` GetFormattedValue(this.Length, "Metric") = "10.0 m" GetFormattedValue(this.Length) = "10.0 m" diff --git a/docs/learning/presentation/Hierarchies/CustomQueryInstanceNodes.md b/docs/learning/presentation/Hierarchies/CustomQueryInstanceNodes.md index 06517f8f77cf..cf23875c39b2 100644 --- a/docs/learning/presentation/Hierarchies/CustomQueryInstanceNodes.md +++ b/docs/learning/presentation/Hierarchies/CustomQueryInstanceNodes.md @@ -31,6 +31,7 @@ Query specifications define the actual results of the `CustomQueryInstanceNodes` and [ECProperty value](#ecpropertyvalue). The queries used in the specifications **must** return `ECClassId` and `ECInstanceId` columns, e.g.: + ```SQL SELECT ECClassId, ECInstanceId FROM [bis].[Element] e diff --git a/docs/learning/presentation/Hierarchies/GroupingRule.md b/docs/learning/presentation/Hierarchies/GroupingRule.md index 51777d2340b5..5d095a665547 100644 --- a/docs/learning/presentation/Hierarchies/GroupingRule.md +++ b/docs/learning/presentation/Hierarchies/GroupingRule.md @@ -5,11 +5,13 @@ Grouping rules provide advanced ways to group instances when creating hierarchies. It allows to define these types of groupings: + - Group by base class. - Group by any property of the instance by a common value or a range of values. - Group multiple instances with the same label in to one ECInstance node. This can be used in cases when these instances represent the same object for the user. The rule works in conjunction with other grouping options available in [navigation specifications](./index.md#specifications): `groupByClass` and `groupByLabel`. The grouping hierarchy looks like this: + - Base ECClass grouping node (specified by [base class grouping specification](#base-class-grouping)) - ECClass grouping node (specified by `groupByClass` property) - ECProperty grouping node 1 (specified by 1st [property grouping specification](#property-grouping)) diff --git a/docs/learning/presentation/Hierarchies/InfiniteHierarchiesPrevention.md b/docs/learning/presentation/Hierarchies/InfiniteHierarchiesPrevention.md index 0687ec32b4a5..b2139b76c846 100644 --- a/docs/learning/presentation/Hierarchies/InfiniteHierarchiesPrevention.md +++ b/docs/learning/presentation/Hierarchies/InfiniteHierarchiesPrevention.md @@ -3,6 +3,7 @@ When creating hierarchies the presentation rules engine avoids getting into infinite loops by checking if the created node already has a similar ancestor node. If it does, the node is marked as hidden and creating the hierarchy further is stopped at that point. For the above checks, two nodes are considered similar if: + - they're both based on the same specification - they both have same type (ECInstance, ECClass Grouping, ECProperty Grouping, Label Grouping, Custom) - based on node type, they represent the same thing (same ECInstance, same ECClass, etc.) diff --git a/docs/learning/presentation/Hierarchies/Terminology.md b/docs/learning/presentation/Hierarchies/Terminology.md index e2398afbe661..d9844cc4c455 100644 --- a/docs/learning/presentation/Hierarchies/Terminology.md +++ b/docs/learning/presentation/Hierarchies/Terminology.md @@ -6,4 +6,4 @@ Nested rules are defined as child elements of rule specification(s). They are evaluated and executed only when user expands nodes provided by parent specification. This allows to have isolated/non-global rules at specific level -of the hierarchy. \ No newline at end of file +of the hierarchy. diff --git a/docs/learning/presentation/Hierarchies/index.md b/docs/learning/presentation/Hierarchies/index.md index c523b51ede60..dbba3b00fb36 100644 --- a/docs/learning/presentation/Hierarchies/index.md +++ b/docs/learning/presentation/Hierarchies/index.md @@ -5,12 +5,14 @@ There are 2 primary concepts for creating hierarchies: rules and specifications. ## Rules Define *where* and *if* specific branch should be created in the hierarchy. There are 2 types of rules: + - [RootNodeRule](./RootNodeRule.md) - [ChildNodeRule](./ChildNodeRule.md) ## Specifications Define *contents* for each branch. There are 6 types of specifications: + - [RelatedInstanceNodes](./RelatedInstanceNodes.md) - [InstanceNodesOfSpecificClasses](./InstanceNodesOfSpecificClasses.md) - [CustomQueryInstanceNodes](./CustomQueryInstanceNodes.md) @@ -27,10 +29,12 @@ means nodes generated from different specifications do not get grouped and sorte All [general use customization rules](../Customization/index.md#rules) can be applied to hierarchies. In addition, there are some hierarchy-specific customization rules: + - [GroupingRule](./GroupingRule.md) for advanced grouping - [NodeArtifactsRule](./NodeArtifactsRule.md) to help create hierarchies for specific cases ## Related Topics + - [Infinite hierarchies prevention](./InfiniteHierarchiesPrevention.md) - [ECExpressions](./ECExpressions.md) - [Terminology](./Terminology.md) diff --git a/docs/learning/presentation/RelatedInstanceSpecification.md b/docs/learning/presentation/RelatedInstanceSpecification.md index 25f7f4d53e09..482da5c98597 100644 --- a/docs/learning/presentation/RelatedInstanceSpecification.md +++ b/docs/learning/presentation/RelatedInstanceSpecification.md @@ -5,6 +5,7 @@ Related instance specification can be used in conjunction with both content and hierarchy related rules. It's primary purpose is to *join* primary instance with some related instance and allow using them both for: + - filtering - labeling - grouping diff --git a/docs/learning/presentation/RelationshipPathSpecification.md b/docs/learning/presentation/RelationshipPathSpecification.md index 873d02c36fa2..014ac9a49981 100644 --- a/docs/learning/presentation/RelationshipPathSpecification.md +++ b/docs/learning/presentation/RelationshipPathSpecification.md @@ -13,7 +13,6 @@ Name | Required? | Type | Default | Meaning `targetClass` | No | `SingleSchemaClassSpecification` | Other end of relationship | Specification of the related class. `count` | No | `number \| "*"` | 1 | Number of times the relationship should be traversed. `"*"` makes the step optional, so results of previous step are also included in results of this step, no matter if this step has any output of its own or not. - ## Example A single-step relationship path which simply jumps from *current* ECClass to *BisCore.PhysicalElement* through *BisCore.ModelModelsElement* relationship: diff --git a/docs/learning/presentation/Testing.md b/docs/learning/presentation/Testing.md index 0b754f17e942..b36c3c49f481 100644 --- a/docs/learning/presentation/Testing.md +++ b/docs/learning/presentation/Testing.md @@ -8,6 +8,7 @@ purely for that reason. The package delivers an API that allows creating hierarchies for supplied iModels and rulesets. Consumers can then verify the result using tools of their liking. Our recommendation is to use snapshot testing for 2 reasons: + 1. resulting hierarchies get rather large - testing the them in code might be difficult 2. snapshots protect against regressions @@ -15,6 +16,7 @@ code might be difficult ## Example An example of setting up snapshot tests with the **@bentley/presentation-testing** package: + ``` ts [[include:Presentation.Testing.Rulesets]] ``` @@ -25,6 +27,7 @@ An example of setting up snapshot tests with the **@bentley/presentation-testing - Don't forget to close the iModel connection - Ruleset can be provided either as an ID of already registered ruleset or as a `Ruleset` object. The object can even be imported from a JSON file: + ```ts await builder.createHierarchy(require("rulesets/YourRuleset")) ``` diff --git a/docs/learning/presentation/Unified-Selection/ContentComponents.md b/docs/learning/presentation/Unified-Selection/ContentComponents.md index c1ee20721ef2..f14192bde4ec 100644 --- a/docs/learning/presentation/Unified-Selection/ContentComponents.md +++ b/docs/learning/presentation/Unified-Selection/ContentComponents.md @@ -1,6 +1,7 @@ # Unified Selection: Content Components Content components may react to selection changes in two ways: + - Request and display content for current selection - Highlight / distinguish current selection in currently displayed content diff --git a/docs/learning/presentation/Unified-Selection/index.md b/docs/learning/presentation/Unified-Selection/index.md index 2f819bc89b2f..4f53a0463ee9 100644 --- a/docs/learning/presentation/Unified-Selection/index.md +++ b/docs/learning/presentation/Unified-Selection/index.md @@ -5,6 +5,7 @@ The purpose of unified selection is to act as a single source of truth of what i ![selection storage](./selection-storage.png "Selection storage") The storage may contain: + - ECInstance keys which represent elements and models - Node keys which represent tree nodes @@ -14,5 +15,6 @@ differently - some may only want to show content for current selection while oth last selection change event. See also: + - [Content Components](./ContentComponents.md) - [Terminology](./Terminology.md) diff --git a/docs/learning/tutorials/create-test-imodel-itwin-sync.md b/docs/learning/tutorials/create-test-imodel-itwin-sync.md index 8a52a1955bd2..78fc284293d7 100644 --- a/docs/learning/tutorials/create-test-imodel-itwin-sync.md +++ b/docs/learning/tutorials/create-test-imodel-itwin-sync.md @@ -1,4 +1,5 @@ # Getting started with iModel.js using your own data via the Free Trial service + This tutorial will describe steps to get started with iModel.js, using the free trial test environment. We will outline creating a Bentley user account, creating a starter iModel, then loading the starter iModel with data from source files on your desktop. At the end of the tutorial, you should have an iModel containing your own data that you will be able to view either on the web, with in a localhost web application, or with a local Electron app. You should have a basic understanding of [iModels]($docs/learning/imodels.md), [iModelHub]($docs/learning/imodelhub/index.md), [iModel Bridges]($docs/learning/imodel-bridges.md), but don't worry if any of those concepts aren't entirely clear. @@ -45,7 +46,6 @@ Build and run the [query-agent](/~https://github.com/imodeljs/imodeljs-samples/tre > _Note: Test iModels should not be used to host sensitive data. The uploaded data is administered by Bentley and should only be used for the purpose of testing. It is not subject to the same data privacy, security policies, and access controls that apply to Bentley’s iTwin offerings. It is subject to data size and other usage limitations, and will be purged after 90 days, if not renewed._ _If you need help or have questions, please contact us on [Github](/~https://github.com/imodeljs/imodeljs/issues)._ - \ No newline at end of file + diff --git a/docs/learning/tutorials/explore-schema-browser.md b/docs/learning/tutorials/explore-schema-browser.md index ddcb68c33238..652ddc5faf2f 100644 --- a/docs/learning/tutorials/explore-schema-browser.md +++ b/docs/learning/tutorials/explore-schema-browser.md @@ -1,5 +1,6 @@ # Using iModel schema browser -- Navigate to https://imodelconsole.bentley.com/ + +- Navigate to - Select your Project - Select your iModel - Choose most recent changeset @@ -11,6 +12,7 @@ - Explore schemas in iModel ## Learn More + [Learn more about Base Infrastructure Schemas (BIS)]($docs/bis)
@@ -22,4 +24,4 @@ a#explore-imodel---build-application { display: none; } - \ No newline at end of file + diff --git a/docs/learning/tutorials/index.md b/docs/learning/tutorials/index.md index bdd4fb16ec7f..44efaf0bec89 100644 --- a/docs/learning/tutorials/index.md +++ b/docs/learning/tutorials/index.md @@ -13,18 +13,21 @@ Test iModels can be used for local development. There are a few different ways t [!bwc tile heading="Offline snapshot from local files" linkTo="create-test-imodel-offline" contents="Create a local snapshot file from files on your local computer" icon="document.svg" step="13" width="28%"] ### Exploring iModels + [!bwc tile heading="ECSQL tutorial" linkTo="index path=learning/ecsqltutorial/index subPath=/ecsqltutorial" contents="Familiarize yourself with the basics of ECSQL" icon="database.svg" step="13" width="28%"] [!bwc tile heading="View in iModelHub" linkTo="use-existing-imodel" contents="How to view your iModel in iModelHub" icon="visibility.svg" step="13" width="28%"] [!bwc tile heading="Explore iModel content" linkTo="explore-imodel-console" contents="How to query the data in your iModel" icon="developer.svg" step="13" width="28%"] [!bwc tile heading="Explore schemas in the iModel" linkTo="explore-schema-browser" contents="How to browse the schemas in your iModel" icon="ec-schema.svg" step="13" width="28%"] ### Building Applications + [!bwc tile heading="Web viewer" linkTo="develop-web-viewer" contents="Create a web based viewer" icon="network.svg" step="13" width="28%" ] [!bwc tile heading="Desktop viewer" linkTo="develop-desktop-viewer" contents="Create a desktop viewer" icon="computer.svg" step="13" width="28%"] [!bwc tile heading="Agent application" linkTo="develop-agent" contents="Create an agent application" icon="notification.svg" step="13" width="28%"] [!bwc tile heading="Extension" linkTo="gettingstarted subPath=/frontend/extensions" contents="Create an iModel.js Extension" icon="puzzle.svg" step="13" width="28%"] ### Registering Applications + [!bwc tile heading="Register application" linkTo="registering-applications" contents="Register an application for deployment" icon="applications.svg" step="13" width="28%"] ### Support diff --git a/docs/learning/tutorials/itwin-snapshot-app.md b/docs/learning/tutorials/itwin-snapshot-app.md index 8ef21142446a..3bcbb0cbefda 100644 --- a/docs/learning/tutorials/itwin-snapshot-app.md +++ b/docs/learning/tutorials/itwin-snapshot-app.md @@ -2,13 +2,12 @@ [Snapshot iModels]($docs/learning/backend/accessingimodels.md/#snapshot-imodels) are a static format representing the state of an iModel at a point in time. Once created, they can not be modified. And do not have a connection with iModelHub. Developers writing iModel.js applications should enjoy several features of Snapshot iModels: - - No connection to iModelHub removes authentication and authorization obstacles - - Their offline nature allows all development to be done locally, with no network latency - - It is not required to have an iTwin Subscription to develop using them +- No connection to iModelHub removes authentication and authorization obstacles +- Their offline nature allows all development to be done locally, with no network latency +- It is not required to have an iTwin Subscription to develop using them Snapshot iModels should not be used in any production workflows as they do not provide security, change history, and other benefits of an iTwin Subscription. The iTwin Snapshot app was designed with developers in mind. The free tool allows developers to create snapshots and after the snapshot has been created, it guides you to a viewer to visualize the snapshot. It also contains links to iModel.js documentation and blogs. [!bwc tile heading="Download iTwin Snapshot" link="https://autoupdatecdn.bentley.com/itsnp/client/iTwinSnapshot.exe" contents=" " icon="download.svg" step="13" width="20%"] - diff --git a/docs/learning/tutorials/registering-applications.md b/docs/learning/tutorials/registering-applications.md index db73862ee3ab..4823b64b15ab 100644 --- a/docs/learning/tutorials/registering-applications.md +++ b/docs/learning/tutorials/registering-applications.md @@ -5,22 +5,25 @@ Your application must be registered with Bentley’s OpenId provider in order to There are three types: ##### [Web Application]($docs/learning/app.md/#interactive-apps) + An interactive application obtains information from an iModel and presents that information in a user interface. ##### [Agent Application]($docs/learning/app.md/#agents-and-services) + iModel agents and services are apps that have no interactive user interface. ##### [Desktop Application]($docs/learning/app.md/#desktop-apps) + An interactive application obtains information from an iModel and presents that information in a user interface. The app runs in Electron on the user's desktop. **[Register apps here]($docs/registration-dashboard.md)** - 1. Go to the [registration dashboard]($docs/getting-started/registration-dashboard/) - 1. Click the "+ New App" button - 1. Select the type of app you would like to register - 1. Give your app a human readable name - 1. Select the scopes your app will need - 1. Specify the different redirect URIs for sign in and sign out - 1. Click finish registration - - If Agent application, the client's secret will be displayed one time only, save this secret in a secure location - 1. The app's Client ID will appear in the Registered Apps grid \ No newline at end of file +1. Go to the [registration dashboard]($docs/getting-started/registration-dashboard/) +1. Click the "+ New App" button +1. Select the type of app you would like to register +1. Give your app a human readable name +1. Select the scopes your app will need +1. Specify the different redirect URIs for sign in and sign out +1. Click finish registration + - If Agent application, the client's secret will be displayed one time only, save this secret in a secure location +1. The app's Client ID will appear in the Registered Apps grid diff --git a/docs/learning/tutorials/use-existing-imodel.md b/docs/learning/tutorials/use-existing-imodel.md index fd8e7c339a7c..0e686f326522 100644 --- a/docs/learning/tutorials/use-existing-imodel.md +++ b/docs/learning/tutorials/use-existing-imodel.md @@ -8,6 +8,6 @@ If you already have access to an iModel this will guide you through locating the - Locate your iModel in the grid - Click on the card to launch [Design Review](https://www.bentley.com/en/products/product-line/digital-twins/itwin-design-review/project-coordination) +## iTwin Hub screenshot -### iTwin Hub screenshot ![itwin hub overview]($docs/learning/tutorials/images/itwin-hub.png) diff --git a/docs/learning/ui/React.md b/docs/learning/ui/React.md index 76d8e206c81a..2531892776fa 100644 --- a/docs/learning/ui/React.md +++ b/docs/learning/ui/React.md @@ -10,6 +10,6 @@ React is a fast and lightweight library for user interface development. The fact **Tooling** - React and Redux are supported by widely-available tools, including: -* VS Code – Visual Studio Code provides great support for TypeScript, React components and TSX/JSX. -* React Developer Tools for Chrome – these provide terrific support for the virtual DOM, showing component Props, allows dynamic changing of Props, etc. -* Redux DevTools for Chrome – Redux time travel support; you can completely control the currently running application’s actions/state \ No newline at end of file +- VS Code – Visual Studio Code provides great support for TypeScript, React components and TSX/JSX. +- React Developer Tools for Chrome – these provide terrific support for the virtual DOM, showing component Props, allows dynamic changing of Props, etc. +- Redux DevTools for Chrome – Redux time travel support; you can completely control the currently running application’s actions/state diff --git a/docs/learning/ui/abstract/Backstage.md b/docs/learning/ui/abstract/Backstage.md index 99a342b4ec39..22f42f35e531 100644 --- a/docs/learning/ui/abstract/Backstage.md +++ b/docs/learning/ui/abstract/Backstage.md @@ -25,4 +25,4 @@ See additional example in [Backstage](../../../learning/ui/framework/Backstage.m ## API Reference -* [Backstage]($ui-abstract:Backstage) +- [Backstage]($ui-abstract:Backstage) diff --git a/docs/learning/ui/abstract/DialogItem.md b/docs/learning/ui/abstract/DialogItem.md index b83113a42042..083eccfa0fb6 100644 --- a/docs/learning/ui/abstract/DialogItem.md +++ b/docs/learning/ui/abstract/DialogItem.md @@ -5,26 +5,26 @@ The [DialogItem]($ui-abstract:Dialog) interface is used to specify user interfac For example, this code: ```ts - // ------------- boolean based toggle button --------------- - private static _lockToggleName = "lockToggle"; - private static _getLockToggleDescription = (): PropertyDescription => { - return { - name: SampleTool._lockToggleName, - displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Lock"), - typename: "boolean", - editor: { name: "toggle" }, - }; - } - - private _lockValue: DialogItemValue = { value: true }; - - public get lock(): boolean { - return this._lockValue.value as boolean; - } - - public set lock(option: boolean) { - this._lockValue.value = option; - } +// ------------- boolean based toggle button --------------- +private static _lockToggleName = "lockToggle"; +private static _getLockToggleDescription = (): PropertyDescription => { + return { + name: SampleTool._lockToggleName, + displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Lock"), + typename: "boolean", + editor: { name: "toggle" }, + }; +} + +private _lockValue: DialogItemValue = { value: true }; + +public get lock(): boolean { + return this._lockValue.value as boolean; +} + +public set lock(option: boolean) { + this._lockValue.value = option; +} { value: this._lockValue, property: SampleTool._getLockToggleDescription(), editorPosition: { rowPriority: 5, columnIndex: 2 } } ``` @@ -49,4 +49,4 @@ Will result in this group of React components: ## API Reference -* [DialogItem]($ui-abstract:Dialog) +- [DialogItem]($ui-abstract:Dialog) diff --git a/docs/learning/ui/abstract/Item.md b/docs/learning/ui/abstract/Item.md index e5a23e876c11..aaafbcfbbb2d 100644 --- a/docs/learning/ui/abstract/Item.md +++ b/docs/learning/ui/abstract/Item.md @@ -7,10 +7,10 @@ The [Item]($ui-abstract:Item) classes and interfaces are used when working with The [ConditionalBooleanValue]($ui-abstract) class is used to specify a boolean value that can change value during the session. When a class instance is constructed, a test function is provided and is used to update the internal boolean value. The function is run to get its initial value if the value is not explicitly set when it is constructed. The syncEventIds are used to allow the user to monitor the application for specific events which would trigger the test function to be rerun. Typically the UI container that holds the item that uses a conditional value will register to listen for the specified event Ids and call the refresh method to update its internal value. These types of values are often used to set the items isHidden property value, as shown below. ```ts - const isHidden = new ConditionalBooleanValue(() => { - const activeContentControl = ContentViewManager.getActiveContentControl(); - return !!activeContentControl?.viewport?.view.is2d(); - }, [SyncUiEventId.ActiveContentChanged, SyncUiEventId.ActiveViewportChanged, SyncUiEventId.ViewStateChanged]); +const isHidden = new ConditionalBooleanValue(() => { + const activeContentControl = ContentViewManager.getActiveContentControl(); + return !!activeContentControl?.viewport?.view.is2d(); +}, [SyncUiEventId.ActiveContentChanged, SyncUiEventId.ActiveViewportChanged, SyncUiEventId.ViewStateChanged]); ``` ## ConditionalStringValue @@ -18,14 +18,14 @@ The [ConditionalBooleanValue]($ui-abstract) class is used to specify a boolean v The [ConditionalStringValue]($ui-abstract) class is used to specify a string value that can change value during the session. When a class instance is constructed, a test function is provided and is used to update the internal string value. The function is run to get its initial value if the value is not explicitly set when it is constructed. The syncEventIds are used to allow the user to monitor the application for specific events which would trigger the test function to be rerun. Typically the UI container that holds the item that uses a conditional value will register to listen for the specified event Ids and call the refresh method to update its internal value. The example below is used to determine the icon to display based on the active content view. ```ts - const iconSpec = new ConditionalStringValue(() => { - const activeContentControl = ContentViewManager.getActiveContentControl(); - if (activeContentControl?.viewport?.view.is2d()) - return "icon-rotate-left"; - return "icon-gyroscope"; - }, [SyncUiEventId.ActiveContentChanged, SyncUiEventId.ActiveViewportChanged, SyncUiEventId.ViewStateChanged]), +const iconSpec = new ConditionalStringValue(() => { + const activeContentControl = ContentViewManager.getActiveContentControl(); + if (activeContentControl?.viewport?.view.is2d()) + return "icon-rotate-left"; + return "icon-gyroscope"; +}, [SyncUiEventId.ActiveContentChanged, SyncUiEventId.ActiveViewportChanged, SyncUiEventId.ViewStateChanged]), ``` ## API Reference -* [Item]($ui-abstract:Item) +- [Item]($ui-abstract:Item) diff --git a/docs/learning/ui/abstract/Properties.md b/docs/learning/ui/abstract/Properties.md index 9cf50636652c..b8478e7b8920 100644 --- a/docs/learning/ui/abstract/Properties.md +++ b/docs/learning/ui/abstract/Properties.md @@ -11,37 +11,37 @@ Included in the metadata are the type and format of the property's value, its ed Property Editor Params are used to specify the type of editor shown in the UI for the property. The [BasePropertyEditorParams]($ui-abstract:Properties) handles strings: ```ts - // ------------- text based edit field --------------- - private static _cityName = "city"; - private static _getCityDescription = (): PropertyDescription => { - return { - name: SampleTool._cityName, - displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.City"), - typename: "string", - }; - } +// ------------- text based edit field --------------- +private static _cityName = "city"; +private static _getCityDescription = (): PropertyDescription => { + return { + name: SampleTool._cityName, + displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.City"), + typename: "string", + }; +} ``` The size of the input field can be controlled with [InputEditorSizeParams]($ui-abstract:Properties): ```ts - // ------------- text based edit field --------------- - private static _stateName = "state"; - private static _getStateDescription = (): PropertyDescription => { - return { - name: SampleTool._stateName, - displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.State"), - typename: "string", - editor: { - params: [{ - type: PropertyEditorParamTypes.InputEditorSize, - size: 4, - /* maxLength: 60,*/ - } as InputEditorSizeParams, - ], - }, - }; - } +// ------------- text based edit field --------------- +private static _stateName = "state"; +private static _getStateDescription = (): PropertyDescription => { + return { + name: SampleTool._stateName, + displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.State"), + typename: "string", + editor: { + params: [{ + type: PropertyEditorParamTypes.InputEditorSize, + size: 4, + /* maxLength: 60,*/ + } as InputEditorSizeParams, + ], + }, + }; +} ``` For any editor type, the label can be suppressed using [SuppressLabelEditorParams]($ui-abstract:Properties). @@ -51,91 +51,91 @@ Numeric values can be formatted with custom formatters using [CustomFormattedNum Enums can be edited as a selection list: ```ts - // ------------- Enum based picklist --------------- - private static enumAsPicklistMessage(str: string) { return SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Options." + str); } - private static _optionsName = "enumAsPicklist"; - private static _getEnumAsPicklistDescription = (): PropertyDescription => { - return { - name: SampleTool._optionsName, - displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Options"), - typename: "enum", - enum: { - choices: [ - { label: SampleTool.enumAsPicklistMessage("Red"), value: ToolOptions.Red }, - { label: SampleTool.enumAsPicklistMessage("White"), value: ToolOptions.White }, - { label: SampleTool.enumAsPicklistMessage("Blue"), value: ToolOptions.Blue }, - { label: SampleTool.enumAsPicklistMessage("Yellow"), value: ToolOptions.Yellow }, - ], - }, - }; - } +// ------------- Enum based picklist --------------- +private static enumAsPicklistMessage(str: string) { return SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Options." + str); } +private static _optionsName = "enumAsPicklist"; +private static _getEnumAsPicklistDescription = (): PropertyDescription => { + return { + name: SampleTool._optionsName, + displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Options"), + typename: "enum", + enum: { + choices: [ + { label: SampleTool.enumAsPicklistMessage("Red"), value: ToolOptions.Red }, + { label: SampleTool.enumAsPicklistMessage("White"), value: ToolOptions.White }, + { label: SampleTool.enumAsPicklistMessage("Blue"), value: ToolOptions.Blue }, + { label: SampleTool.enumAsPicklistMessage("Yellow"), value: ToolOptions.Yellow }, + ], + }, + }; +} ``` or using as button group with [ButtonGroupEditorParams]($ui-abstract:Properties): ```ts - private static _methodsName = "selectionMethods"; - /* The property descriptions used to generate ToolSettings UI. */ - private static _getMethodsDescription(): PropertyDescription { - return { - name: SelectionTool._methodsName, - displayLabel: "", - typename: "enum", - editor: { - name: "enum-buttongroup", - params: [{ - type: PropertyEditorParamTypes.ButtonGroupData, - buttons: [ - { iconSpec: "icon-select-single" }, - { iconSpec: "icon-select-line" }, - { iconSpec: "icon-select-box" }, - ], - } as ButtonGroupEditorParams, { - type: PropertyEditorParamTypes.SuppressEditorLabel, - suppressLabelPlaceholder: true, - } as SuppressLabelEditorParams, - ], - }, - enum: { - choices: [ - { label: SelectionTool.methodsMessage("Pick"), value: SelectionMethod.Pick }, - { label: SelectionTool.methodsMessage("Line"), value: SelectionMethod.Line }, - { label: SelectionTool.methodsMessage("Box"), value: SelectionMethod.Box }, +private static _methodsName = "selectionMethods"; +/* The property descriptions used to generate ToolSettings UI. */ +private static _getMethodsDescription(): PropertyDescription { + return { + name: SelectionTool._methodsName, + displayLabel: "", + typename: "enum", + editor: { + name: "enum-buttongroup", + params: [{ + type: PropertyEditorParamTypes.ButtonGroupData, + buttons: [ + { iconSpec: "icon-select-single" }, + { iconSpec: "icon-select-line" }, + { iconSpec: "icon-select-box" }, ], - }, - }; - } + } as ButtonGroupEditorParams, { + type: PropertyEditorParamTypes.SuppressEditorLabel, + suppressLabelPlaceholder: true, + } as SuppressLabelEditorParams, + ], + }, + enum: { + choices: [ + { label: SelectionTool.methodsMessage("Pick"), value: SelectionMethod.Pick }, + { label: SelectionTool.methodsMessage("Line"), value: SelectionMethod.Line }, + { label: SelectionTool.methodsMessage("Box"), value: SelectionMethod.Box }, + ], + }, + }; +} ``` Colors may be edited in a color picker by specifying the available colors as an enum and using the [ColorEditorParams]($ui-abstract:Properties): ```ts - private static _colorName = "color"; - private static _getColorDescription = (): PropertyDescription => { - return { - name: SampleTool._colorName, - displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Color"), - typename: "number", - editor: { - name: "color-picker", - params: [{ - type: PropertyEditorParamTypes.ColorData, - colorValues: [ - ColorByName.blue as number, - ColorByName.red as number, - ColorByName.green as number, - ColorByName.yellow as number, - ColorByName.black as number, - ColorByName.gray as number, - ColorByName.purple as number, - ColorByName.pink as number, - ], - numColumns: 2, - } as ColorEditorParams, +private static _colorName = "color"; +private static _getColorDescription = (): PropertyDescription => { + return { + name: SampleTool._colorName, + displayLabel: SampleTool.i18n.translate("sampleNameSpace:tools.SampleTool.Prompts.Color"), + typename: "number", + editor: { + name: "color-picker", + params: [{ + type: PropertyEditorParamTypes.ColorData, + colorValues: [ + ColorByName.blue as number, + ColorByName.red as number, + ColorByName.green as number, + ColorByName.yellow as number, + ColorByName.black as number, + ColorByName.gray as number, + ColorByName.purple as number, + ColorByName.pink as number, ], - }, - }; - } + numColumns: 2, + } as ColorEditorParams, + ], + }, + }; +} ``` ## Property Record diff --git a/docs/learning/ui/abstract/StatusBar.md b/docs/learning/ui/abstract/StatusBar.md index a5fc09b740dc..8bb408955af0 100644 --- a/docs/learning/ui/abstract/StatusBar.md +++ b/docs/learning/ui/abstract/StatusBar.md @@ -9,21 +9,21 @@ The [StatusBar]($ui-abstract:StatusBar) classes and interfaces are used for crea The following example defines a StatusBar item that executes an action when pressed. In this simple example it just write a message to the console. ```ts - AbstractStatusBarItemUtilities.createActionItem("Sample:StatusBarItem1", StatusBarSection.Center, 100, "icon-developer", "Test tool-tip", - () => { - console.log("Got Here!"); - })); +AbstractStatusBarItemUtilities.createActionItem("Sample:StatusBarItem1", StatusBarSection.Center, 100, "icon-developer", "Test tool-tip", + () => { + console.log("Got Here!"); + })); ``` The following example defines a StatusBar item that just displays an icon and a label. The label is defined using a [ConditionalStringValue] and will update when the SyncUi Event Id defined, by the string "SampleApp.SET_EXTENSION_UI_VISIBLE", is fired by the application or extension. There is additional information about SyncUi at [SyncUi]($ui-framework:SyncUi). ```ts - const labelCondition = new ConditionalStringValue(() => SampleExtensionStateManager.isExtensionUiVisible ? "Active" : "Inactive", ["SampleApp.SET_EXTENSION_UI_VISIBLE"]); - AbstractStatusBarItemUtilities.createLabelItem("Sample:StatusBarLabel1", StatusBarSection.Center, 200, "icon-hand-2", labelCondition, undefined); - ``` +const labelCondition = new ConditionalStringValue(() => SampleExtensionStateManager.isExtensionUiVisible ? "Active" : "Inactive", ["SampleApp.SET_EXTENSION_UI_VISIBLE"]); +AbstractStatusBarItemUtilities.createLabelItem("Sample:StatusBarLabel1", StatusBarSection.Center, 200, "icon-hand-2", labelCondition, undefined); +``` See [StatusBarItemUtilities]($ui-framework) for React specific StatusBar item definitions. ## API Reference -* [StatusBar]($ui-abstract:StatusBar) +- [StatusBar]($ui-abstract:StatusBar) diff --git a/docs/learning/ui/abstract/Toolbar.md b/docs/learning/ui/abstract/Toolbar.md index c504b961b49c..6373f3393eb4 100644 --- a/docs/learning/ui/abstract/Toolbar.md +++ b/docs/learning/ui/abstract/Toolbar.md @@ -18,7 +18,6 @@ const simpleAction2Spec = ToolbarItemUtilities.createActionButton("simple-action (): void => { console.log("Got Here!"); }); - ``` Example of creating a group button definition and will allow access to multiple action buttons. In this example we place the two buttons defined above into a single group button. The last object passed in below contain any override values for any available property of a [GroupButton]($ui-abstract). @@ -33,4 +32,4 @@ See additional information under [ToolbarHelper]($ui-framework) to see functions ## API Reference -* [Toolbar]($ui-abstract:Toolbar) +- [Toolbar]($ui-abstract:Toolbar) diff --git a/docs/learning/ui/abstract/UiAdmin.md b/docs/learning/ui/abstract/UiAdmin.md index 113b9a48e495..bb287d09ac18 100644 --- a/docs/learning/ui/abstract/UiAdmin.md +++ b/docs/learning/ui/abstract/UiAdmin.md @@ -2,16 +2,16 @@ The [UiAdmin]($ui-abstract) class contains an API used to display the following: -* Context Menu -* Toolbar -* Menu Buttons -* Calculator -* Input editors -* Card at Cursor -* Tool Settings popup -* Keyin Palette -* Dialog -* HTML element +- Context Menu +- Toolbar +- Menu Buttons +- Calculator +- Input editors +- Card at Cursor +- Tool Settings popup +- Keyin Palette +- Dialog +- HTML element The UiAdmin methods are callable from `IModelApp.uiAdmin` in the imodeljs-frontend package. @@ -290,17 +290,17 @@ IModelApp.uiAdmin.showInputEditor(30, propertyDescription, IModelApp.uiAdmin.cur ### showCard ```tsx - private _showCard() { - const contentContainer = document.createElement("div"); +private _showCard() { + const contentContainer = document.createElement("div"); - // Add HTMLElements as child elements of contentContainer + // Add HTMLElements as child elements of contentContainer - ElementTooltip.isTooltipHalted = true; + ElementTooltip.isTooltipHalted = true; - IModelApp.uiAdmin.showCard(contentContainer, "Title", myToolbar, - IModelApp.uiAdmin.cursorPosition, IModelApp.uiAdmin.createXAndY(8, 8), - toolbarItemExecuted, toolbarCancel, RelativePosition.Right); - } + IModelApp.uiAdmin.showCard(contentContainer, "Title", myToolbar, + IModelApp.uiAdmin.cursorPosition, IModelApp.uiAdmin.createXAndY(8, 8), + toolbarItemExecuted, toolbarCancel, RelativePosition.Right); +} ``` ![uiAdmin-showCard](./images/UiAdmin-showCard.png "IModelApp.uiAdmin.showCard") @@ -313,17 +313,17 @@ The `FrameworkUiAdmin.showReactCard` function may be used instead of `UiAdmin.sh when React components with event handlers need to be used. ```tsx - private _showReactCard() { - let content: React.ReactNode; +private _showReactCard() { + let content: React.ReactNode; - // Set content to React elements + // Set content to React elements - ElementTooltip.isTooltipHalted = true; + ElementTooltip.isTooltipHalted = true; - (IModelApp.uiAdmin as FrameworkUiAdmin).showReactCard(content, "Title", myToolbar, - IModelApp.uiAdmin.cursorPosition, IModelApp.uiAdmin.createXAndY(8, 8), - toolbarItemExecuted, toolbarCancel, RelativePosition.Right); - } + (IModelApp.uiAdmin as FrameworkUiAdmin).showReactCard(content, "Title", myToolbar, + IModelApp.uiAdmin.cursorPosition, IModelApp.uiAdmin.createXAndY(8, 8), + toolbarItemExecuted, toolbarCancel, RelativePosition.Right); +} ``` #### hideCard @@ -331,10 +331,10 @@ when React components with event handlers need to be used. The `hideCard` function hides the Card. ```tsx - private _closeCard() { - IModelApp.uiAdmin.hideCard(); - ElementTooltip.isTooltipHalted = false; - } +private _closeCard() { + IModelApp.uiAdmin.hideCard(); + ElementTooltip.isTooltipHalted = false; +} ``` ### openToolSettingsPopup @@ -447,10 +447,9 @@ export class MyToolWithSettings extends PrimitiveTool { The `closeToolSettingsPopup` function closes the popup. ```ts - private _handleToolSettingsPopupCancel = () => { - IModelApp.uiAdmin.closeToolSettingsPopup(); - }; - +private _handleToolSettingsPopupCancel = () => { + IModelApp.uiAdmin.closeToolSettingsPopup(); +}; ``` ![uiAdmin-openToolSettingsPopup1](./images/UiAdmin-openToolSettingsPopup1.png "IModelApp.uiAdmin.openToolSettingsPopup 1") @@ -595,7 +594,7 @@ class DynamicModalUiDataProvider extends DialogLayoutDataProvider { The `closeDialog` function closes a Dialog with a given Id. ```ts - IModelApp.uiAdmin.closeDialog("SampleApp:DynamicModal"); +IModelApp.uiAdmin.closeDialog("SampleApp:DynamicModal"); ``` ![uiAdmin-openDialog1](./images/UiAdmin-openDialog1.png "IModelApp.uiAdmin.openDialog 1") @@ -604,4 +603,4 @@ The `closeDialog` function closes a Dialog with a given Id. ## API Reference -* [UiAdmin]($ui-abstract) +- [UiAdmin]($ui-abstract) diff --git a/docs/learning/ui/abstract/UiDataProvider.md b/docs/learning/ui/abstract/UiDataProvider.md index 4d4a524dd460..dfa27e89c655 100644 --- a/docs/learning/ui/abstract/UiDataProvider.md +++ b/docs/learning/ui/abstract/UiDataProvider.md @@ -7,62 +7,63 @@ As an abstract class, the app must extend it with a class in their own app: ```ts export class MyUiProvider extends UiDataProvider {} ``` + UiDataProvider relies on the app to provide an array of [DialogPropertyItem]($ui-abstract:Dialog) to communicate with the UI. To set this up, the app defines supplyAvailableProperties() to return the array of DialogPropertyItem interfaces: ```ts - public supplyAvailableProperties(): DialogPropertyItem[] { - return [ - { value: { value: this.currentAnimationType as number }, propertyName: this.currentAnimationTypePropertyName }, - { value: { value: this.monitorMode }, propertyName: this.monitorModePropertyName }, - { value: { value: this.startTime }, propertyName: this.startTimePropertyName }, - { value: { value: this.endTime }, propertyName: this.endTimePropertyName }, - { value: { value: this.monitorTime }, propertyName: this.monitorTimePropertyName }, - { value: { value: this.minDate }, propertyName: this.minDatePropertyName }, - { value: { value: this.maxDate }, propertyName: this.maxDatePropertyName }, - { value: { value: this.alarmText }, propertyName: this.alarmTextPropertyName }, - ]; - } +public supplyAvailableProperties(): DialogPropertyItem[] { + return [ + { value: { value: this.currentAnimationType as number }, propertyName: this.currentAnimationTypePropertyName }, + { value: { value: this.monitorMode }, propertyName: this.monitorModePropertyName }, + { value: { value: this.startTime }, propertyName: this.startTimePropertyName }, + { value: { value: this.endTime }, propertyName: this.endTimePropertyName }, + { value: { value: this.monitorTime }, propertyName: this.monitorTimePropertyName }, + { value: { value: this.minDate }, propertyName: this.minDatePropertyName }, + { value: { value: this.maxDate }, propertyName: this.maxDatePropertyName }, + { value: { value: this.alarmText }, propertyName: this.alarmTextPropertyName }, + ]; +} ``` The method processChangesInUi() notifies the dataProvider that the UI has changed. This is usually called from the OK handler in a modal dialog. Here's an example of the processChangesInUi method that goes with the supplyAvailableProperties example above: ```ts - public processChangesInUi(properties: DialogPropertyItem[]): PropertyChangeResult { - if (properties.length > 0) { - for (const prop of properties) { - if (prop.propertyName === this.currentAnimationTypePropertyName) { - this.currentAnimationType = this.getAnimationType(prop.value.value! as number); - continue; - } - if (prop.propertyName === this.monitorModePropertyName) { - this.monitorMode = prop.value.value! as boolean; - continue; - } - if (prop.propertyName === this.startTimePropertyName) { - this.startTime = (prop.value.value! as Date); - continue; - } - if (prop.propertyName === this.endTimePropertyName) { - this.endTime = (prop.value.value! as Date); - continue; - } +public processChangesInUi(properties: DialogPropertyItem[]): PropertyChangeResult { + if (properties.length > 0) { + for (const prop of properties) { + if (prop.propertyName === this.currentAnimationTypePropertyName) { + this.currentAnimationType = this.getAnimationType(prop.value.value! as number); + continue; + } + if (prop.propertyName === this.monitorModePropertyName) { + this.monitorMode = prop.value.value! as boolean; + continue; + } + if (prop.propertyName === this.startTimePropertyName) { + this.startTime = (prop.value.value! as Date); + continue; + } + if (prop.propertyName === this.endTimePropertyName) { + this.endTime = (prop.value.value! as Date); + continue; } } + } - if (this.monitorMode) { - this.extension.runMonitor(this.currentAnimationType); - return { status: PropertyChangeStatus.Success }; - } else { - // get duration in minutes. - let duration: number = (this.endTime.getTime() - this.startTime.getTime()) / (60.0 * 1000.0); - if (duration < 10) - duration = 10; - this.extension.runAnimation(this.currentAnimationType, duration, this.startTime.getTime()); - return { status: PropertyChangeStatus.Success }; - } + if (this.monitorMode) { + this.extension.runMonitor(this.currentAnimationType); + return { status: PropertyChangeStatus.Success }; + } else { + // get duration in minutes. + let duration: number = (this.endTime.getTime() - this.startTime.getTime()) / (60.0 * 1000.0); + if (duration < 10) + duration = 10; + this.extension.runAnimation(this.currentAnimationType, duration, this.startTime.getTime()); + return { status: PropertyChangeStatus.Success }; } +} ``` ## API Reference -* [UiDataProvider]($ui-abstract:Dialog) +- [UiDataProvider]($ui-abstract:Dialog) diff --git a/docs/learning/ui/abstract/UiItemsProvider.md b/docs/learning/ui/abstract/UiItemsProvider.md index 991f3964291b..a6225984822f 100644 --- a/docs/learning/ui/abstract/UiItemsProvider.md +++ b/docs/learning/ui/abstract/UiItemsProvider.md @@ -117,10 +117,10 @@ These actions are defined by [UiItemsApplicationAction]($ui-abstract). The application implements the [UiItemsApplication]($ui-abstract) and provides one or more of the following optional functions to validate items: -* validateToolbarButtonItem - Validate and optionally update a Toolbar button item -* validateStatusBarItem - Validate and optionally update a StatusBar item -* validateBackstageItem - Validate and optionally update a Backstage item -* validateWidget - Validate and optionally update a Widget +- validateToolbarButtonItem - Validate and optionally update a Toolbar button item +- validateStatusBarItem - Validate and optionally update a StatusBar item +- validateBackstageItem - Validate and optionally update a Backstage item +- validateWidget - Validate and optionally update a Widget To setup for arbitration, the application sets the `UiItemsArbiter.uiItemsApplication` member, which may only be set once: @@ -131,10 +131,10 @@ UiItemsArbiter.uiItemsApplication = new ExampleUiItemsApplication(); A [UiItemsProvider]($ui-abstract) can listen for the actions taken by the application by defining the following optional methods: -* onToolbarButtonItemArbiterChange - Called if the application changes the Toolbar button item -* onStatusBarItemArbiterChange - Called if the application changes the StatusBar item -* onBackstageItemArbiterChange - Called if the application changes the Backstage item -* onWidgetArbiterChange - Called if the application changes the Widget +- onToolbarButtonItemArbiterChange - Called if the application changes the Toolbar button item +- onStatusBarItemArbiterChange - Called if the application changes the StatusBar item +- onBackstageItemArbiterChange - Called if the application changes the Backstage item +- onWidgetArbiterChange - Called if the application changes the Widget ### Examples @@ -181,4 +181,4 @@ class ExampleUiItemsApplication implements UiItemsApplication { ## API Reference -* [UiItemsProvider]($ui-abstract:UiItemsProvider) +- [UiItemsProvider]($ui-abstract:UiItemsProvider) diff --git a/docs/learning/ui/abstract/Utilities.md b/docs/learning/ui/abstract/Utilities.md index b2780e351138..10d404894fd3 100644 --- a/docs/learning/ui/abstract/Utilities.md +++ b/docs/learning/ui/abstract/Utilities.md @@ -17,4 +17,4 @@ throw new UiError("my-package.MyClass", "This is my error"); ## API Reference -* [Utilities]($ui-abstract:Utilities) +- [Utilities]($ui-abstract:Utilities) diff --git a/docs/learning/ui/abstract/index.md b/docs/learning/ui/abstract/index.md index 1afed78fd743..680fccfbe195 100644 --- a/docs/learning/ui/abstract/index.md +++ b/docs/learning/ui/abstract/index.md @@ -6,13 +6,13 @@ Therefore, code in imodeljs-frontend can use classes and interfaces in ui-abstra ## Topics -* [Backstage](./Backstage.md) - Abstractions used by ui-framework package to create and manage the display of Backstage menu items. -* [DialogItem](./DialogItem.md) - Interfaces used by UiLayoutDataProvider to create UI automatically for use in AppUi apps. -* [Item](./Item.md) - Classes for working with an Item in a Toolbar, Widget, Backstage or Context Menu. -* [Properties](./Properties.md) - Interfaces and classes to create UI editors for Property data. -* [StatusBar](./StatusBar.md) - Classes for creating and managing items in the status bar. -* [Toolbar](./Toolbar.md) - Classes for creating and managing items in a toolbar. -* [UiAdmin](./UiAdmin.md) - Abstractions for UI controls, such as toolbars, buttons and menus and are callable from IModelApp.uiAdmin in imodeljs-frontend. -* [UiItemsProvider](./UiItemsProvider.md) - Classes and interfaces for specifying UI items to be inserted at runtime. -* [UiDataProvider](./UiDataProvider.md) - Data synchronization for apps that directly create UI with React or other UI libraries. -* [Utilities](./Utilities.md) - Various utility classes for working with a UI. +- [Backstage](./Backstage.md) - Abstractions used by ui-framework package to create and manage the display of Backstage menu items. +- [DialogItem](./DialogItem.md) - Interfaces used by UiLayoutDataProvider to create UI automatically for use in AppUi apps. +- [Item](./Item.md) - Classes for working with an Item in a Toolbar, Widget, Backstage or Context Menu. +- [Properties](./Properties.md) - Interfaces and classes to create UI editors for Property data. +- [StatusBar](./StatusBar.md) - Classes for creating and managing items in the status bar. +- [Toolbar](./Toolbar.md) - Classes for creating and managing items in a toolbar. +- [UiAdmin](./UiAdmin.md) - Abstractions for UI controls, such as toolbars, buttons and menus and are callable from IModelApp.uiAdmin in imodeljs-frontend. +- [UiItemsProvider](./UiItemsProvider.md) - Classes and interfaces for specifying UI items to be inserted at runtime. +- [UiDataProvider](./UiDataProvider.md) - Data synchronization for apps that directly create UI with React or other UI libraries. +- [Utilities](./Utilities.md) - Various utility classes for working with a UI. diff --git a/docs/learning/ui/components/Color.md b/docs/learning/ui/components/Color.md index ef208cf19a7b..e47ba3b45559 100644 --- a/docs/learning/ui/components/Color.md +++ b/docs/learning/ui/components/Color.md @@ -36,16 +36,16 @@ interface State { #### Preset Colors ```tsx - private readonly _presetColors = [ - new ColorDef(ColorByName.grey), - new ColorDef(ColorByName.lightGrey), - new ColorDef(ColorByName.darkGrey), - new ColorDef(ColorByName.lightBlue), - new ColorDef(ColorByName.lightGreen), - new ColorDef(ColorByName.darkGreen), - new ColorDef(ColorByName.tan), - new ColorDef(ColorByName.darkBrown), - ]; +private readonly _presetColors = [ + new ColorDef(ColorByName.grey), + new ColorDef(ColorByName.lightGrey), + new ColorDef(ColorByName.darkGrey), + new ColorDef(ColorByName.lightBlue), + new ColorDef(ColorByName.lightGreen), + new ColorDef(ColorByName.darkGreen), + new ColorDef(ColorByName.tan), + new ColorDef(ColorByName.darkBrown), +]; ``` #### render() method @@ -140,4 +140,4 @@ private _handleColorChange = (value: ColorDef) => { ## API Reference -* [Color]($ui-components:Color) +- [Color]($ui-components:Color) diff --git a/docs/learning/ui/components/Common.md b/docs/learning/ui/components/Common.md index b2139066145e..f366143e44c8 100644 --- a/docs/learning/ui/components/Common.md +++ b/docs/learning/ui/components/Common.md @@ -14,4 +14,4 @@ The Common category can be broken down further into the following sections: ## API Reference -* [Common]($ui-components:Common) +- [Common]($ui-components:Common) diff --git a/docs/learning/ui/components/LineWeight.md b/docs/learning/ui/components/LineWeight.md index 938a16c8f88e..76d280ddc1c9 100644 --- a/docs/learning/ui/components/LineWeight.md +++ b/docs/learning/ui/components/LineWeight.md @@ -41,4 +41,4 @@ private _handleWeightChange = (value: number) => { ## API Reference -* [LineWeight]($ui-components:LineWeight) +- [LineWeight]($ui-components:LineWeight) diff --git a/docs/learning/ui/components/OIDC.md b/docs/learning/ui/components/OIDC.md index fee7bb8eb4be..d3006455ad09 100644 --- a/docs/learning/ui/components/OIDC.md +++ b/docs/learning/ui/components/OIDC.md @@ -39,4 +39,4 @@ import { FrontendRequestContext } from "@bentley/imodeljs-frontend"; ## API Reference -* [OIDC]($ui-components:OIDC) +- [OIDC]($ui-components:OIDC) diff --git a/docs/learning/ui/components/PropertyEditors.md b/docs/learning/ui/components/PropertyEditors.md index 1b16e392afea..784693bf0763 100644 --- a/docs/learning/ui/components/PropertyEditors.md +++ b/docs/learning/ui/components/PropertyEditors.md @@ -23,18 +23,18 @@ which contains the type name and optional editor name. The following is a list of the provided property editors: -* [BasicPropertyEditor]($ui-components) - registered for the "text" and "string" type names -* [BooleanPropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names -* [ColorPropertyEditor]($ui-components) - registered for the "number" type name and "color-picker" editor name -* [EnumPropertyButtonGroupEditor]($ui-components) - registered for the "enum" type name and the "enum-buttongroup" editor name -* [EnumPropertyEditor]($ui-components) - registered for the "enum" type name -* [ImageCheckBoxPropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names and "image-check-box" editor name -* [NumericInputPropertyEditor]($ui-components) - registered for the "number" type name and "numeric-input" editor name -* [SliderPropertyEditor]($ui-components) - registered for the "number" type name and "slider" editor name -* [TextareaPropertyEditor]($ui-components) - registered for the "text" and "string" type names and "multi-line" editor name -* [ThemedEnumPropertyEditor]($ui-components) - registered for the "enum" type name and "themed-enum" editor name -* [TogglePropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names and "toggle" editor name -* [WeightPropertyEditor]($ui-components) - registered for the "number" type name and "weight-picker" editor name +- [BasicPropertyEditor]($ui-components) - registered for the "text" and "string" type names +- [BooleanPropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names +- [ColorPropertyEditor]($ui-components) - registered for the "number" type name and "color-picker" editor name +- [EnumPropertyButtonGroupEditor]($ui-components) - registered for the "enum" type name and the "enum-buttongroup" editor name +- [EnumPropertyEditor]($ui-components) - registered for the "enum" type name +- [ImageCheckBoxPropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names and "image-check-box" editor name +- [NumericInputPropertyEditor]($ui-components) - registered for the "number" type name and "numeric-input" editor name +- [SliderPropertyEditor]($ui-components) - registered for the "number" type name and "slider" editor name +- [TextareaPropertyEditor]($ui-components) - registered for the "text" and "string" type names and "multi-line" editor name +- [ThemedEnumPropertyEditor]($ui-components) - registered for the "enum" type name and "themed-enum" editor name +- [TogglePropertyEditor]($ui-components) - registered for the "bool" and "boolean" type names and "toggle" editor name +- [WeightPropertyEditor]($ui-components) - registered for the "number" type name and "weight-picker" editor name **Note**: `PropertyEditorManager.registerEditor` is called by the system for these delivered property editors. @@ -45,4 +45,4 @@ The [StandardTypeNames]($ui-abstract) and [StandardEditorNames]($ui-abstract) en ## API Reference -* [PropertyEditors]($ui-components:PropertyEditors) +- [PropertyEditors]($ui-components:PropertyEditors) diff --git a/docs/learning/ui/components/PropertyGrid.md b/docs/learning/ui/components/PropertyGrid.md index 32c50bbc0ac3..afdb4bc6761d 100644 --- a/docs/learning/ui/components/PropertyGrid.md +++ b/docs/learning/ui/components/PropertyGrid.md @@ -7,13 +7,13 @@ classes and components for working with a PropertyGrid control. The following React components comprise the PropertyGrid control. -* [PropertyGrid]($ui-components) - renders property categories -* [PropertyList]($ui-components) - renders multiple properties within a category as a list -* [PropertyRenderer]($ui-components) - renders a property -* [PrimitivePropertyRenderer]($ui-components) - renders a primitive property -* [NonPrimitivePropertyRenderer]($ui-components) - renders struct and array properties -* [PropertyView]($ui-components) - renders a property as a label/value pair -* [PropertyCategoryBlock]($ui-components) - Expandable block for a category; uses [ExpandableBlock]($ui-core) for rendering +- [PropertyGrid]($ui-components) - renders property categories +- [PropertyList]($ui-components) - renders multiple properties within a category as a list +- [PropertyRenderer]($ui-components) - renders a property +- [PrimitivePropertyRenderer]($ui-components) - renders a primitive property +- [NonPrimitivePropertyRenderer]($ui-components) - renders struct and array properties +- [PropertyView]($ui-components) - renders a property as a label/value pair +- [PropertyCategoryBlock]($ui-components) - Expandable block for a category; uses [ExpandableBlock]($ui-core) for rendering There are a number of value renderer components for different types that can be found in the [Properties]($ui-components:Properties) category. Those components are managed by the [PropertyValueRendererManager]($ui-components). @@ -107,6 +107,6 @@ const rulesetId = "Default"; ## API Reference -* [PropertyGrid]($ui-components:PropertyGrid) -* [Properties in @bentley/ui-components]($ui-components:Properties) -* [Properties in @bentley/ui-abstract]($ui-abstract:Properties) +- [PropertyGrid]($ui-components:PropertyGrid) +- [Properties in @bentley/ui-components]($ui-components:Properties) +- [Properties in @bentley/ui-abstract]($ui-abstract:Properties) diff --git a/docs/learning/ui/components/Table.md b/docs/learning/ui/components/Table.md index 5940fa9cdc90..740890c60665 100644 --- a/docs/learning/ui/components/Table.md +++ b/docs/learning/ui/components/Table.md @@ -7,9 +7,9 @@ classes and components for working with a Table control. The following React components comprise the Table control. -* [Table]($ui-components) - renders data rows and columns in a grid along with a header -* [TableCell]($ui-components) - renders a table cell -* [TableCellContent]($ui-components) - renders table cell content +- [Table]($ui-components) - renders data rows and columns in a grid along with a header +- [TableCell]($ui-components) - renders a table cell +- [TableCellContent]($ui-components) - renders table cell content There are a number of value renderer components for different types that can be found in the [Properties]($ui-components:Properties) category. Those components are managed by the [PropertyValueRendererManager]($ui-components). @@ -91,12 +91,12 @@ For selection support, the `selectionMode` prop specifies the desired [Selection and the `tableSelectionTarget` prop specifies the desired [TableSelectionTarget]($ui-components). There are a number of selection related callback functions: -* isRowSelected - Callback for determining if row is selected -* onRowsSelected - Callback for when rows are selected -* onRowsDeselected - Callback for when rows are deselected -* isCellSelected - Callback for determining if cell is selected -* onCellsSelected - Callback for when cells are selected -* onCellsDeselected - Callback for when cells are deselected +- isRowSelected - Callback for determining if row is selected +- onRowsSelected - Callback for when rows are selected +- onRowsDeselected - Callback for when rows are deselected +- isCellSelected - Callback for determining if cell is selected +- onCellsSelected - Callback for when cells are selected +- onCellsDeselected - Callback for when cells are deselected For cell editing support, the `onPropertyUpdated` callback function is called when properties are updated. The `ColumnDescription.editable` member should be set to true to enable cell editing. @@ -151,6 +151,6 @@ const rulesetId = "Default"; ## API Reference -* [Table in @bentley/ui-components]($ui-components:Table) -* [Properties in @bentley/ui-components]($ui-components:Properties) -* [Properties in @bentley/ui-abstract]($ui-abstract:Properties) +- [Table in @bentley/ui-components]($ui-components:Table) +- [Properties in @bentley/ui-components]($ui-components:Properties) +- [Properties in @bentley/ui-abstract]($ui-abstract:Properties) diff --git a/docs/learning/ui/components/Toolbar.md b/docs/learning/ui/components/Toolbar.md index 557f3f496a32..0c8f100848dc 100644 --- a/docs/learning/ui/components/Toolbar.md +++ b/docs/learning/ui/components/Toolbar.md @@ -17,7 +17,6 @@ components that provide a toolbar that supports an overflow button. The following sample shows the definition of a toolbar. ``` tsx - // First create toolbar item definitions const toolbarItems = [ ToolbarHelper.createToolbarItemFromItemDef(0, CoreTools.keyinBrowserButtonItemDef), @@ -36,13 +35,12 @@ const toolbarItems = [ useDragInteraction={false} useProximityOpacity={true} />; - ``` The props defined above are all defaults, so the above definition could be shortened to the following. ``` tsx - ; +; ``` ![ToolbarWithOverflow](./images/toolbar.png "ToolbarWithOverflow Component") @@ -56,14 +54,14 @@ Toolbar support two basic Popup buttons, one that is created for a [GroupButton] A [CustomToolbarItem]($ui-components) definition can be used to define a button with a custom pop-up panel. The `panelContentNode` property is used to define the React component to display in the popup panel. ```tsx - const buttonDefWithPopupPanel = { - id: "MyPopupPanelButton", - itemPriority: 10, - icon: "icon-placeholder", - label: "Show Hello World", - isCustom: true, - panelContentNode:
HelloWorld!
, - } as CustomToolbarItem; +const buttonDefWithPopupPanel = { + id: "MyPopupPanelButton", + itemPriority: 10, + icon: "icon-placeholder", + label: "Show Hello World", + isCustom: true, + panelContentNode:
HelloWorld!
, + } as CustomToolbarItem; ``` #### Group Popup Panel @@ -71,17 +69,17 @@ A [CustomToolbarItem]($ui-components) definition can be used to define a button Below is an example of setting up a [GroupButton]($ui-abstract) definition that shows a pop-up panel of actions. ```tsx - const childItems: ActionButton[] = [ - ToolbarItemUtilities.createActionButton("Child1", 10, "icon-app-1", "Child1 Tool", (): void => {/* start tool or open a dialog */ }), - ToolbarItemUtilities.createActionButton("Child2", 20, "icon-app-2", "Child2 Tool", (): void => {/* start tool or open a dialog */}), - ]; - - const toolbarItemsWithGroup: CommonToolbarItem[] = [ - ToolbarItemUtilities.createGroupButton("GroupButton", 10, "icon-developer", "Tool Group", childItems), - ]; +const childItems: ActionButton[] = [ + ToolbarItemUtilities.createActionButton("Child1", 10, "icon-app-1", "Child1 Tool", (): void => {/* start tool or open a dialog */ }), + ToolbarItemUtilities.createActionButton("Child2", 20, "icon-app-2", "Child2 Tool", (): void => {/* start tool or open a dialog */}), +]; + +const toolbarItemsWithGroup: CommonToolbarItem[] = [ + ToolbarItemUtilities.createGroupButton("GroupButton", 10, "icon-developer", "Tool Group", childItems), +]; ``` ## API Reference -* [Abstract Toolbar definitions]($ui-abstract:Toolbar) -* [Toolbar]($ui-components:Toolbar) +- [Abstract Toolbar definitions]($ui-abstract:Toolbar) +- [Toolbar]($ui-components:Toolbar) diff --git a/docs/learning/ui/components/Tree.md b/docs/learning/ui/components/Tree.md index fd17a1555bbb..fa8a3f023c09 100644 --- a/docs/learning/ui/components/Tree.md +++ b/docs/learning/ui/components/Tree.md @@ -9,21 +9,21 @@ The older Tree component has been deprecated and replaced by the [ControlledTree The following React components comprise the ControlledTree component. -* [ControlledTree]($ui-components) - renders hierarchical data and is fully controlled from outside -* [TreeRenderer]($ui-components) - default component for rendering the tree -* [TreeNodeRenderer]($ui-components) - default component for rendering tree nodes +- [ControlledTree]($ui-components) - renders hierarchical data and is fully controlled from outside +- [TreeRenderer]($ui-components) - default component for rendering the tree +- [TreeNodeRenderer]($ui-components) - default component for rendering tree nodes There are also several [Tree]($ui-core:Tree) presentational components in the `@bentley/ui-core` package used for rendering. The following React hooks work in conjunction with the ControlledTree component. -* [usePagedTreeNodeLoader]($ui-components) - creates a paging nodes' loader using the supplied data provider and model source. The loader pulls nodes from the data provider and puts them into the model source. -* [useTreeModelSource]($ui-components) - creates a [TreeModelSource]($ui-components) -* [useTreeNodeLoader]($ui-components) - creates a nodes' loader using the supplied data provider and model source. The loader pulls nodes from the data provider and puts them into the model source. -* [useVisibleTreeNodes]($ui-components) - returns a flat list of visible nodes from given [TreeModelSource]($ui-components) and subscribes to onModelChanged event to update the list when model changes -* [usePresentationTreeNodeLoader]($presentation-components) - creates a [PagedTreeNodeLoader]($$ui-components) with [PresentationTreeDataProvider]($presentation-components) using supplied imodel and ruleset -* [useUnifiedSelectionTreeEventHandler]($presentation-components) - creates and disposes [UnifiedSelectionTreeEventHandler]($presentation-components) +- [usePagedTreeNodeLoader]($ui-components) - creates a paging nodes' loader using the supplied data provider and model source. The loader pulls nodes from the data provider and puts them into the model source. +- [useTreeModelSource]($ui-components) - creates a [TreeModelSource]($ui-components) +- [useTreeNodeLoader]($ui-components) - creates a nodes' loader using the supplied data provider and model source. The loader pulls nodes from the data provider and puts them into the model source. +- [useVisibleTreeNodes]($ui-components) - returns a flat list of visible nodes from given [TreeModelSource]($ui-components) and subscribes to onModelChanged event to update the list when model changes +- [usePresentationTreeNodeLoader]($presentation-components) - creates a [PagedTreeNodeLoader]($$ui-components) with [PresentationTreeDataProvider]($presentation-components) using supplied imodel and ruleset +- [useUnifiedSelectionTreeEventHandler]($presentation-components) - creates and disposes [UnifiedSelectionTreeEventHandler]($presentation-components) ## Tree Node Loader, Data Provider and Model @@ -33,25 +33,25 @@ The Data Provider is a legacy provider but is still supported by the Node Loader ### Node Loader -* [ITreeNodeLoader]($ui-components) - interface for the Tree node loader which is used to load tree nodes -* [ITreeNodeLoaderWithProvider]($ui-components) - interface for Tree node loader which uses [TreeDataProvider]($ui-components) to load nodes +- [ITreeNodeLoader]($ui-components) - interface for the Tree node loader which is used to load tree nodes +- [ITreeNodeLoaderWithProvider]($ui-components) - interface for Tree node loader which uses [TreeDataProvider]($ui-components) to load nodes ### Data Provider -* [ITreeDataProvider]($ui-components) - legacy interface for a Tree data provider -* [TreeDataProvider]($ui-components) - type definition for all Tree data providers -* [TreeNodeItem]($ui-components) - information about a node item which can be displayed in a Tree -* [EditableTreeDataProvider]($ui-components) - provides cell editing processing for the Tree -* [IPresentationTreeDataProvider]($presentation-components) - Presentation Rules tree data provider +- [ITreeDataProvider]($ui-components) - legacy interface for a Tree data provider +- [TreeDataProvider]($ui-components) - type definition for all Tree data providers +- [TreeNodeItem]($ui-components) - information about a node item which can be displayed in a Tree +- [EditableTreeDataProvider]($ui-components) - provides cell editing processing for the Tree +- [IPresentationTreeDataProvider]($presentation-components) - Presentation Rules tree data provider ### Model -* [TreeModel]($ui-components) - interface that describes a tree model containing methods to get the root node and nodes by id and parent id -* [TreeModelNode]($ui-components) - immutable data structure that describes tree node -* [MutableTreeModelNode]($ui-components) - mutable data structure that describes tree node -* [VisibleTreeNodes]($ui-components) - interface that describes the set of visible tree nodes as a flat list -* [TreeModelSource]($ui-components) - controls tree model and visible tree nodes. It is used to modify model and inform when tree model changes. -* [MutableTreeModel]($ui-components) - implementation of TreeModel that allows adding and removing tree nodes +- [TreeModel]($ui-components) - interface that describes a tree model containing methods to get the root node and nodes by id and parent id +- [TreeModelNode]($ui-components) - immutable data structure that describes tree node +- [MutableTreeModelNode]($ui-components) - mutable data structure that describes tree node +- [VisibleTreeNodes]($ui-components) - interface that describes the set of visible tree nodes as a flat list +- [TreeModelSource]($ui-components) - controls tree model and visible tree nodes. It is used to modify model and inform when tree model changes. +- [MutableTreeModel]($ui-components) - implementation of TreeModel that allows adding and removing tree nodes ## Properties @@ -59,10 +59,10 @@ The ControlledTree properties are defined in the [ControlledTreeProps]($ui-compo The following props are required: -* `visibleNodes` - the flat list of nodes to be rendered in tree -* `nodeLoader` - the Node Loader used to load root nodes and placeholder nodes -* `treeEvents` - the tree events handler -* `selectionMode` - Mode of nodes' selection in tree +- `visibleNodes` - the flat list of nodes to be rendered in tree +- `nodeLoader` - the Node Loader used to load root nodes and placeholder nodes +- `treeEvents` - the tree events handler +- `selectionMode` - Mode of nodes' selection in tree The optional props include overrides for renderers, flags for enabling descriptions and icons, @@ -105,13 +105,13 @@ export default function SimpleTreeComponent(props: Props) { ## API Reference -* [Tree in @bentley/ui-components]($ui-components:Tree) -* [Tree in @bentley/presentation-components]($presentation-components:Tree) -* [Tree in @bentley/ui-core]($ui-core:Tree) -* [Properties in @bentley/ui-components]($ui-components:Properties) -* [Properties in @bentley/ui-abstract]($ui-abstract:Properties) +- [Tree in @bentley/ui-components]($ui-components:Tree) +- [Tree in @bentley/presentation-components]($presentation-components:Tree) +- [Tree in @bentley/ui-core]($ui-core:Tree) +- [Properties in @bentley/ui-components]($ui-components:Properties) +- [Properties in @bentley/ui-abstract]($ui-abstract:Properties) ## Samples -* [simple-viewer-app](/~https://github.com/imodeljs/imodeljs-samples/tree/master/interactive-app/simple-viewer-app): An example of an interactive application which can display graphical data, browse iModel catalog and view element properties. +- [simple-viewer-app](/~https://github.com/imodeljs/imodeljs-samples/tree/master/interactive-app/simple-viewer-app): An example of an interactive application which can display graphical data, browse iModel catalog and view element properties. diff --git a/docs/learning/ui/components/TypeConverters.md b/docs/learning/ui/components/TypeConverters.md index 944550fa350f..e6867ce6d4fb 100644 --- a/docs/learning/ui/components/TypeConverters.md +++ b/docs/learning/ui/components/TypeConverters.md @@ -10,8 +10,8 @@ The TypeConverter class implements the [SortComparer]($ui-components), Type converters may optionally implement one of the following interfaces to provide value processing for Table filtering: -* [LessGreaterOperatorProcessor]($ui-components) - numeric types -* [StringOperatorProcessor]($ui-components) - string types +- [LessGreaterOperatorProcessor]($ui-components) - numeric types +- [StringOperatorProcessor]($ui-components) - string types Each type converter must be registered with the [TypeConverterManager]($ui-components) for a given type name @@ -30,18 +30,18 @@ const typeConverter = TypeConverterManager.TypeConverterManager.getConverter("st The following is a list of the provided type converters: -* [BooleanTypeConverter]($ui-components) -* [CompositeTypeConverter]($ui-components) -* [DateTimeTypeConverter]($ui-components) -* [EnumTypeConverter]($ui-components) -* [FloatTypeConverter]($ui-components) -* [HexadecimalTypeConverter]($ui-components) -* [IntTypeConverter]($ui-components) -* [NavigationPropertyTypeConverter]($ui-components) -* [Point2dTypeConverter]($ui-components) -* [Point3dTypeConverter]($ui-components) -* [ShortDateTypeConverter]($ui-components) -* [StringTypeConverter]($ui-components) +- [BooleanTypeConverter]($ui-components) +- [CompositeTypeConverter]($ui-components) +- [DateTimeTypeConverter]($ui-components) +- [EnumTypeConverter]($ui-components) +- [FloatTypeConverter]($ui-components) +- [HexadecimalTypeConverter]($ui-components) +- [IntTypeConverter]($ui-components) +- [NavigationPropertyTypeConverter]($ui-components) +- [Point2dTypeConverter]($ui-components) +- [Point3dTypeConverter]($ui-components) +- [ShortDateTypeConverter]($ui-components) +- [StringTypeConverter]($ui-components) **Note**: `TypeConverterManager.registerConverter` is called by the system for these delivered type converters. @@ -52,4 +52,4 @@ This enum contains the type names used when registering the converters listed ab ## API Reference -* [TypeConverters]($ui-components:TypeConverters) +- [TypeConverters]($ui-components:TypeConverters) diff --git a/docs/learning/ui/components/Viewport.md b/docs/learning/ui/components/Viewport.md index d8bae848d751..1d472e4afa5e 100644 --- a/docs/learning/ui/components/Viewport.md +++ b/docs/learning/ui/components/Viewport.md @@ -71,4 +71,4 @@ const rulesetId = "Default"; ## API Reference -* [Viewport]($ui-components:Viewport) +- [Viewport]($ui-components:Viewport) diff --git a/docs/learning/ui/components/index.md b/docs/learning/ui/components/index.md index 65d5a7935005..e15fe9f02f46 100644 --- a/docs/learning/ui/components/index.md +++ b/docs/learning/ui/components/index.md @@ -4,14 +4,14 @@ The ui-components package contains React components that are data-oriented, such ## Topics -* [Common](./Common.md) - Common classes used across various UI components. -* [Color](./Color.md) - Classes and components for working with and picking a Color. -* [LineWeight](./LineWeight.md) - Classes and components for working with and picking a Line Weight. -* [OIDC](./OIDC.md) - Component for OIDC Sign-in. -* [PropertyEditors](./PropertyEditors.md) - Classes and components for working with Property Editors. -* [PropertyGrid](./PropertyGrid.md) - Classes and components for working with a PropertyGrid control. -* [Table](./Table.md) - Classes and components for working with a Table control. -* [Toolbar](./Toolbar.md) - Functions and components that provide a Toolbar. -* [Tree](./Tree.md) - Classes and components for working with a Tree control. -* [TypeConverters](./TypeConverters.md) - Various Type Converter classes for different types. -* [Viewport](./Viewport.md) - Classes and components for working with a Viewport. +- [Common](./Common.md) - Common classes used across various UI components. +- [Color](./Color.md) - Classes and components for working with and picking a Color. +- [LineWeight](./LineWeight.md) - Classes and components for working with and picking a Line Weight. +- [OIDC](./OIDC.md) - Component for OIDC Sign-in. +- [PropertyEditors](./PropertyEditors.md) - Classes and components for working with Property Editors. +- [PropertyGrid](./PropertyGrid.md) - Classes and components for working with a PropertyGrid control. +- [Table](./Table.md) - Classes and components for working with a Table control. +- [Toolbar](./Toolbar.md) - Functions and components that provide a Toolbar. +- [Tree](./Tree.md) - Classes and components for working with a Tree control. +- [TypeConverters](./TypeConverters.md) - Various Type Converter classes for different types. +- [Viewport](./Viewport.md) - Classes and components for working with a Viewport. diff --git a/docs/learning/ui/core/AutoSuggest.md b/docs/learning/ui/core/AutoSuggest.md index 9439ce1e2221..671a003ac13c 100644 --- a/docs/learning/ui/core/AutoSuggest.md +++ b/docs/learning/ui/core/AutoSuggest.md @@ -27,4 +27,4 @@ There are props for several handlers: ## API Reference -* [AutoSuggest]($ui-core:AutoSuggest) +- [AutoSuggest]($ui-core:AutoSuggest) diff --git a/docs/learning/ui/core/Base.md b/docs/learning/ui/core/Base.md index cad16c7da645..2aa7a7341093 100644 --- a/docs/learning/ui/core/Base.md +++ b/docs/learning/ui/core/Base.md @@ -49,4 +49,4 @@ It uses the `uicore-scrollview` CSS class. ## API Reference -* [Base]($ui-core:Base) +- [Base]($ui-core:Base) diff --git a/docs/learning/ui/core/Button.md b/docs/learning/ui/core/Button.md index ad5700de8f69..f6a20001d33b 100644 --- a/docs/learning/ui/core/Button.md +++ b/docs/learning/ui/core/Button.md @@ -95,4 +95,4 @@ The `onClick` event handler is run when the Button is clicked or touched. ## API Reference -* [Button]($ui-core:Button) +- [Button]($ui-core:Button) diff --git a/docs/learning/ui/core/CheckListBox.md b/docs/learning/ui/core/CheckListBox.md index 0cd4f851791d..96afdd7ba7c0 100644 --- a/docs/learning/ui/core/CheckListBox.md +++ b/docs/learning/ui/core/CheckListBox.md @@ -33,4 +33,4 @@ The CheckListBoxSeparator component is used for a separator item. ## API Reference -* [CheckListBox]($ui-core:CheckListBox) +- [CheckListBox]($ui-core:CheckListBox) diff --git a/docs/learning/ui/core/Checkbox.md b/docs/learning/ui/core/Checkbox.md index ea637840ce5e..834dbff14067 100644 --- a/docs/learning/ui/core/Checkbox.md +++ b/docs/learning/ui/core/Checkbox.md @@ -23,4 +23,4 @@ In addition to showing an 'on' or 'off' state, the `indeterminate` prop indicate ## API Reference -* [Checkbox]($ui-core:Checkbox) +- [Checkbox]($ui-core:Checkbox) diff --git a/docs/learning/ui/core/Common.md b/docs/learning/ui/core/Common.md index 0988db38edc4..c3c709de4450 100644 --- a/docs/learning/ui/core/Common.md +++ b/docs/learning/ui/core/Common.md @@ -4,19 +4,19 @@ The [Common]($ui-core:Common) category in the `@bentley/ui-core` package include ## React Higher-Order Components (HOCs) -* [withIsPressed]($ui-core) - adds pointer and mouse events -* [withOnOutsideClick]($ui-core) - adds outside click support -* [withTimeout]($ui-core) - adds timeout support +- [withIsPressed]($ui-core) - adds pointer and mouse events +- [withOnOutsideClick]($ui-core) - adds outside click support +- [withTimeout]($ui-core) - adds timeout support ## Common Enums -* [CheckBoxState]($ui-core) - State of a checkbox: On, Off or Partial -* [HorizontalAlignment]($ui-core) - Left, Center, Right or Justify -* [Orientation]($ui-core) - Horizontal or Vertical -* [SortDirection]($ui-core) - Direction for column sorting: Ascending, Descending or NoSort -* [TimeFormat]($ui-core) - Short or Long -* [VerticalAlignment]($ui-core) - Top, Middle or Bottom +- [CheckBoxState]($ui-core) - State of a checkbox: On, Off or Partial +- [HorizontalAlignment]($ui-core) - Left, Center, Right or Justify +- [Orientation]($ui-core) - Horizontal or Vertical +- [SortDirection]($ui-core) - Direction for column sorting: Ascending, Descending or NoSort +- [TimeFormat]($ui-core) - Short or Long +- [VerticalAlignment]($ui-core) - Top, Middle or Bottom ## API Reference -* [Common]($ui-core:Common) +- [Common]($ui-core:Common) diff --git a/docs/learning/ui/core/ContextMenu.md b/docs/learning/ui/core/ContextMenu.md index 63954169db69..e1a7ad9b8a60 100644 --- a/docs/learning/ui/core/ContextMenu.md +++ b/docs/learning/ui/core/ContextMenu.md @@ -103,4 +103,4 @@ export function SamplePopupContextMenu() { ## API Reference -* [ContextMenu]($ui-core:ContextMenu) +- [ContextMenu]($ui-core:ContextMenu) diff --git a/docs/learning/ui/core/Dialog.md b/docs/learning/ui/core/Dialog.md index b9a623409084..296f3cb83fb5 100644 --- a/docs/learning/ui/core/Dialog.md +++ b/docs/learning/ui/core/Dialog.md @@ -78,4 +78,4 @@ The `contentStyle` prop specifies CSS properties for the content area. ## API Reference -* [Dialog]($ui-core:Dialog) +- [Dialog]($ui-core:Dialog) diff --git a/docs/learning/ui/core/Expandable.md b/docs/learning/ui/core/Expandable.md index f9ad519efde7..e0716f8c2fd4 100644 --- a/docs/learning/ui/core/Expandable.md +++ b/docs/learning/ui/core/Expandable.md @@ -69,4 +69,4 @@ and that prop is used in this example. ## API Reference -* [Expandable]($ui-core:Expandable) +- [Expandable]($ui-core:Expandable) diff --git a/docs/learning/ui/core/Form.md b/docs/learning/ui/core/Form.md index 93a76210bd7b..5531478c30ef 100644 --- a/docs/learning/ui/core/Form.md +++ b/docs/learning/ui/core/Form.md @@ -90,4 +90,4 @@ export class ExampleForm extends React.Component { ## API Reference -* [Form]($ui-core:Form) +- [Form]($ui-core:Form) diff --git a/docs/learning/ui/core/Icon.md b/docs/learning/ui/core/Icon.md index 93b67f23d650..12d10d0e2092 100644 --- a/docs/learning/ui/core/Icon.md +++ b/docs/learning/ui/core/Icon.md @@ -115,4 +115,4 @@ In tsconfig.json, add a `types` entry for `@bentley/webpack-tools` in the `compi ## API Reference -* [Icon]($ui-core:Icon) +- [Icon]($ui-core:Icon) diff --git a/docs/learning/ui/core/Inputs.md b/docs/learning/ui/core/Inputs.md index dc84691b0cd5..baca3c6f96f0 100644 --- a/docs/learning/ui/core/Inputs.md +++ b/docs/learning/ui/core/Inputs.md @@ -87,4 +87,4 @@ The Input and Textarea components have a labeled version. ## API Reference -* [Inputs]($ui-core:Inputs) +- [Inputs]($ui-core:Inputs) diff --git a/docs/learning/ui/core/Loading.md b/docs/learning/ui/core/Loading.md index 157bc39f5cd6..943dc2e27e2d 100644 --- a/docs/learning/ui/core/Loading.md +++ b/docs/learning/ui/core/Loading.md @@ -2,12 +2,12 @@ The [Loading]($ui-core:Loading) category in the `@bentley/ui-core` package includes components for displaying determinate and indeterminate status indicators, such as spinners and progress bars. These include: -* [Spinner]($ui-core) - indeterminate spinner component that supports multiple sizes -* [LoadingBar]($ui-core) - determinate loading bar with optional percentage text -* [LoadingPrompt]($ui-core) - component to display during loading that optionally shows percentage, status text and a cancel button -* [LoadingSpinner]($ui-core) - loading spinner component that optionally shows a text message -* [ProgressBar]($ui-core) - horizontal progress bar that supports determinate and indeterminate modes -* [ProgressSpinner]($ui-core) - circular progress indicator that supports determinate and indeterminate modes +- [Spinner]($ui-core) - indeterminate spinner component that supports multiple sizes +- [LoadingBar]($ui-core) - determinate loading bar with optional percentage text +- [LoadingPrompt]($ui-core) - component to display during loading that optionally shows percentage, status text and a cancel button +- [LoadingSpinner]($ui-core) - loading spinner component that optionally shows a text message +- [ProgressBar]($ui-core) - horizontal progress bar that supports determinate and indeterminate modes +- [ProgressSpinner]($ui-core) - circular progress indicator that supports determinate and indeterminate modes ## Spinner Examples @@ -89,4 +89,4 @@ The following examples show the LoadingPrompt component with different props. ## API Reference -* [Loading]($ui-core:Loading) - An indeterminate spinner component +- [Loading]($ui-core:Loading) - An indeterminate spinner component diff --git a/docs/learning/ui/core/Notification.md b/docs/learning/ui/core/Notification.md index 27009ea11e00..9344b1afbadf 100644 --- a/docs/learning/ui/core/Notification.md +++ b/docs/learning/ui/core/Notification.md @@ -2,10 +2,10 @@ The [Notification]($ui-core:Notification) category in the `@bentley/ui-core` package includes components, interfaces and types for displaying messages and tooltips. These include: -* [MessageRenderer]($ui-core) - React component renders a string, `HTMLElement` or React node in a `div` or `span` -* [ReactMessage]($ui-core) - Interface that describes a React based message. The `reactNode` member is a `React.ReactNode` that represents the message. -* [MessageType]($ui-core) - Type that lists the valid types for a message: `string | HTMLElement | ReactMessage` +- [MessageRenderer]($ui-core) - React component renders a string, `HTMLElement` or React node in a `div` or `span` +- [ReactMessage]($ui-core) - Interface that describes a React based message. The `reactNode` member is a `React.ReactNode` that represents the message. +- [MessageType]($ui-core) - Type that lists the valid types for a message: `string | HTMLElement | ReactMessage` ## API Reference -* [Notification]($ui-core:Notification) +- [Notification]($ui-core:Notification) diff --git a/docs/learning/ui/core/Popup.md b/docs/learning/ui/core/Popup.md index 60d1d3235586..78569f59338d 100644 --- a/docs/learning/ui/core/Popup.md +++ b/docs/learning/ui/core/Popup.md @@ -71,4 +71,4 @@ Several props control whether the popup closes for certain events (all default t ## API Reference -* [Popup]($ui-core:Popup) +- [Popup]($ui-core:Popup) diff --git a/docs/learning/ui/core/RadialMenu.md b/docs/learning/ui/core/RadialMenu.md index ddee0a760d3e..cfd29c3ba4fd 100644 --- a/docs/learning/ui/core/RadialMenu.md +++ b/docs/learning/ui/core/RadialMenu.md @@ -101,4 +101,4 @@ export class TestRadialMenu extends React.Component` element -* [IconHelper]($ui-core) - Icon Helper Class used to store the data needed to generate an `` for use in any control that shows an icon -* [NoChildrenProps]($ui-core) - Props used by components that do not expect children to be passed in -* [OmitChildrenProp]($ui-core) - Omit children property -* [PointProps]($ui-core) - Describes 2d points -* [RectangleProps]($ui-core) - Describes 2d bounds -* [SizeProps]($ui-core) - Describes 2d dimensions -* [Timer]($ui-core) - Notifies handler after a set interval -* [UiCore]($ui-core) - Manages the I18N service for the ui-core package -* [useDisposable]($ui-core) - Custom hook which creates a disposable object and manages its disposal on unmount or factory method change -* [useEffectSkipFirst]($ui-core) - Custom hook which works like useEffect hook, but does not invoke callback when effect is triggered for the first time -* [useOptionalDisposable]($ui-core) - Custom hook which calls the factory method to create a disposable object which might as well be undefined. If the result was a disposable object, the hook takes care of disposing it when necessary. +- [ClassNameProps]($ui-core) - Props used by components that expect a CSS class name to be passed in +- [CommonProps]($ui-core) - Common props used by components; includes `style` for CSS properties +- [CommonDivProps]($ui-core) - Common properties using a `
` element +- [IconHelper]($ui-core) - Icon Helper Class used to store the data needed to generate an `` for use in any control that shows an icon +- [NoChildrenProps]($ui-core) - Props used by components that do not expect children to be passed in +- [OmitChildrenProp]($ui-core) - Omit children property +- [PointProps]($ui-core) - Describes 2d points +- [RectangleProps]($ui-core) - Describes 2d bounds +- [SizeProps]($ui-core) - Describes 2d dimensions +- [Timer]($ui-core) - Notifies handler after a set interval +- [UiCore]($ui-core) - Manages the I18N service for the ui-core package +- [useDisposable]($ui-core) - Custom hook which creates a disposable object and manages its disposal on unmount or factory method change +- [useEffectSkipFirst]($ui-core) - Custom hook which works like useEffect hook, but does not invoke callback when effect is triggered for the first time +- [useOptionalDisposable]($ui-core) - Custom hook which calls the factory method to create a disposable object which might as well be undefined. If the result was a disposable object, the hook takes care of disposing it when necessary. ## API Reference -* [Utilities]($ui-core:Utilities) +- [Utilities]($ui-core:Utilities) diff --git a/docs/learning/ui/core/index.md b/docs/learning/ui/core/index.md index 49371fcdf128..c81c17e505bc 100644 --- a/docs/learning/ui/core/index.md +++ b/docs/learning/ui/core/index.md @@ -5,34 +5,34 @@ It also contains various input components, such as Input, Radio, Checkbox, Numbe ## Topics -* [AutoSuggest](./AutoSuggest.md) - Component for input with an auto-suggestion dropdown. -* [Base](./Base.md) - Low-level classes and components for building a user interface. -* [Button](./Button.md) - Components for working with various Buttons. -* [Checkbox](./Checkbox.md) - Component is a wrapper for the `` HTML element. -* [CheckListBox](./CheckListBox.md) - Components for working with a Check listbox. -* [Common](./Common.md) - Common classes used across various UI components. -* [ContextMenu](./ContextMenu.md) - Components and classes for working with a Context Menu. -* [Dialog](./Dialog.md) - Components for working with a Dialog or MessageBox. -* [Expandable](./Expandable.md) - Components for working with a ExpandableBlock or ExpandableList. -* [Form](./Form.md) - Components used to create a Form using supplied properties to specify fields. -* [Icon](./Icon.md) - Components that render icons when given an icon name or SVG source or path. -* [Inputs](./Inputs.md) - Components for working with input controls, such as Input, IconInput, NumberInput and Textarea. -* [Loading](./Loading.md) - Components for working with Loading spinners and progress bars. -* [Notification](./Notification.md) - Components for working with with messages and tooltips. -* [Popup](./Popup.md) - Components for working with a Popup. -* [RadialMenu](./RadialMenu.md) - Components for working with a RadialMenu. -* [Radio](./Radio.md) - Component is a wrapper for the `` HTML element. -* [SearchBox](./SearchBox.md) - Components for working with a SearchBox. -* [Select](./Select.md) - Components that display a value and a drop-down showing possible values the user can choose. -* [Slider](./Slider.md) - Component for displaying a range slider. -* [SplitButton](./SplitButton.md) - Component that displays a button with two parts: +- [AutoSuggest](./AutoSuggest.md) - Component for input with an auto-suggestion dropdown. +- [Base](./Base.md) - Low-level classes and components for building a user interface. +- [Button](./Button.md) - Components for working with various Buttons. +- [Checkbox](./Checkbox.md) - Component is a wrapper for the `` HTML element. +- [CheckListBox](./CheckListBox.md) - Components for working with a Check listbox. +- [Common](./Common.md) - Common classes used across various UI components. +- [ContextMenu](./ContextMenu.md) - Components and classes for working with a Context Menu. +- [Dialog](./Dialog.md) - Components for working with a Dialog or MessageBox. +- [Expandable](./Expandable.md) - Components for working with a ExpandableBlock or ExpandableList. +- [Form](./Form.md) - Components used to create a Form using supplied properties to specify fields. +- [Icon](./Icon.md) - Components that render icons when given an icon name or SVG source or path. +- [Inputs](./Inputs.md) - Components for working with input controls, such as Input, IconInput, NumberInput and Textarea. +- [Loading](./Loading.md) - Components for working with Loading spinners and progress bars. +- [Notification](./Notification.md) - Components for working with with messages and tooltips. +- [Popup](./Popup.md) - Components for working with a Popup. +- [RadialMenu](./RadialMenu.md) - Components for working with a RadialMenu. +- [Radio](./Radio.md) - Component is a wrapper for the `` HTML element. +- [SearchBox](./SearchBox.md) - Components for working with a SearchBox. +- [Select](./Select.md) - Components that display a value and a drop-down showing possible values the user can choose. +- [Slider](./Slider.md) - Component for displaying a range slider. +- [SplitButton](./SplitButton.md) - Component that displays a button with two parts: an action button on the left and an arrow button on the right that opens a context menu. -* [Style](./Style.md) - Sass variables and mixins for breakpoints, colors, color themes, opacity, sizing, spacing and typography. -* [Tabs](./Tabs.md) - Components for working with horizontal or vertical tabs. -* [Text](./Text.md) - Components for working with styled text and different text sizes. -* [Tiles](./Tiles.md) - Components for a container rendering elements that can be grouped together. -* [Toggle](./Toggle.md) - Component for working with a Toggle switch. -* [Tooltip](./Tooltip.md) - Component displays tooltip popup for a specified target element. -* [Tree](./Tree.md) - Presentation React components for working with a Tree. -* [UiSettings](./UiSettings.md) - Interfaces and classes for working with persistent UI settings. -* [Utilities](./Utilities.md) - Various utility classes, functions and React hooks for working with a UI. +- [Style](./Style.md) - Sass variables and mixins for breakpoints, colors, color themes, opacity, sizing, spacing and typography. +- [Tabs](./Tabs.md) - Components for working with horizontal or vertical tabs. +- [Text](./Text.md) - Components for working with styled text and different text sizes. +- [Tiles](./Tiles.md) - Components for a container rendering elements that can be grouped together. +- [Toggle](./Toggle.md) - Component for working with a Toggle switch. +- [Tooltip](./Tooltip.md) - Component displays tooltip popup for a specified target element. +- [Tree](./Tree.md) - Presentation React components for working with a Tree. +- [UiSettings](./UiSettings.md) - Interfaces and classes for working with persistent UI settings. +- [Utilities](./Utilities.md) - Various utility classes, functions and React hooks for working with a UI. diff --git a/docs/learning/ui/framework/Backstage.md b/docs/learning/ui/framework/Backstage.md index d3b1f57d7ca4..0219b7000369 100644 --- a/docs/learning/ui/framework/Backstage.md +++ b/docs/learning/ui/framework/Backstage.md @@ -31,5 +31,5 @@ See additional info in [Backstage](../../../learning/ui/abstract/Backstage.md). Below is an example of defining the ConfigurableUiContent and specifying the backstage, using the component from the above example. ```tsx - } /> +} /> ``` diff --git a/docs/learning/ui/framework/ContentViews.md b/docs/learning/ui/framework/ContentViews.md index 08a7c9830266..d43102454c35 100644 --- a/docs/learning/ui/framework/ContentViews.md +++ b/docs/learning/ui/framework/ContentViews.md @@ -202,4 +202,4 @@ const fourQuadrants: ContentLayoutProps = { ## API Reference -* [Content Views]($ui-framework:ContentView) +- [Content Views]($ui-framework:ContentView) diff --git a/docs/learning/ui/framework/Dialogs.md b/docs/learning/ui/framework/Dialogs.md index 633f195aa641..eaa102636f08 100644 --- a/docs/learning/ui/framework/Dialogs.md +++ b/docs/learning/ui/framework/Dialogs.md @@ -205,4 +205,4 @@ The `ModelessDialogManager.closeDialog` function is called to close a modeless d ## API Reference -* [Dialog]($ui-framework:Dialog) +- [Dialog]($ui-framework:Dialog) diff --git a/docs/learning/ui/framework/Frontstages.md b/docs/learning/ui/framework/Frontstages.md index 9a61529de65b..0dc08e42e955 100644 --- a/docs/learning/ui/framework/Frontstages.md +++ b/docs/learning/ui/framework/Frontstages.md @@ -120,12 +120,12 @@ FrontstageManager.setActiveFrontstageDef(frontstageProvider.frontstageDef).then( ## Related Learning Topics -* [Content Views and Layouts](./ContentViews.md) -* [Widgets](./Widgets.md) -* [Status Bar and Fields](./StatusBar.md) -* [Tool Settings](./ToolSettings.md) -* [Stage Panels](./StagePanels.md) +- [Content Views and Layouts](./ContentViews.md) +- [Widgets](./Widgets.md) +- [Status Bar and Fields](./StatusBar.md) +- [Tool Settings](./ToolSettings.md) +- [Stage Panels](./StagePanels.md) ## API Reference -* [Zone]($ui-framework:Zone) +- [Zone]($ui-framework:Zone) diff --git a/docs/learning/ui/framework/ModalFrontstage.md b/docs/learning/ui/framework/ModalFrontstage.md index 75c9c583f9c6..0700bdc456b3 100644 --- a/docs/learning/ui/framework/ModalFrontstage.md +++ b/docs/learning/ui/framework/ModalFrontstage.md @@ -37,15 +37,14 @@ class SampleModalPage extends React.Component { The following code instantiates a modal frontstage and calls `FrontstageManager.openModalFrontstage` to open the modal frontstage. -```TS - const modalFrontstage = new SampleModalFrontstage(); - FrontstageManager.openModalFrontstage(modalFrontstage); - +```ts +const modalFrontstage = new SampleModalFrontstage(); +FrontstageManager.openModalFrontstage(modalFrontstage); ``` ## API Reference -* [ModalFrontstage]($ui-framework) -* [ModalFrontstageInfo]($ui-framework) -* [FrontstageManager]($ui-framework) -* [Frontstage]($ui-framework:Frontstage) +- [ModalFrontstage]($ui-framework) +- [ModalFrontstageInfo]($ui-framework) +- [FrontstageManager]($ui-framework) +- [Frontstage]($ui-framework:Frontstage) diff --git a/docs/learning/ui/framework/Notifications.md b/docs/learning/ui/framework/Notifications.md index 93a7c6c6f884..131604ede745 100644 --- a/docs/learning/ui/framework/Notifications.md +++ b/docs/learning/ui/framework/Notifications.md @@ -57,4 +57,4 @@ private _handleLink = () => { ## API Reference -* [Notification]($ui-framework:Notification) +- [Notification]($ui-framework:Notification) diff --git a/docs/learning/ui/framework/StatusBar.md b/docs/learning/ui/framework/StatusBar.md index 968cf541fe82..e6d3a7c912ad 100644 --- a/docs/learning/ui/framework/StatusBar.md +++ b/docs/learning/ui/framework/StatusBar.md @@ -52,4 +52,4 @@ ConfigurableUiManager.registerControl("AppStatusBar", AppStatusBarWidgetControl) ## API Reference -* [StatusBar]($ui-framework:StatusBar) +- [StatusBar]($ui-framework:StatusBar) diff --git a/docs/learning/ui/framework/TasksWorkflows.md b/docs/learning/ui/framework/TasksWorkflows.md index aff289c8c8ff..54b0754ea8db 100644 --- a/docs/learning/ui/framework/TasksWorkflows.md +++ b/docs/learning/ui/framework/TasksWorkflows.md @@ -10,67 +10,67 @@ The following shows how to define a couple of Tasks and load them into the TaskM Each task references a Frontstage by an Id that has been registered with the FrontstageManager. When the Task is launched or activated, the Frontstage is also activated. -```JS - const taskPropsList: TaskPropsList = { - tasks: [ - { - id: "Task1", - primaryStageId: "Test1", - iconSpec: "icon-placeholder", - labelKey: "SampleApp:backstage.task1", - }, - { - id: "Task2", - primaryStageId: "Test2", - iconSpec: "icon-placeholder", - labelKey: "SampleApp:backstage.task2", - }, - ], - }; - - ConfigurableUiManager.loadTasks(taskPropsList); +```ts +const taskPropsList: TaskPropsList = { + tasks: [ + { + id: "Task1", + primaryStageId: "Test1", + iconSpec: "icon-placeholder", + labelKey: "SampleApp:backstage.task1", + }, + { + id: "Task2", + primaryStageId: "Test2", + iconSpec: "icon-placeholder", + labelKey: "SampleApp:backstage.task2", + }, + ], +}; + +ConfigurableUiManager.loadTasks(taskPropsList); ``` ## Defining a Workflow The following shows how to define a Workflow and load it into the WorkflowManager. It references tasks `Task1` and `Task2` defined above. -```JS - const workflowProps: WorkflowProps = { - id: "ExampleWorkflow", - iconSpec: "icon-placeholder", - labelKey: "SampleApp:Test.my-label", - defaultTaskId: "task1", - tasks: ["Task1", "Task2"], - }; +```ts +const workflowProps: WorkflowProps = { + id: "ExampleWorkflow", + iconSpec: "icon-placeholder", + labelKey: "SampleApp:Test.my-label", + defaultTaskId: "task1", + tasks: ["Task1", "Task2"], +}; - ConfigurableUiManager.loadWorkflow(workflowProps); +ConfigurableUiManager.loadWorkflow(workflowProps); ``` ## Launching a Task from the Backstage A Task can be launched from the Backstage using the **TaskLaunchBackstageItem** Backstage item. -```TSX - +```tsx + ``` ## Setting a Workflow and Task active programmatically A Task can be set active programmatically using `WorkflowManager.setActiveWorkflowAndTask`. -```TS - const workflow = WorkflowManager.findWorkflow("ExampleWorkflow"); - if (workflow) { - const task = workflow.getTask("Task1"); - if (task) { - await WorkflowManager.setActiveWorkflowAndTask(workflow, task); - } - } +```ts +const workflow = WorkflowManager.findWorkflow("ExampleWorkflow"); +if (workflow) { + const task = workflow.getTask("Task1"); + if (task) { + await WorkflowManager.setActiveWorkflowAndTask(workflow, task); + } +} ``` ## API Reference -* [Workflows and Tasks]($ui-framework:WorkflowTask) +- [Workflows and Tasks]($ui-framework:WorkflowTask) diff --git a/docs/learning/ui/framework/ToolSettings.md b/docs/learning/ui/framework/ToolSettings.md index 6dc0edfd562b..7e3001b5ec82 100644 --- a/docs/learning/ui/framework/ToolSettings.md +++ b/docs/learning/ui/framework/ToolSettings.md @@ -19,15 +19,15 @@ If the 'Active' Tool updates a property that is being displayed by a type editor The following classes defined within the ui-abstract package are used by the Default Tool Settings Provider. -* [DialogItem]($ui-abstract) -* [PropertyRecord]($ui-abstract) -* [PropertyDescription]($ui-abstract) -* [DialogItemValue]($ui-abstract) -* [DialogPropertySyncItem]($ui-abstract) -* [EditorPosition]($ui-abstract) -* [PropertyEditorParamTypes]($ui-abstract) -* [PropertyValue]($ui-abstract) +- [DialogItem]($ui-abstract) +- [PropertyRecord]($ui-abstract) +- [PropertyDescription]($ui-abstract) +- [DialogItemValue]($ui-abstract) +- [DialogPropertySyncItem]($ui-abstract) +- [EditorPosition]($ui-abstract) +- [PropertyEditorParamTypes]($ui-abstract) +- [PropertyValue]($ui-abstract) ## API Reference -* [ToolSettings]($ui-framework:ToolSettings) +- [ToolSettings]($ui-framework:ToolSettings) diff --git a/docs/learning/ui/framework/Widgets.md b/docs/learning/ui/framework/Widgets.md index f5d94cd1b1fc..78f456f98c0d 100644 --- a/docs/learning/ui/framework/Widgets.md +++ b/docs/learning/ui/framework/Widgets.md @@ -81,14 +81,14 @@ A [WidgetDef]($ui-framework) object is created for each Widget component in the The following example demonstrates how to open a widget programmatically. The example assumes an `id` prop of "VerticalPropertyGrid" has been provided on the Widget component. -```TS - const activeFrontstageDef = FrontstageManager.activeFrontstageDef; - if (activeFrontstageDef) { - const widgetDef = activeFrontstageDef.findWidgetDef("VerticalPropertyGrid"); - if (widgetDef) { - widgetDef.setWidgetState(WidgetState.Open); - } - } +```ts +const activeFrontstageDef = FrontstageManager.activeFrontstageDef; +if (activeFrontstageDef) { + const widgetDef = activeFrontstageDef.findWidgetDef("VerticalPropertyGrid"); + if (widgetDef) { + widgetDef.setWidgetState(WidgetState.Open); + } +} ``` ## Tool Widget @@ -154,4 +154,4 @@ There is an extensible Navigation Widget named [BasicNavigationWidget]($ui-frame ## API Reference -* [Widget]($ui-framework:Widget) +- [Widget]($ui-framework:Widget) diff --git a/docs/learning/ui/framework/index.md b/docs/learning/ui/framework/index.md index 22e50b67ced9..40901b377524 100644 --- a/docs/learning/ui/framework/index.md +++ b/docs/learning/ui/framework/index.md @@ -6,23 +6,23 @@ The ui-framework package contains application fragments for Login, Project, iMod There are numerous React components and TypeScript classes in the `@bentley/ui-framework` package for configuring the application user interface. The following constructs are defined using these components and classes: -* [Frontstages and Zones](./Frontstages.md) - * [Nested Frontstages](./NestedFrontstage.md) - * [Modal FrontStage](./ModalFrontstage.md) -* [Content Views and Layouts](./ContentViews.md) -* [Widgets](./Widgets.md) -* [Status Bar and Fields](./StatusBar.md) -* [Navigation Aids]($ui-framework:NavigationAids) - A user interface control that moves the user's perspective around within a specific Content View. -* [Tool Settings](./ToolSettings.md) -* [Stage Panels](./StagePanels.md) -* [Backstage](./Backstage.md) -* [Notifications and Messages](./Notifications.md) -* [Dialogs](./Dialogs.md) -* [Workflows and Tasks](./TasksWorkflows.md) -* [KeyboardShortcut]($ui-framework:KeyboardShortcut) - A keystroke or combination of keystrokes used to launch a command or tool. +- [Frontstages and Zones](./Frontstages.md) + - [Nested Frontstages](./NestedFrontstage.md) + - [Modal FrontStage](./ModalFrontstage.md) +- [Content Views and Layouts](./ContentViews.md) +- [Widgets](./Widgets.md) +- [Status Bar and Fields](./StatusBar.md) +- [Navigation Aids]($ui-framework:NavigationAids) - A user interface control that moves the user's perspective around within a specific Content View. +- [Tool Settings](./ToolSettings.md) +- [Stage Panels](./StagePanels.md) +- [Backstage](./Backstage.md) +- [Notifications and Messages](./Notifications.md) +- [Dialogs](./Dialogs.md) +- [Workflows and Tasks](./TasksWorkflows.md) +- [KeyboardShortcut]($ui-framework:KeyboardShortcut) - A keystroke or combination of keystrokes used to launch a command or tool. ## Other Topics -* [SyncUi](./SyncUi.md) -* [Hooks](./Hooks.md) -* [State](./State.md) +- [SyncUi](./SyncUi.md) +- [Hooks](./Hooks.md) +- [State](./State.md) diff --git a/docs/learning/ui/index.md b/docs/learning/ui/index.md index 1eda7036e315..592cec7a6974 100644 --- a/docs/learning/ui/index.md +++ b/docs/learning/ui/index.md @@ -24,10 +24,10 @@ The iModel.js UI library is divided into these NPM packages in the `@bentley` sc See also: -* [UI 2.0](./FrontstageUi2.md). -* [Creating an IModelApp that supports Extensible UI](./HostAppUI.md). -* [Augmenting the UI of an IModelApp](./AugmentingUI.md). -* [Glossary of terms used in iModel.js UI](./UIGlossary) -* [React](https://reactjs.org/) -* [Redux](https://redux.js.org/) -* [React and Typescript](/~https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/) +- [UI 2.0](./FrontstageUi2.md). +- [Creating an IModelApp that supports Extensible UI](./HostAppUI.md). +- [Augmenting the UI of an IModelApp](./AugmentingUI.md). +- [Glossary of terms used in iModel.js UI](./UIGlossary) +- [React](https://reactjs.org/) +- [Redux](https://redux.js.org/) +- [React and Typescript](/~https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/) diff --git a/docs/learning/ui/ninezone/index.md b/docs/learning/ui/ninezone/index.md index fe29c48daeb1..e6d18d93f4ac 100644 --- a/docs/learning/ui/ninezone/index.md +++ b/docs/learning/ui/ninezone/index.md @@ -6,10 +6,10 @@ The 9-Zone UI Pattern allows applications to work across a range of devices and ## Core Principles -* Content is full screen -* UI appears on a layer above the content -* The UI layer is divided into zones. Each zone has a specific purpose -* Widgets not dialogs +- Content is full screen +- UI appears on a layer above the content +- The UI layer is divided into zones. Each zone has a specific purpose +- Widgets not dialogs ## Zones