4.9.0 Change Notes
Table of contents:
Quantity
- The
minWidth
property on FormatProps now works as documented. - The
spacer
property on FormatProps now indicates the space used between composite components, it defaults to a single space, and there is no longer a ':' prepended. If a ':' spacer is desired,spacer
has to be set accordingly. This is to streamline the behavior with the documentation and native APIs. - Added support for bearing and azimuth format types (e.g. bearing
N45°30'10"E
). A new phenomenon "Direction" for these will be added to our units library soon, but they work just as well with the angle phenomenon for now. Persistence values for both bearing and azimuth are to be provided counter-clockwise from an east-base (inspired by PowerPlatform).
Electron 32 support
In addition to already supported Electron versions, iTwin.js now supports Electron 32.
Geometry
Approximating an elliptical arc with a circular arc chain
Arc3d.constructCircularArcChainApproximation returns a CurveChain of circular arcs that approximates the elliptical instance arc. Each arc in the chain starts and ends on the ellipse. The ellipse major/minor axis points and tangents are also interpolated, as well as those at the elliptical arc start/end, and the arcs are arranged to preserve ellipse symmetry. Various settings in the optional EllipticalArcApproximationOptions input object control the approximation accuracy. The default method is EllipticalArcSampleMethod.AdaptiveSubdivision, which is controlled by a maximum error distance, options.maxError
. Other values of options.sampleMethod
interpolate the ellipse in other ways, controlled by the number of points interpolated in a given quadrant, options.numSamplesInQuadrant
. For a fixed number of samples, the default method usually yields the most accurate approximation.
Pictured below in order of decreasing error are some example approximations in blue, with ellipses in black, sample sites circled, and maximum error segment in red.
Approximation using options.sampleMethod = EllipticalArcSampleMethod.UniformCurvature
and options.numSamplesInQuadrant = 5
, yielding error 0.18:
Approximation using options.sampleMethod = EllipticalArcSampleMethod.UniformParameter
and options.numSamplesInQuadrant = 5
, yielding error 0.12:
Approximation using options.sampleMethod = EllipticalArcSampleMethod.NonUniformCurvature
, options.remapFunction = (x) => x*x
, and options.numSamplesInQuadrant = 5
, yielding error 0.05:
Approximation using options.sampleMethod = EllipticalArcSampleMethod.AdaptiveSubdivision
and options.maxError === 0.05
, yielding error 0.03:
Triangulating points
PolyfaceBuilder.pointsToTriangulatedPolyface, which creates a Polyface from an xy-triangulation of input points, now uses the StrokeOptions input setting options.chordTol
to control the maximum xy-distance for equating points. This method preserves the highest z-coordinate among points equated in this manner. The default for this setting is Geometry.smallMetricDistance, however for typical DTM datasets, a larger tolerance can be used (e.g., 1-2mm) to eliminate extraneous "skirt" points that lie underneath the terrain boundary.
Pictured below are triangulations of a DTM dataset with skirt points. At top is the result using default tolerance. Due to the skirt points having xy-distance greater than the default tolerance from actual terrain sites, they are included in the triangulation, resulting in undesirable near-vertical facets. At bottom is the result using options.chordTol = 0.002
, which is sufficiently large to remove these artifacts:
Display
Dynamic clip masks
PlanarClipMaskSettings permit you to mask out (render partially or fully transparent) portions of the background map based on its intersection with other geometry in the scene. Previously, only GeometricModels and reality models could contribute to the mask. Now, geometry added to the scene dynamically via TiledGraphicsProviders can also contribute to the mask. As with reality models, TiledGraphicsProviders' geometry only contributes to the mask in PlanarClipMaskMode.Priority. You can optionally configure a custom mask priority using TileTreeReference.planarClipMaskPriority or the newly-added RenderGraphicTileTreeArgs.planarClipMaskPriority. Here's an example of the latter:
/** Mask out portions of the viewport's background map where it intersects a set of spherical regions. */
export function maskBackgroundMap(viewport: Viewport, regions: Iterable<Sphere>): void {
// Use a GraphicBuilder to define the mask geometry.
const builder = IModelApp.renderSystem.createGraphic({
type: GraphicType.Scene,
computeChordTolerance: () => 0.1,
});
for (const region of regions) {
builder.addSolidPrimitive(region);
}
// Create a tile tree reference to provide the graphics defining the mask.
const tileTreeReference = TileTreeReference.createFromRenderGraphic({
modelId: viewport.iModel.transientIds.getNext(),
graphic: builder.finish(),
iModel: viewport.iModel,
// Set the priority higher than the default of PlanarClipMaskPriority.DesignModel.
planarClipMaskPriority: 4100,
});
// Add the tile tree reference to the viewport as a TiledGraphicsProvider.
viewport.addTiledGraphicsProvider({
forEachTileTreeRef: (_vp, func) => func(tileTreeReference),
});
// Enable masking by priority, with priority set just below that of our TileTreeReference so that the map will only be masked by
// our geometry, not by any design models that may be present in the scene.
viewport.changeBackgroundMapProps({
planarClipMask: {
mode: PlanarClipMaskMode.Priority,
priority: 4000,
},
});
viewport.invalidateRenderPlan();
}
Presentation
Custom content parser for creating element properties
The getElementProperties
function on the backend PresentationManager has two overloads:
- For single element case, taking
elementId
and returning an data structure in the form ofElementProperties
. - For multiple elements case, taking an optional list of
elementClasses
and returning properties of those elements. While the default form of the returned data structure isElementProperties
, just like in single element case, the overload allows for a custom parser function to be provided. In that case the parser function determines the form of the returned data structure.
In this release the overload for single element case was enhanced to also take an optional custom content parser to make the two overloads consistent in this regard. In addition, the getElementProperties
method on the frontend PresentationManager has also been enhanced with this new feature to be consistent with the similar method on the backend.
ECExpression to get related instance label
A new GetRelatedDisplayLabel
function symbol has been added to ECInstance ECExpressions context, allowing retrieval of related instance label. The function takes 3 arguments: full name of a relationship, its direction and related class name. Example usage in calculated properties specification:
{
"label": "My Calculated Property",
"value": "this.GetRelatedDisplayLabel(\"BisCore:ModelContainsElements\", \"Backward\", \"BisCore:Model\")"
}
The above specification, when applied to BisCore:Element
content, will include a "My Calculated Property" property whose value equals to the label of the model that contains the element.
Referencing schema-based categories in property overrides and calculated properties
In some cases there may be a need to place specific property in the same group as other specific properties. One way to do that is by creating a property category specification and assigning it to all such properties. However, what if want to place a property next to other properties, which are categorized through a schema-based category? This is now possible through the new SchemaCategory
category identifier. For example, to place a calculated property next to an ECProperty that uses MySchema:MyCategory
category:
{
"label": "My calculated property",
"categoryId": {
"type": "SchemaCategory",
"categoryName": "MySchema:MyCategory"
}
}
Calculated properties specification enhancements
A number of enhancements have been made to calculated properties specification:
The
value
is now optional. If not provided, the value of resulting property will beundefined
.A new optional
type
attribute has been added. The attribute allows specifying value type of the calculated property, allowing the property to have other types thanstring
. The default value isstring
.A new optional
extendedData
attribute has been added. The attribute allows associating resulting calculated properties field with some extra information, which may be especially useful for dynamically created calculated properties.
API deprecations
@itwin/appui-abstract
LayoutFragmentProps
,ContentLayoutProps
,LayoutSplitPropsBase
,LayoutHorizontalSplitProps
,LayoutVerticalSplitProps
, andStandardContentLayouts
have been deprecated. Use the same APIs from@itwin/appui-react
instead.BackendItemsManager
is internal and should never have been consumed. It has been deprecated and will be removed in 5.0.0. UseUiFramework.backstage
from@itwin/appui-react
instead.
Last Updated: 04 October, 2024