@numericelements/knot-sequence
Version:
A library for generating and manipulating knot sequences for b-spline curves and surfaces
143 lines (140 loc) • 6.92 kB
JavaScript
import { AbstractKnotSequence } from './AbstractKnotSequence.js';
import { Knot } from './Knot.js';
import { NO_KNOT_PERIODIC_CURVE, UNIFORM_PERIODICKNOTSEQUENCE } from './KnotSequenceConstructorInterface.js';
import { EM_ORIGIN_NORMALIZEDKNOT_SEQUENCE, EM_KNOT_MULTIPLICITIES_AT_NORMALIZED_BASIS_BOUNDS_DIFFER, EM_SEQUENCE_ORIGIN_REMOVAL, EM_ABSCISSA_TOO_CLOSE_TO_KNOT, EM_KNOT_INSERTION_UNDER_SEQORIGIN, EM_KNOT_INSERTION_OVER_UMAX } from './ErrorMessages/KnotSequences.js';
import { UPPER_BOUND_NORMALIZED_BASIS_DEFAULT_ABSCISSA, KNOT_SEQUENCE_ORIGIN } from './namedConstants/KnotSequences.js';
class AbstractPeriodicKnotSequence extends AbstractKnotSequence {
constructor(maxMultiplicityOrder, knotParameters) {
super(maxMultiplicityOrder);
this._isKnotMultiplicityNonUniform = false;
this.knotSequence = [];
this._uMax = UPPER_BOUND_NORMALIZED_BASIS_DEFAULT_ABSCISSA;
if (knotParameters.type === NO_KNOT_PERIODIC_CURVE) {
this.computeKnotSequenceFromMaxMultiplicityOrder();
}
else if (knotParameters.type === UNIFORM_PERIODICKNOTSEQUENCE) {
this.computeUniformKnotSequenceFromBsplBasisSize(knotParameters);
}
}
get uMax() {
return this._uMax;
}
get isKnotMultiplicityNonUniform() {
return this._isKnotMultiplicityNonUniform;
}
checkNonUniformKnotMultiplicityOrder() {
this._isKnotMultiplicityNonUniform = false;
}
checkNormalizedBasisOrigin() {
if (this.knotSequence[0].abscissa !== KNOT_SEQUENCE_ORIGIN) {
this.throwRangeErrorMessage('checkNormalizedBasisOrigin', EM_ORIGIN_NORMALIZEDKNOT_SEQUENCE);
}
}
getPeriod() {
return this.knotSequence[this.knotSequence.length - 1].abscissa - this.knotSequence[0].abscissa;
}
lastKnot() {
return this.knotSequence[this.knotSequence.length - 1].abscissa;
}
checkKnotMultiplicitiesAtNormalizedBasisBoundaries() {
if (this.knotSequence[0].multiplicity !== this.knotSequence[this.knotSequence.length - 1].multiplicity) {
this.throwRangeErrorMessage("checkKnotMultiplicitiesAtNormalizedBasisBoundaries", EM_KNOT_MULTIPLICITIES_AT_NORMALIZED_BASIS_BOUNDS_DIFFER);
}
}
computeKnotSequenceFromMaxMultiplicityOrder() {
const minValueMaxMultiplicityOrder = 1;
this.constructorInputMultOrderAssessment(minValueMaxMultiplicityOrder);
let upperBound = this._maxMultiplicityOrder + 1;
if (this._maxMultiplicityOrder === 1)
upperBound = this._maxMultiplicityOrder + 2;
for (let i = 0; i < upperBound; i++) {
this.knotSequence.push(new Knot(i, 1));
}
this._uMax = this._maxMultiplicityOrder + 1;
}
computeUniformKnotSequenceFromBsplBasisSize(knotParameters) {
const minValueMaxMultiplicityOrder = 1;
this.constructorInputMultOrderAssessment(minValueMaxMultiplicityOrder);
this.constructorInputBspBasisSizeAssessment(knotParameters);
for (let i = 0; i < knotParameters.BsplBasisSize; i++) {
this.knotSequence.push(new Knot(i, 1));
}
this._uMax = this.knotSequence[this.knotSequence.length - 1].abscissa;
}
decrementKnotMultiplicityMutSeq(index) {
if (!Array.isArray(index))
index = [index];
for (const ind of index) {
this.strictlyIncKnotIndexInputParamAssessment(ind, "decrementKnotMultiplicityMutSeq");
if (this.knotSequence[ind.knotIndex].multiplicity === 1) {
if (ind.knotIndex === 0 || ind.knotIndex === this.knotSequence.length - 1) {
this.throwRangeErrorMessage("decrementKnotMultiplicityMutSeq", EM_SEQUENCE_ORIGIN_REMOVAL);
}
const abscissae = this.distinctAbscissae();
const multiplicities = this.multiplicities();
abscissae.splice(ind.knotIndex, 1);
multiplicities.splice(ind.knotIndex, 1);
this.knotSequence = [];
let i = 0;
for (const abscissa of abscissae) {
const knot = new Knot(abscissa, multiplicities[i]);
this.knotSequence.push(knot);
i++;
}
}
else {
this.knotSequence[ind.knotIndex].multiplicity--;
if (ind.knotIndex === 0) {
this.knotSequence[this.knotSequence.length - 1].multiplicity--;
}
else if (ind.knotIndex === (this.knotSequence.length - 1)) {
this.knotSequence[0].multiplicity--;
}
}
}
this.checkUniformityOfKnotSpacing();
this.checkUniformityOfKnotMultiplicity();
this.checkNonUniformKnotMultiplicityOrder();
}
raiseKnotMultiplicityArrayMutSeq(indicesArray, multiplicity) {
if (!Array.isArray(indicesArray))
indicesArray = [indicesArray];
for (const index of indicesArray) {
const indexWithinPeriod = index.knotIndex % (this.knotSequence.length - 1);
this.knotSequence[indexWithinPeriod].multiplicity += multiplicity;
this.checkMaxMultiplicityOrderConsistency();
if (indexWithinPeriod === 0)
this.knotSequence[this.knotSequence.length - 1].multiplicity += multiplicity;
}
this.checkUniformityOfKnotMultiplicity();
this.checkNonUniformKnotMultiplicityOrder();
}
insertKnotMutSeq(abscissae, multiplicity = 1) {
if (!Array.isArray(abscissae))
abscissae = [abscissae];
for (const abscissa of abscissae) {
if (this.isAbscissaCoincidingWithKnot(abscissa)) {
this.throwRangeErrorMessage("insertKnot", EM_ABSCISSA_TOO_CLOSE_TO_KNOT);
}
if (abscissa < this.knotSequence[0].abscissa) {
this.throwRangeErrorMessage("insertKnot", EM_KNOT_INSERTION_UNDER_SEQORIGIN);
}
else if (abscissa > this.knotSequence[this.knotSequence.length - 1].abscissa) {
this.throwRangeErrorMessage("insertKnot", EM_KNOT_INSERTION_OVER_UMAX);
}
this.maxMultiplicityOrderInputParamAssessment(multiplicity, "insertKnot");
const knot = new Knot(abscissa, multiplicity);
let i = 0;
while (i < (this.knotSequence.length - 1)) {
if (this.knotSequence[i].abscissa < abscissa && abscissa < this.knotSequence[i + 1].abscissa)
break;
i++;
}
this.knotSequence.splice((i + 1), 0, knot);
this.checkUniformityOfKnotSpacing();
this.checkUniformityOfKnotMultiplicity();
this.checkNonUniformKnotMultiplicityOrder();
}
}
}
export { AbstractPeriodicKnotSequence };