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.
@@ -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))/h
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
- # ========== Lie Group Method ==========
502
+ # ========== Intrinsic Gradient Operator Method ==========
512
503
 
513
- class LieGroupCurvatureCalculator:
504
+ class IntrinsicGradientCurvatureCalculator:
514
505
  """
515
- Curvature calculator using Lie group frame field method
516
-
517
- This method uses coord3 Lie group operations to compute curvature
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 Lie group curvature calculator
513
+ Initialize intrinsic gradient curvature calculator
549
514
 
550
515
  Args:
551
516
  surface: Surface object
552
- step_size: Finite difference step size (default: 1e-3, optimal for O(h²) convergence)
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.scale_factor = scale_factor
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 Lie group method
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 curvature and related quantities using Lie group method
630
-
631
- Args:
632
- u, v: Parameter coordinates
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
- Returns:
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
- Example:
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
- # Temporarily set surface.h to match calculator's step size
650
- original_h = self.surface.h
651
- self.surface.h = self.h
652
-
653
- try:
654
- # Compute intrinsic gradient operators
655
- intrinsic_op = IntrinsicGradientOperator(
656
- self.surface,
657
- self.h
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
- step_size_lie: float = 1e-5
578
+ step_size_intrinsic: float = 1e-3
699
579
  ) -> Dict[str, float]:
700
580
  """
701
- Compare classical and Lie group curvature methods
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
- step_size_lie: Step size for Lie group method
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
- - 'K_lie': Gaussian curvature from Lie group method
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"Lie Group: K = {result['K_lie']:.8f}")
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
- # Lie group method
732
- calc_lie = LieGroupCurvatureCalculator(surface, step_size_lie)
733
- K_lie = calc_lie.compute_gaussian_curvature(u, v)
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 - K_lie)
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
- 'K_lie': K_lie,
621
+ 'K_intrinsic': K_intrinsic,
742
622
  'difference': difference,
743
623
  'relative_error': relative_error
744
624
  }
745
625
 
746
626
 
747
- def gaussian_curvature_lie(
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)) / h
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.2.0 (Fixed)
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)) / h
152
+ Based on proven formula: G_μ = (c(u+h) - c(u-h)) / (2h) then extract .VZ()
184
153
 
185
- Key insight: Use coord3's normalize() to separate rotation and scaling,
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 calc_embedding_frame(self, u: float, v: float) -> EmbeddingFrame:
168
+ def calc_intrinsic_frame(self, u: float, v: float) -> coord3:
201
169
  """
202
- Calculate embedding frame at point (u, v) using coord3's normalize
203
- CRITICAL: Leverages coord3's ability to separate rotation and scaling
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
- # Get tangent vectors
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
- # Create coord3 frame with tangent vectors (not normalized yet)
210
- c = coord3()
211
- c.o = self.surface.position(u, v)
212
- c.ux = r_u
213
- c.uy = r_v
214
- c.uz = r_u.cross(r_v)
215
-
216
- # Use coord3's normalize to separate rotation and scale
217
- # This is the KEY operation that separates our design from matrices!
218
- c.normalize(False) # False = don't normalize scale factors
219
-
220
- # Now c.ux, c.uy, c.uz are unit vectors
221
- # and c.s contains the original scales
222
-
223
- # Apply Gram-Schmidt for orthogonality while preserving scales
224
- e1 = c.ux
225
- e2_temp = c.uy - e1 * c.uy.dot(e1)
226
- e2 = e2_temp.normcopy()
227
- n = e1.cross(e2).normcopy()
228
-
229
- # Get the scale factors (metric information)
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
- Returns simplified gradient results containing only necessary information
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.calc_embedding_frame(u, v)
242
- c_u_plus = self.calc_embedding_frame(u + self.h, v)
243
- c_v_plus = self.calc_embedding_frame(u, v + self.h)
244
-
245
- # Compute gradient operators: G_μ = (c(u+h) - c(u)) / h
246
- G_u = GradientResult(c_center, c_u_plus, self.h)
247
- G_v = GradientResult(c_center, c_v_plus, self.h)
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
- Simplified gradient result containing normal vector derivative
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, c_center: EmbeddingFrame, c_shifted: EmbeddingFrame, h: float):
238
+ def __init__(self, dn: vec3, direction: str):
258
239
  """
259
- Compute gradient from two frames
240
+ Initialize gradient result
260
241
 
261
242
  Args:
262
- c_center: Frame at center point
263
- c_shifted: Frame at shifted point
264
- h: Step size
243
+ dn: Normal vector derivative (computed using proven algorithm)
244
+ direction: Parameter direction ('u' or 'v')
265
245
  """
266
- # Compute normal vector derivative (the key information we need)
267
- self.dn = vec3(
268
- (c_shifted.n.x - c_center.n.x) / h,
269
- (c_shifted.n.y - c_center.n.y) / h,
270
- (c_shifted.n.z - c_center.n.z) / h
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 and embedding frame
300
- G_u, G_v, c_center = self.grad_op.compute_both(u, 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 tensor
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
- c_shifted = grad_op.calc_embedding_frame(u + step_size, v)
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
- c_shifted = grad_op.calc_embedding_frame(u, v + step_size)
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(c_center, c_shifted, step_size)
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.4
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,,