@numericelements/knot-sequence
Version:
A library for generating and manipulating knot sequences for b-spline curves and surfaces
135 lines (132 loc) • 6.27 kB
JavaScript
import { UPPER_BOUND_NORMALIZED_BASIS_DEFAULT_ABSCISSA, KNOT_SEQUENCE_ORIGIN, KNOT_COINCIDENCE_TOLERANCE } from './namedConstants/KnotSequences.js';
import { AbstractPeriodicKnotSequence } from './AbstractPeriodicKnotSequence.js';
import { Knot } from './Knot.js';
import { STRICTLYINCREASINGPERIODICKNOTSEQUENCE } from './KnotSequenceConstructorInterface.js';
import { EM_KNOTSEQ_MULTIPLICITIES_INCOMPATIBLE_NORMALIZEDBASIS, EM_U_OUTOF_KNOTSEQ_RANGE } from './ErrorMessages/KnotSequences.js';
import { KnotIndexStrictlyIncreasingSequence } from './KnotIndexStrictlyIncreasingSequence.js';
class StrictlyIncreasingPeriodicKnotSequenceClosedCurve extends AbstractPeriodicKnotSequence {
constructor(maxMultiplicityOrder, knotsParameters) {
super(maxMultiplicityOrder, knotsParameters);
this._indexKnotOrigin = new KnotIndexStrictlyIncreasingSequence(0);
if (knotsParameters.type === STRICTLYINCREASINGPERIODICKNOTSEQUENCE) {
this.generateStrictlyIncreasingSequence(knotsParameters);
this.checkKnotMultiplicitiesAtNormalizedBasisBoundaries();
}
this.checkUniformityOfKnotMultiplicity();
this.checkUniformityOfKnotSpacing();
this.checkNonUniformKnotMultiplicityOrder();
this.checkNormalizedBasisOrigin();
}
get allAbscissae() {
const abscissae = [];
for (const knot of this) {
if (knot !== undefined)
abscissae.push(knot.abscissa);
}
return abscissae;
}
[Symbol.iterator]() {
const lastIndex = this.knotSequence.length - 1;
let index = 0;
return {
next: () => {
if (index <= lastIndex) {
const abscissa = this.knotSequence[index].abscissa;
const multiplicity = this.knotSequence[index].multiplicity;
index++;
return { value: { abscissa: abscissa, multiplicity: multiplicity }, done: false };
}
else {
index = 0;
return { done: true };
}
}
};
}
length() {
return this.knotSequence.length;
}
clone() {
return new StrictlyIncreasingPeriodicKnotSequenceClosedCurve(this._maxMultiplicityOrder, { type: STRICTLYINCREASINGPERIODICKNOTSEQUENCE, periodicKnots: this.distinctAbscissae(), multiplicities: this.multiplicities() });
}
generateStrictlyIncreasingSequence(knotParameters) {
const minValueMaxMultiplicityOrder = 1;
this.constructorInputMultOrderAssessment(minValueMaxMultiplicityOrder);
this.constructorInputArrayAssessment(knotParameters);
this.checkKnotStrictlyIncreasingValues(knotParameters.periodicKnots);
for (let i = 0; i < knotParameters.periodicKnots.length; i++) {
this.knotSequence.push(new Knot(knotParameters.periodicKnots[i], knotParameters.multiplicities[i]));
}
this.checkMaxMultiplicityOrderConsistency();
let cumulative_multiplicities = this.knotSequence[0].multiplicity;
for (let i = 1; i < this.knotSequence.length - 1; i++) {
cumulative_multiplicities += this.knotSequence[i].multiplicity;
}
if ((cumulative_multiplicities < this._maxMultiplicityOrder && this._maxMultiplicityOrder > 1)
|| (cumulative_multiplicities < (this._maxMultiplicityOrder + 1) && this._maxMultiplicityOrder === 1)) {
this.throwRangeErrorMessage("generateStrictlyIncreasingSequence", EM_KNOTSEQ_MULTIPLICITIES_INCOMPATIBLE_NORMALIZEDBASIS);
}
this._uMax = this.knotSequence[this.knotSequence.length - 1].abscissa;
this.checkNormalizedBasisOrigin();
this.checkKnotMultiplicitiesAtNormalizedBasisBoundaries();
}
abscissaAtIndex(index) {
let abscissa = UPPER_BOUND_NORMALIZED_BASIS_DEFAULT_ABSCISSA;
const indexPeriod = new KnotIndexStrictlyIncreasingSequence(index.knotIndex % (this.allAbscissae.length - 1));
let i = 0;
for (const knot of this) {
if (i === indexPeriod.knotIndex && knot !== undefined)
abscissa = knot.abscissa;
i++;
}
return abscissa;
}
findSpan(u) {
let index = UPPER_BOUND_NORMALIZED_BASIS_DEFAULT_ABSCISSA;
if (u > this.knotSequence[this.knotSequence.length - 1].abscissa) {
u = u % this.getPeriod();
}
if (u < KNOT_SEQUENCE_ORIGIN) {
this.throwRangeErrorMessage("findSpan", EM_U_OUTOF_KNOTSEQ_RANGE);
}
else {
if (this.isAbscissaCoincidingWithKnot(u)) {
index = 0;
for (const knot of this.knotSequence) {
index++;
if (Math.abs(u - knot.abscissa) < KNOT_COINCIDENCE_TOLERANCE) {
if (knot.abscissa === this.knotSequence[this.knotSequence.length - 1].abscissa) {
index = this.knotSequence.length - 1;
}
index -= 1;
break;
}
}
return new KnotIndexStrictlyIncreasingSequence(index);
}
index = this.findSpanWithAbscissaDistinctFromKnotStrictlyIncreasingKnotSequence(u);
}
return new KnotIndexStrictlyIncreasingSequence(index);
}
revertKnotSequence() {
const newKnotSequence = this.clone();
newKnotSequence.revertKnotSpacing();
return newKnotSequence;
}
raiseKnotMultiplicity(indicesArray, multiplicity = 1) {
const newKnotSequence = this.clone();
newKnotSequence.raiseKnotMultiplicityArrayMutSeq(indicesArray, multiplicity);
return newKnotSequence;
}
decrementKnotMultiplicity(index) {
const newKnotSequence = this.clone();
newKnotSequence.decrementKnotMultiplicityMutSeq(index);
return newKnotSequence;
}
insertKnot(abscissae, multiplicity = 1) {
const newKnotSequence = this.clone();
newKnotSequence.insertKnotMutSeq(abscissae, multiplicity);
return newKnotSequence;
}
}
export { StrictlyIncreasingPeriodicKnotSequenceClosedCurve };