UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

332 lines • 16.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Symbology */ import { compareArrays, compareBooleans, compareNumbers, compareStrings, CompressedId64Set, OrderedId64Iterable } from "@itwin/core-bentley"; import { LinePixels } from "./LinePixels"; import { RgbColor } from "./RgbColor"; /** The style settings used by either a minor or major contour. * @see [[Contour.majorStyle]] * @see [[Contour.minorStyle]] * @public */ export class ContourStyle { /** The color in which to draw the contour lines. Default: black. */ color; /** The width in screen pixels of the contour lines. * Useful values range between 1 and 8.5, in increments of 0.5. Other values will be rounded to meet these criteria. * Default: 1.0. */ pixelWidth; /** The pattern for a major or minor contour line. Defaults to [[LinePixels.Solid]]. */ pattern; /** Returns true if `this` and `other` are logically equivalent. */ equals(other) { if (!this.color.equals(other.color) || this.pixelWidth !== other.pixelWidth || this.pattern !== other.pattern) { return false; } return true; } /** Perform ordered comparison between this and another contour style. */ compare(other) { return ContourStyle.compare(this, other); } /** Performs ordered comparison of two contour styles. * @param lhs First contour style to compare * @param rhs Second contour style to compare * @returns 0 if lhs is equivalent to rhs, a negative number if lhs compares less than rhs, or a positive number if lhs compares greater than rhs. * @public */ static compare(lhs, rhs) { let diff = 0; if ((diff = lhs.color.compareTo(rhs.color)) !== 0) return diff; if ((diff = compareNumbers(lhs.pixelWidth, rhs.pixelWidth)) !== 0) return diff; if ((diff = compareNumbers(lhs.pattern, rhs.pattern)) !== 0) return diff; return diff; } constructor(props) { this.color = props?.color ?? RgbColor.fromJSON({ r: 0, g: 0, b: 0 }); this.pixelWidth = props?.pixelWidth ?? 1; this.pattern = props?.pattern ?? LinePixels.Solid; } static fromJSON(props) { if (!props) return new ContourStyle(); return new this({ color: props?.color ? RgbColor.fromJSON(props.color) : undefined, pixelWidth: props?.pixelWidth, pattern: props?.pattern, }); } toJSON() { const props = {}; if (!this.color.equals(RgbColor.fromJSON({ r: 0, g: 0, b: 0 }))) props.color = this.color.toJSON(); if (1 !== this.pixelWidth) props.pixelWidth = this.pixelWidth; if (0 !== this.pattern) props.pattern = this.pattern; return props; } /** Create a new ContourStyle. Any properties not specified by `props` will be initialized to their default values. */ static create(props) { return props ? new this(props) : new ContourStyle(); } /** Create a copy of this ContourStyle, identical except for any properties specified by `changedProps`. * Any properties of `changedProps` explicitly set to `undefined` will be reset to their default values. */ clone(changedProps) { if (!changedProps) return this; return ContourStyle.create({ ...this, ...changedProps }); } } /** Describes how to generate and style contour lines for geometry within a single [[ContourGroup]]. * Contours provide a way to visualize elevation within a 3d scene by drawing lines at fixed intervals along the z-axis. * There are actually 2 kinds of contour lines: major and minor. Each kind can be styled independently. * A contour line is generated every [[minorInterval]] meters. Every `nth` line will be a *major* contour, where `n` = [[majorIntervalCount]]; the intervening lines will * all be *minor* contours. * For example, with a [[majorIntervalCount]] of `1`, every contour will be major; of `2`, every other contour will be major; and of `3`, there will be two minor contours in between * each major contour. * * @public */ export class Contour { /** Settings that describe how a major contour is styled. Defaults to an instantation of [[ContourStyle]] using `pixelWidth` of 2 and default values for the other properties. */ majorStyle; /** Settings that describe how a minor contour is styled. Defaults to an instantation of [[ContourStyle]] using default values for the properties. */ minorStyle; /** The interval for the minor contour occurrence in meters; these can be specified as fractional. Defaults to 1. If a value <= 0 is specified, this will be treated as 1 meter. */ minorInterval; /** The count of minor contour intervals that define a major interval (integer > 0). A value of 1 means no minor contours will be shown, only major contours. Defaults to 5. If a value < 1 is specified, this will be treated as 1. If a non-integer value is specified, it will be treated as if it were rounded to the nearest integer. */ majorIntervalCount; /** If true, show underlying geometry along with the associated contours. If false, only show the contours, not the underlying geometry. Defaults to true. */ showGeometry; static defaults = new Contour({}); /** Returns true if `this` is logically equivalent to `other`. */ equals(other) { return this.compare(other) === 0; } /** Performs ordered comparison between this and another contour. */ compare(other) { return Contour.compare(this, other); } /** Performs ordered comparison of two contours. * @param lhs First contour to compare * @param rhs Second contour to compare * @returns 0 if lhs is equivalent to rhs, a negative number if lhs compares less than rhs, or a positive number if lhs compares greater than rhs. */ static compare(lhs, rhs) { return ContourStyle.compare(lhs.majorStyle, rhs.majorStyle) || ContourStyle.compare(lhs.minorStyle, rhs.minorStyle) || compareNumbers(lhs.minorInterval, rhs.minorInterval) || compareNumbers(lhs.majorIntervalCount, rhs.majorIntervalCount) || compareBooleans(lhs.showGeometry, rhs.showGeometry); } constructor(props) { this.majorStyle = props?.majorStyle ?? ContourStyle.fromJSON({ pixelWidth: 2 }); this.minorStyle = props?.minorStyle ?? ContourStyle.fromJSON(); this.minorInterval = props?.minorInterval ?? 1; this.majorIntervalCount = props?.majorIntervalCount ?? 5; this.showGeometry = props?.showGeometry ?? true; } static fromJSON(props) { if (!props) return new Contour(); return new this({ majorStyle: props?.majorStyle ? ContourStyle.fromJSON(props.majorStyle) : undefined, minorStyle: props?.minorStyle ? ContourStyle.fromJSON(props.minorStyle) : undefined, minorInterval: props?.minorInterval, majorIntervalCount: props?.majorIntervalCount, showGeometry: props?.showGeometry, }); } toJSON() { const props = {}; if (!this.majorStyle.equals(ContourStyle.fromJSON({ pixelWidth: 2 }))) props.majorStyle = this.majorStyle.toJSON(); if (!this.minorStyle.equals(ContourStyle.fromJSON())) props.minorStyle = this.minorStyle.toJSON(); if (1 !== this.minorInterval) props.minorInterval = this.minorInterval; if (5 !== this.majorIntervalCount) props.majorIntervalCount = this.majorIntervalCount; if (true !== this.showGeometry) props.showGeometry = this.showGeometry; return props; } /** Create a new Contour. Any properties not specified by `props` will be initialized to their default values. */ static create(props) { return props ? new this(props) : new Contour(); } /** Create a copy of this Contour, identical except for any properties specified by `changedProps`. * Any properties of `changedProps` explicitly set to `undefined` will be reset to their default values. */ clone(changedProps) { if (!changedProps) return this; return Contour.create({ ...this, ...changedProps }); } } /** Defines a group of objects to which to apply [[Contour]] lines in a particular style. * The [[ContourDisplay]] settings can contain multiple groups. * Each group is described by a set of [SubCategory]($backend)'s; all geometry belonging to any of those subcategories belongs to the group. * An empty set of subcategories indicates that this is a default group, implicitly containing all subcategories that are not explicitly included in another group. * Each group has an optional, non-user-facing name that applications can use to assign semantics to particular groups. * @public */ export class ContourGroup { _subCategories; /** Describes the appearance of all of the contours applied to geometry belonging to this group. */ contourDef; /** An optional, non-user-facing name that applications can use to assign semantics to particular groups. * Default: an empty string. */ name; /** The set of subcategories belonging to this group, or an empty set if this is a default group. If more than one empty set exists in the [[ContourDisplay]] object's `groups` array, the last entry in that array is used for rendering the default styling. * @see [[isDefaultGroup]] to test if this is a default group. */ get subCategories() { return CompressedId64Set.iterable(this._subCategories); } /** Returns true if [[subCategories]] is an empty set, indicating that any subcategory not included in any other [[ContourGroup]] is implicitly * included in this group. */ get isDefaultGroup() { return OrderedId64Iterable.isEmptySet(this._subCategories); } /** Returns true if `this` and `other` contain the exact same set of subcategories. */ subCategoriesEqual(other) { return this._subCategories === other._subCategories; } /** Perform ordered comparison between this and another contour group. */ compare(other) { return compareStrings(this.name, other.name) || compareStrings(this._subCategories, other._subCategories) || this.contourDef.compare(other.contourDef); } /** Returns true if `this` and `other` are logically equivalent, having the same styling, name, and set of subcategories. */ equals(other) { return undefined !== other && this.compare(other) === 0; } constructor(props) { this.contourDef = props?.contourDef ?? Contour.fromJSON(); this._subCategories = props?.subCategories ? CompressedId64Set.sortAndCompress(props.subCategories) : ""; this.name = props?.name ?? ""; } static fromJSON(props) { if (!props) return new ContourGroup(); return new this({ contourDef: props?.contourDef ? Contour.fromJSON(props.contourDef) : undefined, name: props?.name, subCategories: props?.subCategories ? CompressedId64Set.iterable(props.subCategories) : undefined, }); } toJSON() { const props = {}; if (!this.contourDef.equals(Contour.defaults)) props.contourDef = this.contourDef.toJSON(); if (this.name) props.name = this.name; props.subCategories = this._subCategories; return props; } /** Create a new ContourGroup. Any properties not specified by `props` will be initialized to their default values. */ static create(props) { return props ? new this(props) : new ContourGroup(); } /** Create a copy of this ContourGroup, identical except for any properties specified by `changedProps`. * Any properties of `changedProps` explicitly set to `undefined` will be reset to their default values. */ clone(changedProps) { if (!changedProps) return this; return ContourGroup.create({ ...this, ...changedProps }); } } /** Settings that specify how to apply [contour lines]($docs/learning/display/ContourDisplay.md) to groups of geometry * within a 3d scene. * @see [[DisplayStyle3dSettings.contours]] to associate contour settings with a display style. * @public */ export class ContourDisplay { /** A list of the groups, each describing their own specific contour display settings. Defaults to an empty array. * @note The display system supports no more than [[ContourDisplay.maxContourGroups]]. Entries in this array exceeding that maximum will * have no effect on the display of contour lines. */ groups; /** Whether to display the contour lines described by these settings. Default: false. * @see [[withDisplayContours]] to change this flag. */ displayContours; /** The maximum number of contour groups that the system will allow. Any contour groups added to the [[groups]] array beyond this number will be ignored * for display purposes. */ static maxContourGroups = 5; /** Perform ordered comparison between this and another `ContourDisplay`. */ compare(other) { return compareBooleans(this.displayContours, other.displayContours) || compareArrays(this.groups, other.groups, (lhs, rhs) => lhs.compare(rhs)); } /** Returns true if `this` and `other` are logically equivalent, having the same groups and styling. */ equals(other) { if (this.displayContours !== other.displayContours) return false; if (this.groups.length !== other.groups.length) return false; for (let index = 0, len = this.groups.length; index < len && index < ContourDisplay.maxContourGroups; ++index) { const match = this.groups[index].equals(other.groups[index]); if (!match) return false; } return true; } constructor(props) { this.displayContours = props?.displayContours ?? false; this.groups = props?.groups ?? []; } static fromJSON(props) { if (!props) return new ContourDisplay(); const groups = []; if (undefined !== props && undefined !== props.groups) { for (let n = 0; n < props.groups.length; n++) { groups[n] = ContourGroup.fromJSON(props.groups[n]); } } return new this({ displayContours: props?.displayContours, groups: props.groups ? groups : undefined, }); } toJSON() { const props = {}; props.groups = []; for (let n = 0; n < this.groups.length; n++) { props.groups[n] = this.groups[n].toJSON(); } props.displayContours = this.displayContours; return props; } /** Create a new ContourDisplay. Any properties not specified by `props` will be initialized to their default values. */ static create(props) { return props ? new this(props) : new ContourDisplay(); } /** Create a copy of these settings, changing the `displayContours` flag as specified. */ withDisplayContours(displayContours) { return displayContours === this.displayContours ? this : ContourDisplay.create({ ...this, displayContours }); } /** Create a copy of this ContourDisplay, identical except for any properties specified by `changedProps`. * Any properties of `changedProps` explicitly set to `undefined` will be reset to their default values. */ clone(changedProps) { if (!changedProps) return this; return ContourDisplay.create({ ...this, ...changedProps }); } } //# sourceMappingURL=ContourDisplay.js.map