diff --git a/src/control/IntersectionReferenceSystem.ts b/src/control/IntersectionReferenceSystem.ts index 94702ceb..17fda5dd 100644 --- a/src/control/IntersectionReferenceSystem.ts +++ b/src/control/IntersectionReferenceSystem.ts @@ -68,7 +68,7 @@ export class IntersectionReferenceSystem { private setPath(path: number[][], options: ReferenceSystemOptions = {}): void { this.options = options; - const { calculateDisplacementFromBottom } = this.options; + const { arcDivisions, tension, calculateDisplacementFromBottom } = this.options; this.path = path; @@ -81,9 +81,9 @@ export class IntersectionReferenceSystem { curve: new CurveInterpolator(path), trajectory: new CurveInterpolator( path.map((d: number[]) => [d[0], d[1]]), - { tension: TENSION, arcDivisions: ARC_DIVISIONS }, + { tension: tension || TENSION, arcDivisions: arcDivisions || ARC_DIVISIONS }, ), - curtain: new CurveInterpolator(this.projectedPath, { tension: TENSION, arcDivisions: ARC_DIVISIONS }), + curtain: new CurveInterpolator(this.projectedPath, { tension: tension || TENSION, arcDivisions: arcDivisions || ARC_DIVISIONS }), }; const trajVector = this.getTrajectoryVector(); @@ -105,10 +105,10 @@ export class IntersectionReferenceSystem { */ project(length: number): number[] { const { curtain } = this.interpolators; - const { calculateDisplacementFromBottom } = this.options; + const { normalizedLength, calculateDisplacementFromBottom } = this.options; - const normalizedLength = (length - this._offset) / this.length; - const l = calculateDisplacementFromBottom ? 1 - normalizedLength : normalizedLength; + const factor = (length - this._offset) / (normalizedLength || this.length); + const l = calculateDisplacementFromBottom ? 1 - factor : factor; const t = clamp(l, 0, 1); const p = curtain.getPointAt(t); @@ -157,19 +157,20 @@ export class IntersectionReferenceSystem { * Map a displacement back to length along the curve */ unproject(displacement: number): number { - const { calculateDisplacementFromBottom } = this.options; + const { normalizedLength, calculateDisplacementFromBottom } = this.options; const displacementFromStart = calculateDisplacementFromBottom ? this.displacement - displacement : displacement; + const length = normalizedLength || this.length; if (displacementFromStart < 0) { return displacementFromStart; } if (displacementFromStart > this.displacement) { - return this.length + (displacementFromStart - this.displacement); + return length + (displacementFromStart - this.displacement); } const ls = this.interpolators.curtain.lookupPositions(displacementFromStart, 0, 1); if (ls && ls.length) { - return ls[0] * this.length + this._offset; + return ls[0] * length + this._offset; } return null; } @@ -259,26 +260,30 @@ export class IntersectionReferenceSystem { /** * Generate a set of coordinates along the trajectory of the curve */ - getExtendedTrajectory(steps: number, extensionStart = DEFAULT_START_EXTEND_LENGTH, extensionEnd = DEFAULT_END_EXTEND_LENGTH): Trajectory { - if (!isFinite(extensionStart) || extensionStart < 0.0) { - throw new Error('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive extensionStart parameter'); + getExtendedTrajectory( + numPoints: number, + startExtensionLength = DEFAULT_START_EXTEND_LENGTH, + endExtensionLength = DEFAULT_END_EXTEND_LENGTH, + ): Trajectory { + if (!isFinite(startExtensionLength) || startExtensionLength < 0.0) { + throw new Error('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive startExtensionLength parameter'); } - if (!isFinite(extensionEnd) || extensionEnd < 0.0) { - throw new Error('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive extensionEnd parameter'); + if (!isFinite(endExtensionLength) || endExtensionLength < 0.0) { + throw new Error('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive endExtensionLength parameter'); } - const totalLength = this.displacement + extensionStart + extensionEnd; - const preSteps = Math.floor((extensionStart / totalLength) * steps); - const curveSteps = Math.max(Math.ceil((this.displacement / totalLength) * steps), 1); - const postSteps = steps - curveSteps - preSteps; + const totalLength = this.displacement + startExtensionLength + endExtensionLength; + const startExtensionNumPoints = Math.floor((startExtensionLength / totalLength) * numPoints); + const curveSteps = Math.max(Math.ceil((this.displacement / totalLength) * numPoints), 1); + const endExtensionNumPoints = numPoints - curveSteps - startExtensionNumPoints; const points = []; const refStart = new Vector2(this.interpolators.trajectory.getPointAt(0.0)); const startVec = new Vector2(this.startVector); - const preStep = extensionStart / preSteps; - for (let i = preSteps; i > 0; i--) { - const f = i * preStep; + const startExtensionStepLength = startExtensionLength / startExtensionNumPoints; + for (let i = startExtensionNumPoints; i > 0; i--) { + const f = i * startExtensionStepLength; const point = refStart.add(startVec.scale(f)); points.push(point.toArray()); } @@ -287,14 +292,14 @@ export class IntersectionReferenceSystem { const refEnd = new Vector2(this.interpolators.trajectory.getPointAt(1.0)); const endVec = new Vector2(this.endVector); - const postStep = extensionEnd / postSteps; - for (let i = 1; i < postSteps; i++) { - const f = i * postStep; + const endExtensionStepLength = endExtensionLength / (endExtensionNumPoints - 1); // -1 so last point is at end of extension + for (let i = 1; i < endExtensionNumPoints; i++) { + const f = i * endExtensionStepLength; const point = refEnd.add(endVec.scale(f)); points.push(point.toArray()); } - const offset = -extensionStart; + const offset = -startExtensionLength; return { points, offset }; } diff --git a/src/interfaces.ts b/src/interfaces.ts index 389d12bc..b4721279 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -172,6 +172,9 @@ export interface Trajectory { } export interface ReferenceSystemOptions { + normalizedLength?: number; + arcDivisions?: number; + tension?: number; trajectoryAngle?: number; calculateDisplacementFromBottom?: boolean; } diff --git a/test/reference-system.test.ts b/test/reference-system.test.ts index b06c635b..a1c7eec2 100644 --- a/test/reference-system.test.ts +++ b/test/reference-system.test.ts @@ -1,3 +1,4 @@ +import { degrees } from '@equinor/videx-math'; import { IntersectionReferenceSystem } from '../src'; const wp = [ @@ -16,7 +17,7 @@ function dist(a: number[], b: number[]): number { describe('Reference system', () => { let rs: IntersectionReferenceSystem; beforeEach(() => { - rs = new IntersectionReferenceSystem(wp); + rs = new IntersectionReferenceSystem(wp, { trajectoryAngle: 0 }); }); it('should set path on creation', () => { expect(rs.path).not.toEqual(undefined); @@ -82,8 +83,7 @@ describe('Reference system', () => { expect(trajectory.points.length).toEqual(100); }); - /* TODO: Issue is now solved and tests can be fixed and uncommented - * Jest failed previously due to not finding Vector2 constructor. + it('should have same distance between points in extended trajectory', () => { const trajectory = rs.getExtendedTrajectory(200, 500.0, 500.0); const firstDistance = dist(trajectory.points[0], trajectory.points[1]); @@ -91,7 +91,7 @@ describe('Reference system', () => { for(let i = 2; i < trajectory.points.length; i++){ const point = trajectory.points[i]; const currentDistance = dist(point, lastPoint); - expect(currentDistance).toBeCloseTo(firstDistance); + expect(currentDistance).toBeCloseTo(firstDistance, 0); lastPoint = point; } }); @@ -102,16 +102,16 @@ describe('Reference system', () => { expect(startExtend).toBeCloseTo(500.0); expect(endExtend).toBeCloseTo(500.0); }); -*/ + it('should throw error when parameters are negative', () => { expect(() => { const trajectory = rs.getExtendedTrajectory(100, -50.0, 500.0); - }).toThrow('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive extensionStart parameter'); + }).toThrow('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive startExtensionLength parameter'); expect(() => { const trajectory = rs.getExtendedTrajectory(100, 50.0, -500.0); - }).toThrow('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive extensionEnd parameter'); + }).toThrow('Invalid parameter, getExtendedTrajectory() must be called with a valid and positive endExtensionLength parameter'); }); - /* + it('should work for vertical wellbore', () => { const verticalPosLog = [ [30, 40, 100], @@ -127,8 +127,44 @@ describe('Reference system', () => { const endExtend = dist(trajectory.points[99], irs.interpolators.trajectory.getPointAt(1.0)); expect(startExtend).toBeCloseTo(1500.0); expect(endExtend).toBeCloseTo(1500.0); - const angle = Math.atan((trajectory.points[99][0] - trajectory.points[0][0]) / (trajectory.points[99][1] - trajectory.points[0][1])); - expect(endExtend).toBeCloseTo(45.0); + const angle = degrees(Math.atan((trajectory.points[99][0] - trajectory.points[0][0]) / (trajectory.points[99][1] - trajectory.points[0][1]))); + expect(angle).toBeCloseTo(45.0); + }); + + it('should project to right depths on vertical wellbores', () => { // Note: this is used for picks + const verticalPosLog = [ + [30, 40, 50], + [30, 40, 6500], + ]; + const options = {trajectoryAngle: 45.0}; + const irs = new IntersectionReferenceSystem(verticalPosLog, options); + irs.offset = 50; + + expect(irs.project(0)[1]).toBeCloseTo(50); + expect(irs.project(7000)[1]).toBeCloseTo(6500); + + expect(irs.project(200)[1]).toBeCloseTo(200); + expect(irs.project(6000)[1]).toBeCloseTo(6000); + + }); + + it('should project to right depths on vertical wellbores with negative offset', () => { // Note: this is used for picks + const verticalPosLog = [ + [80, 40, -25], + [80, 40, 5000], + ]; + const options = {trajectoryAngle: 45.0}; + const irs = new IntersectionReferenceSystem(verticalPosLog, options); + irs.offset = -25; + + expect(irs.project(-100)[1]).toBeCloseTo(-25); + expect(irs.project(0)[1]).toBeCloseTo(0); + expect(irs.project(7000)[1]).toBeCloseTo(5000); + + expect(irs.project(200)[1]).toBeCloseTo(200); + expect(irs.project(4000)[1]).toBeCloseTo(4000); + }); - */ + + });