coordinate-system 2.5.4__cp313-cp313-win_amd64.whl → 2.5.5__cp313-cp313-win_amd64.whl
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.
- coordinate_system/coordinate_system.cp313-win_amd64.pyd +0 -0
- coordinate_system/curvature.py +72 -237
- coordinate_system/differential_geometry.py +90 -105
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.5.dist-info}/METADATA +1 -1
- coordinate_system-2.5.5.dist-info/RECORD +9 -0
- coordinate_system/coord3_wrapper.py +0 -300
- coordinate_system-2.5.4.dist-info/RECORD +0 -10
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.5.dist-info}/LICENSE +0 -0
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.5.dist-info}/WHEEL +0 -0
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.5.dist-info}/top_level.txt +0 -0
|
Binary file
|
coordinate_system/curvature.py
CHANGED
|
@@ -18,26 +18,17 @@ Methods Available:
|
|
|
18
18
|
1. Classical Method: First/Second Fundamental Forms + 5-point finite differences
|
|
19
19
|
- Precision: O(h⁴) convergence, typical error < 0.001%
|
|
20
20
|
|
|
21
|
-
2. Intrinsic Gradient Operator Method: G_μ = (c(u+h) - c(u))/
|
|
21
|
+
2. Intrinsic Gradient Operator Method: G_μ = (c(u+h) - c(u-h)) / (2h)
|
|
22
22
|
- Based on coordinate system changes analysis
|
|
23
23
|
- Numerically stable and geometrically intuitive
|
|
24
24
|
|
|
25
25
|
Author: PanGuoJun
|
|
26
|
-
Version: 2.4.0
|
|
27
|
-
Date: 2025-10-30
|
|
28
26
|
"""
|
|
29
27
|
|
|
30
28
|
import numpy as np
|
|
31
29
|
from typing import Tuple, Optional, Dict, List, Callable, Union
|
|
32
|
-
from .differential_geometry import Surface
|
|
30
|
+
from .differential_geometry import Surface, MetricTensor, IntrinsicGradientOperator, IntrinsicGradientCurvatureCalculator
|
|
33
31
|
from .coordinate_system import coord3, vec3
|
|
34
|
-
from .differential_geometry import (
|
|
35
|
-
MetricTensor,
|
|
36
|
-
IntrinsicGradientOperator,
|
|
37
|
-
IntrinsicGradientCurvatureCalculator,
|
|
38
|
-
compute_curvature_tensor as compute_curvature_tensor_lie,
|
|
39
|
-
compute_all_curvatures as compute_all_curvatures_intrinsic
|
|
40
|
-
)
|
|
41
32
|
|
|
42
33
|
|
|
43
34
|
# ========== High-Order Finite Difference Operators ==========
|
|
@@ -508,186 +499,75 @@ def all_curvatures(
|
|
|
508
499
|
return calc.compute_all_curvatures(u, v)
|
|
509
500
|
|
|
510
501
|
|
|
511
|
-
# ==========
|
|
502
|
+
# ========== Intrinsic Gradient Operator Method ==========
|
|
512
503
|
|
|
513
|
-
class
|
|
504
|
+
class IntrinsicGradientCurvatureCalculator:
|
|
514
505
|
"""
|
|
515
|
-
Curvature calculator using
|
|
516
|
-
|
|
517
|
-
This
|
|
518
|
-
through connection operators (frame derivatives) and Cartan structure equations.
|
|
519
|
-
|
|
520
|
-
Theory:
|
|
521
|
-
1. Construct intrinsic frame c(u,v) ∈ SO(3) (orthonormalized)
|
|
522
|
-
2. Construct embedding frame C(u,v) (preserving metric with scale vector)
|
|
523
|
-
3. Compute connection operator: G' = (c₂·c₁⁻¹)/C₂ - I/C₁
|
|
524
|
-
4. Apply corrections: G = scale × G' / √det(g)
|
|
525
|
-
5. Compute curvature tensor: Θ = [G_u, G_v] - G_{[u,v]}
|
|
526
|
-
6. Extract Gaussian curvature: K = Θ₁₂ / det(g)
|
|
527
|
-
|
|
528
|
-
Advantages:
|
|
529
|
-
- Eliminates parametrization dependence through intrinsic frames
|
|
530
|
-
- Natural handling of scale through coord3 Lie group structure
|
|
531
|
-
- Compatible with C++ optimized implementations
|
|
532
|
-
|
|
533
|
-
Comparison with Classical Method:
|
|
534
|
-
- Classical: Uses first/second fundamental forms directly
|
|
535
|
-
- Lie Group: Uses frame field derivatives (connection operators)
|
|
536
|
-
- Both methods converge to same result with proper corrections
|
|
506
|
+
Curvature calculator using the CORRECTED intrinsic gradient operator method
|
|
507
|
+
|
|
508
|
+
This uses the proven algorithm: G_μ = (c(u+h) - c(u-h)) / (2h) then extract .VZ()
|
|
537
509
|
"""
|
|
538
|
-
|
|
539
|
-
def __init__(
|
|
540
|
-
self,
|
|
541
|
-
surface: Surface,
|
|
542
|
-
step_size: float = 1e-3,
|
|
543
|
-
scale_factor: float = 2.0,
|
|
544
|
-
use_metric_correction: bool = True,
|
|
545
|
-
use_lie_derivative: bool = True
|
|
546
|
-
):
|
|
510
|
+
|
|
511
|
+
def __init__(self, surface: Surface, step_size: float = 1e-3):
|
|
547
512
|
"""
|
|
548
|
-
Initialize
|
|
513
|
+
Initialize intrinsic gradient curvature calculator
|
|
549
514
|
|
|
550
515
|
Args:
|
|
551
516
|
surface: Surface object
|
|
552
|
-
step_size:
|
|
553
|
-
scale_factor: Scaling factor for connection correction (default: 2.0, precomputed correction for self-referencing terms)
|
|
554
|
-
use_metric_correction: Whether to apply metric correction (default: True)
|
|
555
|
-
use_lie_derivative: Whether to include Lie derivative term (default: True)
|
|
556
|
-
Highly recommended for accuracy!
|
|
517
|
+
step_size: Step size for gradient computation (default 0.001)
|
|
557
518
|
"""
|
|
558
519
|
self.surface = surface
|
|
559
520
|
self.h = step_size
|
|
560
|
-
self.
|
|
561
|
-
self.use_metric_correction = use_metric_correction
|
|
562
|
-
self.use_lie_derivative = use_lie_derivative
|
|
521
|
+
self.grad_op = IntrinsicGradientOperator(surface, step_size)
|
|
563
522
|
|
|
564
523
|
def compute_gaussian_curvature(self, u: float, v: float) -> float:
|
|
565
524
|
"""
|
|
566
|
-
Compute Gaussian curvature using
|
|
567
|
-
|
|
568
|
-
Args:
|
|
569
|
-
u, v: Parameter coordinates
|
|
570
|
-
|
|
571
|
-
Returns:
|
|
572
|
-
Gaussian curvature K
|
|
573
|
-
|
|
574
|
-
Example:
|
|
575
|
-
>>> from coordinate_system import Sphere
|
|
576
|
-
>>> from coordinate_system.curvature import LieGroupCurvatureCalculator
|
|
577
|
-
>>> import math
|
|
578
|
-
>>>
|
|
579
|
-
>>> sphere = Sphere(radius=2.0)
|
|
580
|
-
>>> calc = LieGroupCurvatureCalculator(sphere)
|
|
581
|
-
>>> K = calc.compute_gaussian_curvature(math.pi/4, math.pi/6)
|
|
582
|
-
>>> print(f"K = {K:.6f}, Expected = 0.250000")
|
|
583
|
-
"""
|
|
584
|
-
# Temporarily set surface.h to match calculator's step size
|
|
585
|
-
original_h = self.surface.h
|
|
586
|
-
self.surface.h = self.h
|
|
587
|
-
|
|
588
|
-
try:
|
|
589
|
-
# Compute curvature tensor using connection operators
|
|
590
|
-
R_uv = compute_curvature_tensor_lie(
|
|
591
|
-
self.surface, u, v,
|
|
592
|
-
scale_factor=self.scale_factor,
|
|
593
|
-
use_metric_correction=self.use_metric_correction,
|
|
594
|
-
use_lie_derivative=self.use_lie_derivative
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
# Compute metric tensor
|
|
598
|
-
g = MetricTensor.from_surface(self.surface, u, v)
|
|
599
|
-
|
|
600
|
-
# Extract Gaussian curvature using antisymmetric part
|
|
601
|
-
# K = R_{12}^{antisym} / det(g) = (R_01 - R_10)/2 / det(g)
|
|
602
|
-
#
|
|
603
|
-
# R_uv is a coord3 representing the curvature tensor as a 3×3 matrix:
|
|
604
|
-
# R_uv.ux = [R_00, R_01, R_02] (first row)
|
|
605
|
-
# R_uv.uy = [R_10, R_11, R_12] (second row)
|
|
606
|
-
# R_uv.uz = [R_20, R_21, R_22] (third row)
|
|
607
|
-
#
|
|
608
|
-
# We need:
|
|
609
|
-
# R_01 = R_uv.ux.y (first row, second column)
|
|
610
|
-
# R_10 = R_uv.uy.x (second row, first column)
|
|
611
|
-
R_01 = R_uv.ux.y
|
|
612
|
-
R_10 = R_uv.uy.x
|
|
613
|
-
|
|
614
|
-
# Antisymmetric part extracts pure curvature (eliminates metric influence)
|
|
615
|
-
R_12_antisym = (R_01 - R_10) / 2.0
|
|
616
|
-
|
|
617
|
-
if abs(g.det) > 1e-14:
|
|
618
|
-
K = R_12_antisym / g.det
|
|
619
|
-
else:
|
|
620
|
-
K = 0.0
|
|
621
|
-
|
|
622
|
-
return K
|
|
623
|
-
finally:
|
|
624
|
-
# Restore original step size
|
|
625
|
-
self.surface.h = original_h
|
|
626
|
-
|
|
627
|
-
def compute_all_curvatures(self, u: float, v: float) -> Dict[str, Union[float, np.ndarray, coord3]]:
|
|
525
|
+
Compute Gaussian curvature using corrected intrinsic gradient method
|
|
628
526
|
"""
|
|
629
|
-
Compute
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
527
|
+
# Compute gradient operators using the proven central difference algorithm
|
|
528
|
+
G_u, G_v, _ = self.grad_op.compute_both(u, v)
|
|
529
|
+
|
|
530
|
+
# Compute tangent vectors
|
|
531
|
+
r_u = self.surface.tangent_u(u, v)
|
|
532
|
+
r_v = self.surface.tangent_v(u, v)
|
|
533
|
+
|
|
534
|
+
# Extract normal derivatives (already computed using correct algorithm)
|
|
535
|
+
dn_du = G_u.dn
|
|
536
|
+
dn_dv = G_v.dn
|
|
537
|
+
|
|
538
|
+
# Compute metric tensor
|
|
539
|
+
E = r_u.dot(r_u)
|
|
540
|
+
F = r_u.dot(r_v)
|
|
541
|
+
G = r_v.dot(r_v)
|
|
542
|
+
metric_det = E * G - F * F
|
|
543
|
+
|
|
544
|
+
# Compute second fundamental form
|
|
545
|
+
L = -dn_du.dot(r_u)
|
|
546
|
+
M1 = -dn_du.dot(r_v)
|
|
547
|
+
M2 = -dn_dv.dot(r_u)
|
|
548
|
+
N = -dn_dv.dot(r_v)
|
|
549
|
+
M = (M1 + M2) / 2.0
|
|
550
|
+
|
|
551
|
+
# Gaussian curvature
|
|
552
|
+
if abs(metric_det) > 1e-14:
|
|
553
|
+
K = (L * N - M * M) / metric_det
|
|
554
|
+
else:
|
|
555
|
+
K = 0.0
|
|
633
556
|
|
|
634
|
-
|
|
635
|
-
Dictionary containing:
|
|
636
|
-
- 'K': Gaussian curvature
|
|
637
|
-
- 'R_uv': Curvature tensor (coord3 object)
|
|
638
|
-
- 'G_u': Connection operator in u direction (coord3)
|
|
639
|
-
- 'G_v': Connection operator in v direction (coord3)
|
|
640
|
-
- 'g': Metric tensor (MetricTensor object)
|
|
641
|
-
- 'det_g': Metric determinant
|
|
557
|
+
return K
|
|
642
558
|
|
|
643
|
-
|
|
644
|
-
>>> calc = LieGroupCurvatureCalculator(sphere)
|
|
645
|
-
>>> result = calc.compute_all_curvatures(math.pi/4, math.pi/6)
|
|
646
|
-
>>> print(f"K = {result['K']:.6f}")
|
|
647
|
-
>>> print(f"det(g) = {result['det_g']:.6f}")
|
|
559
|
+
def compute_all_curvatures(self, u: float, v: float) -> dict:
|
|
648
560
|
"""
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
G_u, G_v = intrinsic_op.compute_both(u, v)
|
|
660
|
-
|
|
661
|
-
# Compute curvature tensor
|
|
662
|
-
R_uv = compute_curvature_tensor_lie(
|
|
663
|
-
self.surface, u, v,
|
|
664
|
-
scale_factor=self.scale_factor,
|
|
665
|
-
use_metric_correction=self.use_metric_correction,
|
|
666
|
-
use_lie_derivative=self.use_lie_derivative
|
|
667
|
-
)
|
|
668
|
-
|
|
669
|
-
# Compute metric
|
|
670
|
-
g = MetricTensor.from_surface(self.surface, u, v)
|
|
671
|
-
|
|
672
|
-
# Extract Gaussian curvature using antisymmetric part
|
|
673
|
-
# K = (R_01 - R_10)/2 / det(g)
|
|
674
|
-
R_01 = R_uv.ux.y
|
|
675
|
-
R_10 = R_uv.uy.x
|
|
676
|
-
R_12_antisym = (R_01 - R_10) / 2.0
|
|
677
|
-
K = R_12_antisym / g.det if abs(g.det) > 1e-14 else 0.0
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
'K': K,
|
|
681
|
-
'R_uv': R_uv,
|
|
682
|
-
'G_u': G_u,
|
|
683
|
-
'G_v': G_v,
|
|
684
|
-
'g': g,
|
|
685
|
-
'det_g': g.det,
|
|
686
|
-
'R_12_antisym': R_12_antisym
|
|
687
|
-
}
|
|
688
|
-
finally:
|
|
689
|
-
# Restore original step size
|
|
690
|
-
self.surface.h = original_h
|
|
561
|
+
Compute all curvature quantities using intrinsic gradient method
|
|
562
|
+
"""
|
|
563
|
+
K = self.compute_gaussian_curvature(u, v)
|
|
564
|
+
|
|
565
|
+
# For other curvatures, use the existing implementation
|
|
566
|
+
calc = IntrinsicGradientCurvatureCalculator(self.surface, self.h)
|
|
567
|
+
result = calc.compute_all_curvatures(u, v)
|
|
568
|
+
result['gaussian_curvature'] = K # Ensure our corrected K is used
|
|
569
|
+
|
|
570
|
+
return result
|
|
691
571
|
|
|
692
572
|
|
|
693
573
|
def compare_methods(
|
|
@@ -695,21 +575,21 @@ def compare_methods(
|
|
|
695
575
|
u: float,
|
|
696
576
|
v: float,
|
|
697
577
|
step_size_classical: float = 1e-3,
|
|
698
|
-
|
|
578
|
+
step_size_intrinsic: float = 1e-3
|
|
699
579
|
) -> Dict[str, float]:
|
|
700
580
|
"""
|
|
701
|
-
Compare classical and
|
|
581
|
+
Compare classical and intrinsic gradient curvature methods
|
|
702
582
|
|
|
703
583
|
Args:
|
|
704
584
|
surface: Surface object
|
|
705
585
|
u, v: Parameter coordinates
|
|
706
586
|
step_size_classical: Step size for classical method
|
|
707
|
-
|
|
587
|
+
step_size_intrinsic: Step size for intrinsic gradient method
|
|
708
588
|
|
|
709
589
|
Returns:
|
|
710
590
|
Dictionary with comparison results:
|
|
711
591
|
- 'K_classical': Gaussian curvature from classical method
|
|
712
|
-
- '
|
|
592
|
+
- 'K_intrinsic': Gaussian curvature from intrinsic gradient method
|
|
713
593
|
- 'difference': Absolute difference
|
|
714
594
|
- 'relative_error': Relative error (if K_classical != 0)
|
|
715
595
|
|
|
@@ -721,93 +601,53 @@ def compare_methods(
|
|
|
721
601
|
>>> sphere = Sphere(radius=2.0)
|
|
722
602
|
>>> result = compare_methods(sphere, math.pi/4, math.pi/6)
|
|
723
603
|
>>> print(f"Classical: K = {result['K_classical']:.8f}")
|
|
724
|
-
>>> print(f"
|
|
604
|
+
>>> print(f"Intrinsic: K = {result['K_intrinsic']:.8f}")
|
|
725
605
|
>>> print(f"Difference: {result['difference']:.2e}")
|
|
726
606
|
"""
|
|
727
607
|
# Classical method
|
|
728
608
|
calc_classical = CurvatureCalculator(surface, step_size_classical)
|
|
729
609
|
K_classical = calc_classical.compute_gaussian_curvature(u, v)
|
|
730
610
|
|
|
731
|
-
#
|
|
732
|
-
|
|
733
|
-
|
|
611
|
+
# Intrinsic gradient method
|
|
612
|
+
calc_intrinsic = IntrinsicGradientCurvatureCalculator(surface, step_size_intrinsic)
|
|
613
|
+
K_intrinsic = calc_intrinsic.compute_gaussian_curvature(u, v)
|
|
734
614
|
|
|
735
615
|
# Comparison
|
|
736
|
-
difference = abs(K_classical -
|
|
616
|
+
difference = abs(K_classical - K_intrinsic)
|
|
737
617
|
relative_error = difference / abs(K_classical) if abs(K_classical) > 1e-14 else 0.0
|
|
738
618
|
|
|
739
619
|
return {
|
|
740
620
|
'K_classical': K_classical,
|
|
741
|
-
'
|
|
621
|
+
'K_intrinsic': K_intrinsic,
|
|
742
622
|
'difference': difference,
|
|
743
623
|
'relative_error': relative_error
|
|
744
624
|
}
|
|
745
625
|
|
|
746
626
|
|
|
747
|
-
|
|
748
|
-
surface: Surface,
|
|
749
|
-
u: float,
|
|
750
|
-
v: float,
|
|
751
|
-
step_size: float = 1e-5,
|
|
752
|
-
scale_factor: float = 2.0,
|
|
753
|
-
use_metric_correction: bool = True,
|
|
754
|
-
use_lie_derivative: bool = True
|
|
755
|
-
) -> float:
|
|
756
|
-
"""
|
|
757
|
-
Compute Gaussian curvature using Lie group method (simplified interface)
|
|
758
|
-
|
|
759
|
-
Args:
|
|
760
|
-
surface: Surface object
|
|
761
|
-
u, v: Parameter coordinates
|
|
762
|
-
step_size: Finite difference step size (default: 1e-5)
|
|
763
|
-
scale_factor: Scaling factor for correction (default: 2.0)
|
|
764
|
-
use_metric_correction: Whether to apply metric correction
|
|
765
|
-
use_lie_derivative: Whether to include Lie derivative term
|
|
766
|
-
|
|
767
|
-
Returns:
|
|
768
|
-
Gaussian curvature K
|
|
769
|
-
|
|
770
|
-
Example:
|
|
771
|
-
>>> from coordinate_system import Sphere
|
|
772
|
-
>>> from coordinate_system.curvature import gaussian_curvature_lie
|
|
773
|
-
>>> import math
|
|
774
|
-
>>>
|
|
775
|
-
>>> sphere = Sphere(radius=2.0)
|
|
776
|
-
>>> K = gaussian_curvature_lie(sphere, math.pi/4, math.pi/6)
|
|
777
|
-
>>> print(f"K = {K:.6f}")
|
|
778
|
-
"""
|
|
779
|
-
calc = LieGroupCurvatureCalculator(
|
|
780
|
-
surface, step_size, scale_factor,
|
|
781
|
-
use_metric_correction, use_lie_derivative
|
|
782
|
-
)
|
|
783
|
-
return calc.compute_gaussian_curvature(u, v)
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
# ========== Intrinsic Gradient Operator Method ==========
|
|
787
|
-
# Now imported from differential_geometry module
|
|
788
|
-
from .differential_geometry import (
|
|
789
|
-
IntrinsicGradientOperator,
|
|
790
|
-
IntrinsicGradientCurvatureCalculator,
|
|
791
|
-
)
|
|
627
|
+
# ========== Convenience Functions for Intrinsic Gradient Method ==========
|
|
792
628
|
|
|
793
|
-
# Define convenience functions for backward compatibility
|
|
794
629
|
def intrinsic_gradient_gaussian_curvature(surface, u, v, step_size=1e-3):
|
|
630
|
+
"""Compute Gaussian curvature using intrinsic gradient method"""
|
|
795
631
|
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
796
632
|
return calc.compute_gaussian_curvature(u, v)
|
|
797
633
|
|
|
798
634
|
def intrinsic_gradient_mean_curvature(surface, u, v, step_size=1e-3):
|
|
635
|
+
"""Compute mean curvature using intrinsic gradient method"""
|
|
799
636
|
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
800
637
|
return calc.compute_mean_curvature(u, v)
|
|
801
638
|
|
|
802
639
|
def intrinsic_gradient_principal_curvatures(surface, u, v, step_size=1e-3):
|
|
640
|
+
"""Compute principal curvatures using intrinsic gradient method"""
|
|
803
641
|
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
804
642
|
result = calc.compute_all_curvatures(u, v)
|
|
805
643
|
return result['principal_curvatures']
|
|
806
644
|
|
|
807
645
|
def intrinsic_gradient_all_curvatures(surface, u, v, step_size=1e-3):
|
|
646
|
+
"""Compute all curvatures using intrinsic gradient method"""
|
|
808
647
|
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
809
648
|
return calc.compute_all_curvatures(u, v)
|
|
810
649
|
|
|
650
|
+
|
|
811
651
|
# ========== Export ==========
|
|
812
652
|
|
|
813
653
|
__all__ = [
|
|
@@ -818,21 +658,16 @@ __all__ = [
|
|
|
818
658
|
'principal_curvatures',
|
|
819
659
|
'all_curvatures',
|
|
820
660
|
|
|
821
|
-
# Lie group method
|
|
822
|
-
'LieGroupCurvatureCalculator',
|
|
823
|
-
'gaussian_curvature_lie',
|
|
824
|
-
'compare_methods',
|
|
825
|
-
|
|
826
661
|
# Intrinsic Gradient Operator method
|
|
827
|
-
'IntrinsicGradientOperator',
|
|
828
662
|
'IntrinsicGradientCurvatureCalculator',
|
|
829
663
|
'intrinsic_gradient_gaussian_curvature',
|
|
830
664
|
'intrinsic_gradient_mean_curvature',
|
|
831
665
|
'intrinsic_gradient_principal_curvatures',
|
|
832
666
|
'intrinsic_gradient_all_curvatures',
|
|
667
|
+
'compare_methods',
|
|
833
668
|
|
|
834
669
|
# Utility functions
|
|
835
670
|
'derivative_5pt',
|
|
836
671
|
'derivative_2nd_5pt',
|
|
837
672
|
'richardson_extrapolation',
|
|
838
|
-
]
|
|
673
|
+
]
|
|
@@ -6,11 +6,10 @@ This module provides tools for discrete differential geometry computations on su
|
|
|
6
6
|
using the CORRECT Intrinsic Gradient Operator framework based on the proven algorithm.
|
|
7
7
|
|
|
8
8
|
Key Formula:
|
|
9
|
-
G_μ = (c(u+h) - c(u)) /
|
|
10
|
-
where c is the embedding frame (NOT pure intrinsic frame)
|
|
9
|
+
G_μ = (c(u+h) - c(u-h)) / (2h) then extract normal derivative using .VZ()
|
|
11
10
|
|
|
12
11
|
Author: PanGuoJun
|
|
13
|
-
Version: 3.
|
|
12
|
+
Version: 3.3.0 (Corrected Intrinsic Gradient)
|
|
14
13
|
Date: 2025-10-31
|
|
15
14
|
"""
|
|
16
15
|
|
|
@@ -145,45 +144,14 @@ class MetricTensor:
|
|
|
145
144
|
return f"MetricTensor(E={self.E:.6f}, F={self.F:.6f}, G={self.G:.6f}, det={self.det:.6f})"
|
|
146
145
|
|
|
147
146
|
|
|
148
|
-
# ========== Helper Class for Embedding Frame ==========
|
|
149
|
-
|
|
150
|
-
class EmbeddingFrame:
|
|
151
|
-
"""
|
|
152
|
-
Helper class to represent embedding frame with metric information
|
|
153
|
-
This replaces complex coord3 operations for clarity
|
|
154
|
-
"""
|
|
155
|
-
|
|
156
|
-
def __init__(self, origin: vec3, e1: vec3, e2: vec3, n: vec3, s1: float, s2: float):
|
|
157
|
-
"""
|
|
158
|
-
Initialize embedding frame
|
|
159
|
-
|
|
160
|
-
Args:
|
|
161
|
-
origin: Position on surface
|
|
162
|
-
e1, e2: Orthonormal tangent vectors
|
|
163
|
-
n: Unit normal vector
|
|
164
|
-
s1, s2: Scale factors (lengths of original tangent vectors)
|
|
165
|
-
"""
|
|
166
|
-
self.origin = origin
|
|
167
|
-
self.e1 = e1
|
|
168
|
-
self.e2 = e2
|
|
169
|
-
self.n = n
|
|
170
|
-
self.s1 = s1
|
|
171
|
-
self.s2 = s2
|
|
172
|
-
|
|
173
|
-
def metric_det(self) -> float:
|
|
174
|
-
"""Compute metric determinant from scale factors"""
|
|
175
|
-
return self.s1 * self.s1 * self.s2 * self.s2
|
|
176
|
-
|
|
177
|
-
|
|
178
147
|
# ========== CORRECT Intrinsic Gradient Operator ==========
|
|
179
148
|
|
|
180
149
|
class IntrinsicGradientOperator:
|
|
181
150
|
"""
|
|
182
151
|
CORRECT Implementation of Intrinsic Gradient Operator
|
|
183
|
-
Based on proven formula: G_μ = (c(u+h) - c(u)) /
|
|
152
|
+
Based on proven formula: G_μ = (c(u+h) - c(u-h)) / (2h) then extract .VZ()
|
|
184
153
|
|
|
185
|
-
|
|
186
|
-
which is the core advantage of our coordinate system design.
|
|
154
|
+
This matches the validated algorithm from the working test code.
|
|
187
155
|
"""
|
|
188
156
|
|
|
189
157
|
def __init__(self, surface: Surface, step_size: float = 1e-3):
|
|
@@ -197,78 +165,89 @@ class IntrinsicGradientOperator:
|
|
|
197
165
|
self.surface = surface
|
|
198
166
|
self.h = step_size
|
|
199
167
|
|
|
200
|
-
def
|
|
168
|
+
def calc_intrinsic_frame(self, u: float, v: float) -> coord3:
|
|
201
169
|
"""
|
|
202
|
-
Calculate
|
|
203
|
-
|
|
170
|
+
Calculate intrinsic frame at point (u, v)
|
|
171
|
+
|
|
172
|
+
This matches the algorithm from the working test code:
|
|
173
|
+
- Compute position and tangent vectors
|
|
174
|
+
- Create orthonormal frame with unit vectors
|
|
175
|
+
- Return coord3 object for vector operations
|
|
204
176
|
"""
|
|
205
|
-
#
|
|
177
|
+
# Position vector
|
|
178
|
+
pos = self.surface.position(u, v)
|
|
179
|
+
|
|
180
|
+
# Tangent vectors
|
|
206
181
|
r_u = self.surface.tangent_u(u, v)
|
|
207
182
|
r_v = self.surface.tangent_v(u, v)
|
|
208
|
-
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
#
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
s1 = c.s.x # Scale from r_u
|
|
231
|
-
s2 = (r_v - e1 * r_v.dot(e1)).len() # Scale from r_v orthogonal component
|
|
232
|
-
|
|
233
|
-
return EmbeddingFrame(c.o, e1, e2, n, s1, s2)
|
|
234
|
-
|
|
235
|
-
def compute_both(self, u: float, v: float) -> Tuple['GradientResult', 'GradientResult']:
|
|
183
|
+
|
|
184
|
+
# Unit normal vector
|
|
185
|
+
n = r_u.cross(r_v).normalized()
|
|
186
|
+
|
|
187
|
+
# Unit tangent vectors
|
|
188
|
+
e1 = r_u.normalized()
|
|
189
|
+
e2 = r_v.normalized()
|
|
190
|
+
|
|
191
|
+
# Ensure orthonormality
|
|
192
|
+
e2_corrected = (e2 - e1 * e2.dot(e1)).normalized()
|
|
193
|
+
n_corrected = e1.cross(e2_corrected).normalized()
|
|
194
|
+
|
|
195
|
+
# Create intrinsic frame
|
|
196
|
+
frame = coord3()
|
|
197
|
+
frame.o = pos
|
|
198
|
+
frame.ux = e1
|
|
199
|
+
frame.uy = e2_corrected
|
|
200
|
+
frame.uz = n_corrected
|
|
201
|
+
|
|
202
|
+
return frame
|
|
203
|
+
|
|
204
|
+
def compute_both(self, u: float, v: float) -> Tuple['GradientResult', 'GradientResult', coord3]:
|
|
236
205
|
"""
|
|
237
|
-
Compute intrinsic gradient operators in both directions
|
|
238
|
-
|
|
206
|
+
Compute intrinsic gradient operators in both directions using CENTRAL DIFFERENCES
|
|
207
|
+
|
|
208
|
+
This implements the proven algorithm:
|
|
209
|
+
dn_du = ((c(u+h) - c(u-h)) / (2h)).VZ()
|
|
239
210
|
"""
|
|
240
|
-
# Compute frames
|
|
241
|
-
c_center = self.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
211
|
+
# Compute frames using central differences (like the working test code)
|
|
212
|
+
c_center = self.calc_intrinsic_frame(u, v)
|
|
213
|
+
|
|
214
|
+
# u-direction: central difference
|
|
215
|
+
c_u_plus = self.calc_intrinsic_frame(u + self.h, v)
|
|
216
|
+
c_u_minus = self.calc_intrinsic_frame(u - self.h, v)
|
|
217
|
+
dn_du = ((c_u_plus - c_u_minus) / (2 * self.h)).VZ()
|
|
218
|
+
|
|
219
|
+
# v-direction: central difference
|
|
220
|
+
c_v_plus = self.calc_intrinsic_frame(u, v + self.h)
|
|
221
|
+
c_v_minus = self.calc_intrinsic_frame(u, v - self.h)
|
|
222
|
+
dn_dv = ((c_v_plus - c_v_minus) / (2 * self.h)).VZ()
|
|
223
|
+
|
|
224
|
+
# Create gradient results
|
|
225
|
+
G_u = GradientResult(dn_du, "u")
|
|
226
|
+
G_v = GradientResult(dn_dv, "v")
|
|
227
|
+
|
|
249
228
|
return G_u, G_v, c_center
|
|
250
229
|
|
|
251
230
|
|
|
252
231
|
class GradientResult:
|
|
253
232
|
"""
|
|
254
|
-
|
|
233
|
+
Gradient result containing normal vector derivative
|
|
234
|
+
|
|
235
|
+
Simplified version that directly stores the computed derivative
|
|
255
236
|
"""
|
|
256
237
|
|
|
257
|
-
def __init__(self,
|
|
238
|
+
def __init__(self, dn: vec3, direction: str):
|
|
258
239
|
"""
|
|
259
|
-
|
|
240
|
+
Initialize gradient result
|
|
260
241
|
|
|
261
242
|
Args:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
h: Step size
|
|
243
|
+
dn: Normal vector derivative (computed using proven algorithm)
|
|
244
|
+
direction: Parameter direction ('u' or 'v')
|
|
265
245
|
"""
|
|
266
|
-
|
|
267
|
-
self.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
)
|
|
246
|
+
self.dn = dn
|
|
247
|
+
self.direction = direction
|
|
248
|
+
|
|
249
|
+
def __repr__(self) -> str:
|
|
250
|
+
return f"GradientResult({self.direction}: [{self.dn.x:.6f}, {self.dn.y:.6f}, {self.dn.z:.6f}])"
|
|
272
251
|
|
|
273
252
|
|
|
274
253
|
# ========== Curvature Calculator ==========
|
|
@@ -296,26 +275,28 @@ class IntrinsicGradientCurvatureCalculator:
|
|
|
296
275
|
|
|
297
276
|
Formula: K = (LN - M²) / det(g)
|
|
298
277
|
"""
|
|
299
|
-
# Compute gradient operators
|
|
300
|
-
G_u, G_v,
|
|
301
|
-
|
|
302
|
-
# Get metric determinant
|
|
303
|
-
metric_det = c_center.metric_det()
|
|
278
|
+
# Compute gradient operators using the proven algorithm
|
|
279
|
+
G_u, G_v, _ = self.grad_op.compute_both(u, v)
|
|
304
280
|
|
|
305
281
|
# Compute tangent vectors
|
|
306
282
|
r_u = self.surface.tangent_u(u, v)
|
|
307
283
|
r_v = self.surface.tangent_v(u, v)
|
|
308
284
|
|
|
309
|
-
# Extract normal derivatives
|
|
285
|
+
# Extract normal derivatives (already computed using correct algorithm)
|
|
310
286
|
dn_du = G_u.dn
|
|
311
287
|
dn_dv = G_v.dn
|
|
312
288
|
|
|
289
|
+
# Compute metric tensor
|
|
290
|
+
E = r_u.dot(r_u)
|
|
291
|
+
F = r_u.dot(r_v)
|
|
292
|
+
G = r_v.dot(r_v)
|
|
293
|
+
metric_det = E * G - F * F
|
|
294
|
+
|
|
313
295
|
# Compute second fundamental form
|
|
314
296
|
L = -dn_du.dot(r_u) # -<dn/du, r_u>
|
|
315
297
|
M1 = -dn_du.dot(r_v) # -<dn/du, r_v>
|
|
316
298
|
M2 = -dn_dv.dot(r_u) # -<dn/dv, r_u>
|
|
317
299
|
N = -dn_dv.dot(r_v) # -<dn/dv, r_v>
|
|
318
|
-
|
|
319
300
|
M = (M1 + M2) / 2.0 # Symmetrize
|
|
320
301
|
|
|
321
302
|
# Gaussian curvature
|
|
@@ -335,7 +316,7 @@ class IntrinsicGradientCurvatureCalculator:
|
|
|
335
316
|
# Compute gradient operators
|
|
336
317
|
G_u, G_v, _ = self.grad_op.compute_both(u, v)
|
|
337
318
|
|
|
338
|
-
# Compute metric
|
|
319
|
+
# Compute tangent vectors and metric
|
|
339
320
|
r_u = self.surface.tangent_u(u, v)
|
|
340
321
|
r_v = self.surface.tangent_v(u, v)
|
|
341
322
|
E = r_u.dot(r_u)
|
|
@@ -489,17 +470,21 @@ def compute_intrinsic_gradient(
|
|
|
489
470
|
GradientResult object
|
|
490
471
|
"""
|
|
491
472
|
grad_op = IntrinsicGradientOperator(surface, step_size)
|
|
492
|
-
|
|
493
|
-
c_center = grad_op.calc_embedding_frame(u, v)
|
|
494
|
-
|
|
473
|
+
|
|
495
474
|
if direction == 'u':
|
|
496
|
-
|
|
475
|
+
# Compute central difference for u direction
|
|
476
|
+
c_plus = grad_op.calc_intrinsic_frame(u + step_size, v)
|
|
477
|
+
c_minus = grad_op.calc_intrinsic_frame(u - step_size, v)
|
|
478
|
+
dn = ((c_plus - c_minus) / (2 * step_size)).VZ()
|
|
497
479
|
elif direction == 'v':
|
|
498
|
-
|
|
480
|
+
# Compute central difference for v direction
|
|
481
|
+
c_plus = grad_op.calc_intrinsic_frame(u, v + step_size)
|
|
482
|
+
c_minus = grad_op.calc_intrinsic_frame(u, v - step_size)
|
|
483
|
+
dn = ((c_plus - c_minus) / (2 * step_size)).VZ()
|
|
499
484
|
else:
|
|
500
485
|
raise ValueError(f"direction must be 'u' or 'v', got: {direction}")
|
|
501
486
|
|
|
502
|
-
return GradientResult(
|
|
487
|
+
return GradientResult(dn, direction)
|
|
503
488
|
|
|
504
489
|
|
|
505
490
|
# ========== Backward Compatibility (DEPRECATED) ==========
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: coordinate_system
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.5
|
|
4
4
|
Summary: High-performance 3D coordinate system library with Intrinsic Gradient Operator method for curvature computation, achieving machine-precision accuracy
|
|
5
5
|
Home-page: https://github.com/panguojun/Coordinate-System
|
|
6
6
|
Author: PanGuoJun
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
coordinate_system/__init__.py,sha256=wDY6E9q4mzfeLWqhVd7sakzmHXUXIoV8o1BG4THlKHI,7858
|
|
2
|
+
coordinate_system/coordinate_system.cp313-win_amd64.pyd,sha256=5H6KLnWa6TN5Pb8UhwzZZ14dNbVIOrQ8mO4SbU0O3Jw,497152
|
|
3
|
+
coordinate_system/curvature.py,sha256=O1IJBC2TdS38tZ0T9DAuIIugvCqgJjHKNGwsmlQl5Hw,21737
|
|
4
|
+
coordinate_system/differential_geometry.py,sha256=_DtJQ60thyE9eM0tFzmsnoyUbaf6uw8g0UAZeBN3RcM,14981
|
|
5
|
+
coordinate_system-2.5.5.dist-info/LICENSE,sha256=tDnRkJxBYPzWdfh2gArRqrUPJxQZRZHJVs68qqBHIq4,1083
|
|
6
|
+
coordinate_system-2.5.5.dist-info/METADATA,sha256=_04i-WzKPln695kKCPDfY3IrHOx48FBYSshg9uSNJZI,19428
|
|
7
|
+
coordinate_system-2.5.5.dist-info/WHEEL,sha256=4-iQBlRoDdX1wfPofc7KLWa5Cys4eZSgXs6GVU8fKlQ,101
|
|
8
|
+
coordinate_system-2.5.5.dist-info/top_level.txt,sha256=R6LguuPPZ5esrIsDTqPGi9UxCvZPIXwn7KRKX87c79M,18
|
|
9
|
+
coordinate_system-2.5.5.dist-info/RECORD,,
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Coord3 Wrapper for Intrinsic Gradient Operator
|
|
3
|
-
===============================================
|
|
4
|
-
|
|
5
|
-
This module provides a Python wrapper for coord3 that correctly implements
|
|
6
|
-
the mathematical operations needed for the intrinsic gradient operator.
|
|
7
|
-
|
|
8
|
-
Key insight: Use coord3's normalize() to separate rotation and scaling,
|
|
9
|
-
which is a core advantage of our coordinate system design over matrices.
|
|
10
|
-
|
|
11
|
-
Solution: Implement subtraction that properly handles the rotation-scale separation.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import numpy as np
|
|
15
|
-
from .coordinate_system import coord3 as _coord3, vec3
|
|
16
|
-
import math
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class Coord3Wrapper:
|
|
20
|
-
"""
|
|
21
|
-
Wrapper for coord3 that implements correct arithmetic for gradient operators
|
|
22
|
-
|
|
23
|
-
The intrinsic gradient operator requires:
|
|
24
|
-
G_μ = (c(u+h) - c(u)) / h
|
|
25
|
-
|
|
26
|
-
This implementation leverages coord3's ability to separate rotation and scaling.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
def __init__(self, coord3_obj=None):
|
|
30
|
-
"""
|
|
31
|
-
Initialize from a coord3 object or create new
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
coord3_obj: Original coord3 object from C++ binding
|
|
35
|
-
"""
|
|
36
|
-
if coord3_obj is None:
|
|
37
|
-
self._c3 = _coord3()
|
|
38
|
-
else:
|
|
39
|
-
self._c3 = coord3_obj
|
|
40
|
-
# Ensure normalization to separate rotation and scale
|
|
41
|
-
self.normalize_axes()
|
|
42
|
-
|
|
43
|
-
def normalize_axes(self):
|
|
44
|
-
"""
|
|
45
|
-
Normalize axes and extract scale factors
|
|
46
|
-
|
|
47
|
-
This is the key operation that separates rotation from scaling,
|
|
48
|
-
which is the core advantage of coord3 over matrix representations.
|
|
49
|
-
"""
|
|
50
|
-
# Extract scale factors from current axes
|
|
51
|
-
sx = math.sqrt(self._c3.ux.dot(self._c3.ux))
|
|
52
|
-
sy = math.sqrt(self._c3.uy.dot(self._c3.uy))
|
|
53
|
-
sz = math.sqrt(self._c3.uz.dot(self._c3.uz))
|
|
54
|
-
|
|
55
|
-
# Normalize axes (pure rotation)
|
|
56
|
-
if sx > 1e-10:
|
|
57
|
-
self._c3.ux = self._c3.ux / sx
|
|
58
|
-
if sy > 1e-10:
|
|
59
|
-
self._c3.uy = self._c3.uy / sy
|
|
60
|
-
if sz > 1e-10:
|
|
61
|
-
self._c3.uz = self._c3.uz / sz
|
|
62
|
-
|
|
63
|
-
# Store scale factors separately
|
|
64
|
-
self._c3.s = vec3(sx, sy, sz)
|
|
65
|
-
|
|
66
|
-
@property
|
|
67
|
-
def o(self):
|
|
68
|
-
"""Origin/position"""
|
|
69
|
-
return self._c3.o
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def ux(self):
|
|
73
|
-
"""X axis direction (unit vector)"""
|
|
74
|
-
return self._c3.ux
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def uy(self):
|
|
78
|
-
"""Y axis direction (unit vector)"""
|
|
79
|
-
return self._c3.uy
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def uz(self):
|
|
83
|
-
"""Z axis direction (unit vector)"""
|
|
84
|
-
return self._c3.uz
|
|
85
|
-
|
|
86
|
-
@property
|
|
87
|
-
def s(self):
|
|
88
|
-
"""Scale factors"""
|
|
89
|
-
return self._c3.s
|
|
90
|
-
|
|
91
|
-
def VX(self):
|
|
92
|
-
"""Scaled X axis = ux * s.x"""
|
|
93
|
-
return vec3(
|
|
94
|
-
self.ux.x * self.s.x,
|
|
95
|
-
self.ux.y * self.s.x,
|
|
96
|
-
self.ux.z * self.s.x
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
def VY(self):
|
|
100
|
-
"""Scaled Y axis = uy * s.y"""
|
|
101
|
-
return vec3(
|
|
102
|
-
self.uy.x * self.s.y,
|
|
103
|
-
self.uy.y * self.s.y,
|
|
104
|
-
self.uy.z * self.s.y
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
def VZ(self):
|
|
108
|
-
"""Scaled Z axis = uz * s.z"""
|
|
109
|
-
return vec3(
|
|
110
|
-
self.uz.x * self.s.z,
|
|
111
|
-
self.uz.y * self.s.z,
|
|
112
|
-
self.uz.z * self.s.z
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
def __sub__(self, other):
|
|
116
|
-
"""
|
|
117
|
-
Subtraction for gradient operator with proper rotation-scale separation
|
|
118
|
-
|
|
119
|
-
This leverages coord3's design advantage:
|
|
120
|
-
1. Both frames are normalized (rotation and scale separated)
|
|
121
|
-
2. Compute differences in rotation (unit vectors)
|
|
122
|
-
3. Compute differences in scale (scale factors)
|
|
123
|
-
4. Keep them separated for proper gradient computation
|
|
124
|
-
"""
|
|
125
|
-
result = Coord3Wrapper()
|
|
126
|
-
|
|
127
|
-
# Ensure both frames are normalized
|
|
128
|
-
self.normalize_axes()
|
|
129
|
-
if isinstance(other, Coord3Wrapper):
|
|
130
|
-
other.normalize_axes()
|
|
131
|
-
|
|
132
|
-
# Origin difference
|
|
133
|
-
result._c3.o = self.o - other.o
|
|
134
|
-
|
|
135
|
-
# Rotation differences (unit vectors)
|
|
136
|
-
result._c3.ux = self.ux - other.ux
|
|
137
|
-
result._c3.uy = self.uy - other.uy
|
|
138
|
-
result._c3.uz = self.uz - other.uz
|
|
139
|
-
|
|
140
|
-
# Scale differences (kept separate)
|
|
141
|
-
result._c3.s = self.s - other.s
|
|
142
|
-
|
|
143
|
-
return result
|
|
144
|
-
|
|
145
|
-
def __truediv__(self, scalar):
|
|
146
|
-
"""
|
|
147
|
-
Division by scalar for gradient operator
|
|
148
|
-
|
|
149
|
-
Used in G_μ = (c(u+h) - c(u)) / h
|
|
150
|
-
"""
|
|
151
|
-
if isinstance(scalar, (int, float)):
|
|
152
|
-
result = Coord3Wrapper()
|
|
153
|
-
|
|
154
|
-
# Divide all components by scalar
|
|
155
|
-
result._c3.o = self.o / scalar
|
|
156
|
-
result._c3.ux = self.ux / scalar
|
|
157
|
-
result._c3.uy = self.uy / scalar
|
|
158
|
-
result._c3.uz = self.uz / scalar
|
|
159
|
-
result._c3.s = self.s / scalar
|
|
160
|
-
|
|
161
|
-
return result
|
|
162
|
-
else:
|
|
163
|
-
raise TypeError(f"Division only supported by scalar, got {type(scalar)}")
|
|
164
|
-
|
|
165
|
-
def compute_metric_det(self):
|
|
166
|
-
"""
|
|
167
|
-
Compute determinant of metric tensor for 2D surface
|
|
168
|
-
|
|
169
|
-
For a surface parametrized by (u,v):
|
|
170
|
-
g = [[E, F], [F, G]]
|
|
171
|
-
where E = |∂r/∂u|², F = ∂r/∂u · ∂r/∂v, G = |∂r/∂v|²
|
|
172
|
-
|
|
173
|
-
Returns:
|
|
174
|
-
det(g) = E*G - F²
|
|
175
|
-
"""
|
|
176
|
-
# Get scaled tangent vectors
|
|
177
|
-
vx = self.VX() # ∂r/∂u direction
|
|
178
|
-
vy = self.VY() # ∂r/∂v direction
|
|
179
|
-
|
|
180
|
-
# First fundamental form coefficients
|
|
181
|
-
E = vx.dot(vx) # g_uu
|
|
182
|
-
F = vx.dot(vy) # g_uv
|
|
183
|
-
G = vy.dot(vy) # g_vv
|
|
184
|
-
|
|
185
|
-
# Determinant
|
|
186
|
-
return E * G - F * F
|
|
187
|
-
|
|
188
|
-
def to_coord3(self):
|
|
189
|
-
"""Convert back to original coord3"""
|
|
190
|
-
return self._c3
|
|
191
|
-
|
|
192
|
-
@classmethod
|
|
193
|
-
def from_surface_frame(cls, surface, u, v, compute_frame_func):
|
|
194
|
-
"""
|
|
195
|
-
Create from surface using frame computation function
|
|
196
|
-
|
|
197
|
-
Args:
|
|
198
|
-
surface: Surface object
|
|
199
|
-
u, v: Parameters
|
|
200
|
-
compute_frame_func: Function to compute embedding frame
|
|
201
|
-
|
|
202
|
-
Returns:
|
|
203
|
-
Coord3Wrapper with proper metric information
|
|
204
|
-
"""
|
|
205
|
-
frame = compute_frame_func(surface, u, v)
|
|
206
|
-
return cls(frame)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def create_embedding_frame_with_normalize(surface, u, v):
|
|
210
|
-
"""
|
|
211
|
-
Create embedding frame for surface at point (u,v) using coord3's normalize
|
|
212
|
-
|
|
213
|
-
This implementation leverages coord3's design advantage:
|
|
214
|
-
1. Compute tangent vectors r_u, r_v
|
|
215
|
-
2. Build initial frame with scaled axes
|
|
216
|
-
3. Use normalize() to separate rotation and scaling
|
|
217
|
-
4. Apply Gram-Schmidt in the normalized space
|
|
218
|
-
5. Preserve metric information in scale factors
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
coord3 with proper embedding frame (rotation and scale separated)
|
|
222
|
-
"""
|
|
223
|
-
# Get position
|
|
224
|
-
pos = surface.position(u, v)
|
|
225
|
-
|
|
226
|
-
# Compute tangent vectors using finite differences
|
|
227
|
-
h = 1e-6
|
|
228
|
-
pos_u_plus = surface.position(u + h, v)
|
|
229
|
-
pos_u_minus = surface.position(u - h, v)
|
|
230
|
-
r_u = (pos_u_plus - pos_u_minus) / (2 * h)
|
|
231
|
-
|
|
232
|
-
pos_v_plus = surface.position(u, v + h)
|
|
233
|
-
pos_v_minus = surface.position(u, v - h)
|
|
234
|
-
r_v = (pos_v_plus - pos_v_minus) / (2 * h)
|
|
235
|
-
|
|
236
|
-
# Create initial frame with tangent vectors (not normalized)
|
|
237
|
-
c = _coord3()
|
|
238
|
-
c.o = pos
|
|
239
|
-
c.ux = r_u # Will be normalized later
|
|
240
|
-
c.uy = r_v # Will be normalized later
|
|
241
|
-
|
|
242
|
-
# Compute initial normal (may not be unit)
|
|
243
|
-
n = r_u.cross(r_v)
|
|
244
|
-
c.uz = n
|
|
245
|
-
|
|
246
|
-
# Use coord3's normalize to separate rotation and scale
|
|
247
|
-
# This automatically extracts scale factors and normalizes axes
|
|
248
|
-
c.normalize() # This is the key operation!
|
|
249
|
-
|
|
250
|
-
# Now apply Gram-Schmidt to ensure orthogonality
|
|
251
|
-
# (while preserving the extracted scale factors)
|
|
252
|
-
|
|
253
|
-
# Get current scale factors (preserved from normalize)
|
|
254
|
-
s1 = c.s.x
|
|
255
|
-
s2 = c.s.y
|
|
256
|
-
s3 = c.s.z
|
|
257
|
-
|
|
258
|
-
# Gram-Schmidt on normalized axes
|
|
259
|
-
e1 = c.ux # Already normalized
|
|
260
|
-
|
|
261
|
-
# Orthogonalize e2 against e1
|
|
262
|
-
e2_temp = c.uy - e1 * c.uy.dot(e1)
|
|
263
|
-
e2_len = math.sqrt(e2_temp.dot(e2_temp))
|
|
264
|
-
if e2_len > 1e-10:
|
|
265
|
-
e2 = e2_temp / e2_len
|
|
266
|
-
else:
|
|
267
|
-
# Degenerate case: create orthogonal vector
|
|
268
|
-
if abs(e1.x) < 0.9:
|
|
269
|
-
e2 = vec3(1, 0, 0) - e1 * e1.x
|
|
270
|
-
else:
|
|
271
|
-
e2 = vec3(0, 1, 0) - e1 * e1.y
|
|
272
|
-
e2 = e2.normalized()
|
|
273
|
-
|
|
274
|
-
# Compute orthogonal normal
|
|
275
|
-
e3 = e1.cross(e2)
|
|
276
|
-
e3_len = math.sqrt(e3.dot(e3))
|
|
277
|
-
if e3_len > 1e-10:
|
|
278
|
-
e3 = e3 / e3_len
|
|
279
|
-
else:
|
|
280
|
-
e3 = vec3(0, 0, 1)
|
|
281
|
-
|
|
282
|
-
# Update frame with orthonormal axes
|
|
283
|
-
c.ux = e1
|
|
284
|
-
c.uy = e2
|
|
285
|
-
c.uz = e3
|
|
286
|
-
|
|
287
|
-
# Preserve the original scale factors (metric information)
|
|
288
|
-
# This is crucial for curvature computation
|
|
289
|
-
c.s = vec3(s1, s2, 1.0)
|
|
290
|
-
|
|
291
|
-
return c
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def create_embedding_frame(surface, u, v):
|
|
295
|
-
"""
|
|
296
|
-
Create embedding frame for surface - backward compatibility wrapper
|
|
297
|
-
|
|
298
|
-
Calls the new implementation that uses normalize().
|
|
299
|
-
"""
|
|
300
|
-
return create_embedding_frame_with_normalize(surface, u, v)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
coordinate_system/__init__.py,sha256=wDY6E9q4mzfeLWqhVd7sakzmHXUXIoV8o1BG4THlKHI,7858
|
|
2
|
-
coordinate_system/coord3_wrapper.py,sha256=d7zi-i0MuNqqN0rAIOo8aoVxOB4Xl4OadmMCG_CpemE,8946
|
|
3
|
-
coordinate_system/coordinate_system.cp313-win_amd64.pyd,sha256=NnAuMCQTuk6dGENjeZEK0q8Hnem10kP64RVGovN4_ds,497664
|
|
4
|
-
coordinate_system/curvature.py,sha256=OEZwTKmuDRwLP1k503oURIBmZtdG70EFlu4Mr-pNjlg,27735
|
|
5
|
-
coordinate_system/differential_geometry.py,sha256=3Pe1JgzW7hY8zVOTARhQmA5d2YUdEK3eeKOgpCpsoo4,15306
|
|
6
|
-
coordinate_system-2.5.4.dist-info/LICENSE,sha256=tDnRkJxBYPzWdfh2gArRqrUPJxQZRZHJVs68qqBHIq4,1083
|
|
7
|
-
coordinate_system-2.5.4.dist-info/METADATA,sha256=Fsc22TPnLnqLllhhtyj_H5FnKoY8p62LTYqJs53Omtw,19428
|
|
8
|
-
coordinate_system-2.5.4.dist-info/WHEEL,sha256=4-iQBlRoDdX1wfPofc7KLWa5Cys4eZSgXs6GVU8fKlQ,101
|
|
9
|
-
coordinate_system-2.5.4.dist-info/top_level.txt,sha256=R6LguuPPZ5esrIsDTqPGi9UxCvZPIXwn7KRKX87c79M,18
|
|
10
|
-
coordinate_system-2.5.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|