@itwin/core-common
Version:
iTwin.js components common to frontend and backend
332 lines • 16.2 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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