/*---------------------------------------------------------------------------------------------
* 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 { compareBooleans, compareNumbers, 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 {
    /** 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;
    }
    /** 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 {
    equals(other) {
        if (!this.majorStyle.equals(other.majorStyle) || !this.minorStyle.equals(other.minorStyle) || this.minorInterval !== other.minorInterval || this.majorIntervalCount !== other.majorIntervalCount || this.showGeometry !== other.showGeometry) {
            return false;
        }
        return true;
    }
    /** 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 });
    }
}
Contour.defaults = new Contour({});
/** 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 {
    /** 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;
    }
    /** Returns true if `this` and `other` are logically equivalent, having the same styling, name, and set of subcategories. */
    equals(other) {
        if (this === undefined && other === undefined)
            return true;
        if (this === undefined || other === undefined)
            return false;
        if (!this.contourDef.equals(other.contourDef))
            return false;
        if (this._subCategories !== other._subCategories)
            return false;
        if (this.name !== other.name)
            return false;
        return true;
    }
    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 {
    /** 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 });
    }
}
/** 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.
 */
ContourDisplay.maxContourGroups = 5;
//# sourceMappingURL=ContourDisplay.js.map