@tetacom/ng-components 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,9 +4,10 @@ import * as i0 from "@angular/core";
|
|
|
4
4
|
export declare class Chart3dTooltipService {
|
|
5
5
|
private _raycaster;
|
|
6
6
|
private _mouse;
|
|
7
|
+
findClosestPointOnCurveLocal(point: THREE.Vector3, curve: THREE.CatmullRomCurve3): THREE.Vector3;
|
|
7
8
|
constructor();
|
|
8
9
|
findIntersection(event: MouseEvent, canvas: HTMLCanvasElement, camera: THREE.Camera, wellMeshes: WellMeshData[]): IntersectionResult | null;
|
|
9
|
-
|
|
10
|
+
private findClosestPointOnCurveToRay;
|
|
10
11
|
private findClosestDataPoint;
|
|
11
12
|
private calculateTVD;
|
|
12
13
|
static ɵfac: i0.ɵɵFactoryDeclaration<Chart3dTooltipService, never>;
|
|
@@ -488,6 +488,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
488
488
|
}], ctorParameters: () => [] });
|
|
489
489
|
|
|
490
490
|
class Chart3dTooltipService {
|
|
491
|
+
// Kept for marker/orientation logic in the component (not used for MD now)
|
|
492
|
+
findClosestPointOnCurveLocal(point, curve) {
|
|
493
|
+
let closestPoint = new THREE.Vector3();
|
|
494
|
+
let minDistance = Infinity;
|
|
495
|
+
const samples = 200;
|
|
496
|
+
for (let i = 0; i <= samples; i++) {
|
|
497
|
+
const t = i / samples;
|
|
498
|
+
const curvePoint = curve.getPoint(t);
|
|
499
|
+
const distance = point.distanceTo(curvePoint);
|
|
500
|
+
if (distance < minDistance) {
|
|
501
|
+
minDistance = distance;
|
|
502
|
+
closestPoint = curvePoint;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return closestPoint;
|
|
506
|
+
}
|
|
491
507
|
constructor() {
|
|
492
508
|
this._raycaster = new THREE.Raycaster();
|
|
493
509
|
this._mouse = new THREE.Vector2();
|
|
@@ -505,19 +521,29 @@ class Chart3dTooltipService {
|
|
|
505
521
|
if (intersects.length === 0) {
|
|
506
522
|
return null;
|
|
507
523
|
}
|
|
524
|
+
// Prefer the closest intersection by distance (Three usually returns sorted,
|
|
525
|
+
// but keeping it explicit avoids surprises across versions)
|
|
526
|
+
intersects.sort((a, b) => a.distance - b.distance);
|
|
508
527
|
// 3. Find well data
|
|
509
528
|
const intersect = intersects[0];
|
|
510
529
|
const wellData = wellMeshes.find((_) => _.mesh === intersect.object);
|
|
511
530
|
if (!wellData) {
|
|
512
531
|
return null;
|
|
513
532
|
}
|
|
514
|
-
// 4. Calculate closest point on curve
|
|
515
|
-
|
|
516
|
-
|
|
533
|
+
// 4. Calculate closest point on the trajectory curve using the mouse ray.
|
|
534
|
+
// Using the curve parameter t makes the tooltip smooth even for very low-point trajectories (e.g. 3 points).
|
|
535
|
+
const hit = this.findClosestPointOnCurveToRay(this._raycaster.ray, wellData.curve, wellData.points);
|
|
536
|
+
const closestPoint = hit.point;
|
|
537
|
+
const intersectPoint = hit.hitPoint ?? intersect.point;
|
|
538
|
+
const intersectDistance = hit.hitDistance ?? intersect.distance;
|
|
539
|
+
// Override intersection with a stable point derived from ray→trajectory projection
|
|
540
|
+
intersect.point = intersectPoint;
|
|
541
|
+
intersect.distance = intersectDistance;
|
|
542
|
+
// 5. Find closest data point (useful for other fields)
|
|
517
543
|
const closestDataPoint = this.findClosestDataPoint(closestPoint, wellData.points, wellData.scale);
|
|
518
|
-
// 6. Calculate TVD and
|
|
544
|
+
// 6. Calculate TVD and MD
|
|
519
545
|
const tvd = this.calculateTVD(closestPoint, wellData.scale.y);
|
|
520
|
-
const md =
|
|
546
|
+
const md = hit.md; // smoothly interpolated along curve parameter t
|
|
521
547
|
return {
|
|
522
548
|
wellData,
|
|
523
549
|
intersectionPoint: intersect.point,
|
|
@@ -527,25 +553,81 @@ class Chart3dTooltipService {
|
|
|
527
553
|
tvd,
|
|
528
554
|
};
|
|
529
555
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
556
|
+
findClosestPointOnCurveToRay(ray, curve, orderedDataPoints) {
|
|
557
|
+
// Compute closest point on the rendered curve to the mouse ray.
|
|
558
|
+
// We sample t densely (fast enough) and then refine with a few iterations.
|
|
559
|
+
// MD is interpolated along the dataPoints md range using the same t.
|
|
560
|
+
if (!orderedDataPoints.length) {
|
|
561
|
+
return { point: new THREE.Vector3(), md: 0 };
|
|
562
|
+
}
|
|
563
|
+
if (orderedDataPoints.length === 1) {
|
|
564
|
+
// Degenerate curve
|
|
565
|
+
const p = curve.getPoint(0);
|
|
566
|
+
const s = Math.max(0, ray.direction.dot(new THREE.Vector3().subVectors(p, ray.origin)));
|
|
567
|
+
const hitPoint = ray.at(s, new THREE.Vector3());
|
|
568
|
+
return {
|
|
569
|
+
point: p,
|
|
570
|
+
md: orderedDataPoints[0].md ?? 0,
|
|
571
|
+
hitPoint,
|
|
572
|
+
hitDistance: s,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const mdMin = orderedDataPoints[0].md ?? 0;
|
|
576
|
+
const mdMax = orderedDataPoints[orderedDataPoints.length - 1].md ?? mdMin;
|
|
577
|
+
const d = ray.direction.clone().normalize();
|
|
578
|
+
// IMPORTANT: use getPointAt(u) (u = arc-length parameter), not getPoint(t).
|
|
579
|
+
// CatmullRomCurve3 "t" is not proportional to arc length and causes MD to change non-uniformly,
|
|
580
|
+
// especially noticeable when there are very few control points.
|
|
581
|
+
const distSqAt = (u) => {
|
|
582
|
+
const p = curve.getPointAt(u);
|
|
583
|
+
const s = Math.max(0, d.dot(new THREE.Vector3().subVectors(p, ray.origin)));
|
|
584
|
+
const r = ray.at(s, new THREE.Vector3());
|
|
585
|
+
return { distSq: r.distanceToSquared(p), p, s, r };
|
|
586
|
+
};
|
|
587
|
+
// 1) coarse scan over arc-length parameter u
|
|
588
|
+
const samples = 400;
|
|
589
|
+
let bestU = 0;
|
|
590
|
+
let best = distSqAt(0);
|
|
591
|
+
for (let i = 1; i <= samples; i++) {
|
|
592
|
+
const u = i / samples;
|
|
593
|
+
const cur = distSqAt(u);
|
|
594
|
+
if (cur.distSq < best.distSq) {
|
|
595
|
+
best = cur;
|
|
596
|
+
bestU = u;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// 2) refine around bestU
|
|
600
|
+
let left = Math.max(0, bestU - 1 / samples);
|
|
601
|
+
let right = Math.min(1, bestU + 1 / samples);
|
|
602
|
+
for (let iter = 0; iter < 10; iter++) {
|
|
603
|
+
const u1 = left + (right - left) / 3;
|
|
604
|
+
const u2 = right - (right - left) / 3;
|
|
605
|
+
const f1 = distSqAt(u1);
|
|
606
|
+
const f2 = distSqAt(u2);
|
|
607
|
+
if (f1.distSq < f2.distSq) {
|
|
608
|
+
right = u2;
|
|
609
|
+
best = f1;
|
|
610
|
+
bestU = u1;
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
left = u1;
|
|
614
|
+
best = f2;
|
|
615
|
+
bestU = u2;
|
|
541
616
|
}
|
|
542
617
|
}
|
|
543
|
-
|
|
618
|
+
// Final eval at bestU
|
|
619
|
+
const final = distSqAt(bestU);
|
|
620
|
+
const md = mdMin + (mdMax - mdMin) * bestU;
|
|
621
|
+
return {
|
|
622
|
+
point: final.p,
|
|
623
|
+
md,
|
|
624
|
+
hitPoint: final.r,
|
|
625
|
+
hitDistance: final.s,
|
|
626
|
+
};
|
|
544
627
|
}
|
|
545
628
|
findClosestDataPoint(curvePoint, dataPoints, scale) {
|
|
546
629
|
let closestPoint = dataPoints[0];
|
|
547
630
|
let minDistance = Infinity;
|
|
548
|
-
let closestIndex = 0;
|
|
549
631
|
for (let i = 0; i < dataPoints.length; i++) {
|
|
550
632
|
const point = dataPoints[i];
|
|
551
633
|
// Convert data point to 3D space using scales
|
|
@@ -554,36 +636,6 @@ class Chart3dTooltipService {
|
|
|
554
636
|
if (distance < minDistance) {
|
|
555
637
|
minDistance = distance;
|
|
556
638
|
closestPoint = point;
|
|
557
|
-
closestIndex = i;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
// If MD is not available in the closest point, try to interpolate
|
|
561
|
-
if (closestPoint.md === undefined || closestPoint.md === null) {
|
|
562
|
-
// Find first point with MD
|
|
563
|
-
for (const point of dataPoints) {
|
|
564
|
-
if (point.md !== undefined && point.md !== null) {
|
|
565
|
-
return point;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
// Try to interpolate MD between two closest points
|
|
570
|
-
if (closestIndex > 0 && closestIndex < dataPoints.length - 1) {
|
|
571
|
-
const prevPoint = dataPoints[closestIndex - 1];
|
|
572
|
-
const nextPoint = dataPoints[closestIndex + 1];
|
|
573
|
-
if (prevPoint.md !== undefined &&
|
|
574
|
-
nextPoint.md !== undefined &&
|
|
575
|
-
closestPoint.md === undefined) {
|
|
576
|
-
// Linear interpolation
|
|
577
|
-
const prevScaled = new THREE.Vector3(scale.x(prevPoint.x), scale.y(prevPoint.y), scale.z(prevPoint.z));
|
|
578
|
-
const nextScaled = new THREE.Vector3(scale.x(nextPoint.x), scale.y(nextPoint.y), scale.z(nextPoint.z));
|
|
579
|
-
const totalDist = prevScaled.distanceTo(nextScaled);
|
|
580
|
-
const distFromPrev = curvePoint.distanceTo(prevScaled);
|
|
581
|
-
const t = distFromPrev / totalDist;
|
|
582
|
-
const interpolatedMD = prevPoint.md + (nextPoint.md - prevPoint.md) * t;
|
|
583
|
-
return {
|
|
584
|
-
...closestPoint,
|
|
585
|
-
md: interpolatedMD,
|
|
586
|
-
};
|
|
587
639
|
}
|
|
588
640
|
}
|
|
589
641
|
return closestPoint;
|
|
@@ -665,7 +717,8 @@ class Chart3dComponent {
|
|
|
665
717
|
if (!data.points?.length) {
|
|
666
718
|
return;
|
|
667
719
|
}
|
|
668
|
-
const
|
|
720
|
+
const orderedDataPoints = [...data.points].sort((a, b) => (a.md ?? 0) - (b.md ?? 0));
|
|
721
|
+
const points = orderedDataPoints.map((_) => new THREE.Vector3(x(_.x), y(_.y), z(_.z)));
|
|
669
722
|
const color = d3.scaleOrdinal(d3.schemeTableau10);
|
|
670
723
|
const material = new THREE.MeshBasicMaterial({
|
|
671
724
|
color: data?.color ?? color(idx.toString()),
|
|
@@ -680,7 +733,7 @@ class Chart3dComponent {
|
|
|
680
733
|
series: data,
|
|
681
734
|
scale: { x, y, z },
|
|
682
735
|
curve: curve,
|
|
683
|
-
points:
|
|
736
|
+
points: orderedDataPoints,
|
|
684
737
|
});
|
|
685
738
|
});
|
|
686
739
|
const circles = x.ticks(this.SIDE_SIZE / 10);
|
|
@@ -951,8 +1004,8 @@ class Chart3dComponent {
|
|
|
951
1004
|
this._tooltipMarker.geometry.dispose();
|
|
952
1005
|
this._tooltipMarker.material.dispose();
|
|
953
1006
|
}
|
|
954
|
-
//
|
|
955
|
-
const pointOnCurve = this._tooltipService.
|
|
1007
|
+
// Closest point on curve (local helper, keep marker purely visual)
|
|
1008
|
+
const pointOnCurve = this._tooltipService.findClosestPointOnCurveLocal(intersectionPoint, curve);
|
|
956
1009
|
// Find parameter t for tangent calculation
|
|
957
1010
|
let closestT = 0;
|
|
958
1011
|
let minDistance = Infinity;
|