plotboilerplate
Version:
A simple javascript plotting boilerplate for 2d stuff.
179 lines (161 loc) • 4.63 kB
text/typescript
/**
* @classdesc A circular interval set.
*
* @author Ikaros Kappler
* @date 2020-10-02
* @modified 2020-10-18 Ported to Typescript from vanilla JS.
* @modified 2020-10-22 Added the removeAt funcion.
* @version 1.0.1
* @name CircularIntervalSet
**/
export class CircularIntervalSet {
/**
* @member {number} start
* @memberof CircularIntervalSet
* @type {number}
* @instance
*/
readonly start:number;
/**
* @member {number} end
* @memberof CircularIntervalSet
* @type {number}
* @instance
*/
readonly end:number;
/**
* @member {Array<Array<number>>} intervals
* @memberof CircularIntervalSet
* @type {Array<Array<number>>}
* @instance
*/
public intervals:Array<Array<number>>;
/**
* Create a new CircularIntervalSet with the given lower and upperBound (start and end).
*
* The intervals inside lower and upper bound will initially be added to this set (full range).
*
* @param {number} start
* @param {number} end
* @method clear
* @memberof CircularIntervalSet
**/
constructor( start:number, end:number ) {
this.start = start;
this.end = end;
this.intervals = [ [start, end] ];
};
/**
* Clear this set (will be empty after this operation).
*
* @method clear
* @instance
* @memberof CircularIntervalSet
* @return {void}
**/
clear() {
this.intervals = [];
};
/**
* Remove the interval at given index.
*
* @param {number} index
* @method removeAt
* @instance
* @memberof CircularIntervalSet
* @return {void}
**/
// Todo: remove? (not in use any more?)
removeAt(index:number) : void {
if( index < 0 || index >= this.intervals.length )
return;
this.intervals.splice( index, 1 );
};
/**
* Intersect all sub intervalls with the given range (must be inside bounds).
*
* @param {number} start
* @param {number} end
* @method intersect
* @instance
* @memberof CircularIntervalSet
* @return {void}
**/
intersect( start:number, end:number ) {
for( var i = 0; i < this.intervals.length; ) {
if( start <= end ) {
if( (this.intervals[i][0] >= end || this.intervals[i][1] <= start) ) {
// Current interval is fully outside range.
// REMOVE
this.intervals.splice( i, 1 );
} else if( this.intervals[i][0] >= start && this.intervals[i][1] <= end ) {
// Current interval is fully inside.
// KEEP
i++;
} else if( this.intervals[i][0] <= start && this.intervals[i][1] >= end ) {
// Desired range lies inside current interval.
// CUT OFF LEFT AND RIGHT.
this.intervals.splice( i, 1, [start,end] );
i++;
} else if( this.intervals[i][0] <= start && this.intervals[i][1] < end ) {
// Right end is inside range.
// CUT OFF LEFT.
this.intervals[i][0] = start;
i++;
} else if( this.intervals[i][0] > start && this.intervals[i][1] >= end ) {
// LEFT end is inside range.
// CUT OFF RIGHT.
this.intervals[i][1] = end;
i++;
} else {
// NOOP
i++;
}
} else {
// start > end
if( this.intervals[i][0] >= end && this.intervals[i][1] <= start ) {
// Current interval is fully outside range.
// REMOVE
this.intervals.splice( i, 1 );
} else if( this.intervals[i][0] >= start ) {
// Full inside (right range).
// Keep.
i++;
} else if( this.intervals[i][1] <= end ) {
// Full inside (left range).
// Keep.
i++;
} else if( this.intervals[i][0] >= end && this.intervals[i][1] > start ) {
// Right part inside.
// Cut off left part.
this.intervals.splice( i, 1, [start,this.intervals[i][1]] );
i++;
} else if( this.intervals[i][0] <= end && this.intervals[i][1] < start ) {
// Left part inside.
// Cut off right part.
this.intervals.splice( i, 1, [this.intervals[i][0],end] );
i++;
} else if( this.intervals[i][0] <= end && this.intervals[i][1] >= start ) {
// Start and end inside, inner part is not.
// Cut into two.
this.intervals.splice( i, 1, [this.intervals[i][0],end], [start,this.intervals[i][1]] );
i+=2;
} else {
// NOOP
i++;
}
}
}
};
/**
* Convert this set to a human readable string.
*
* @method toString
* @instance
* @memberof CircularIntervalSet
* @return {string}
**/
toString() {
return JSON.stringify( this.intervals );
};
}