swcgeom 0.13.2__py3-none-any.whl → 0.15.0__py3-none-any.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.

Potentially problematic release.


This version of swcgeom might be problematic. Click here for more details.

@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: swcgeom
3
- Version: 0.13.2
3
+ Version: 0.15.0
4
4
  Summary: Neuron geometry library for swc format
5
5
  Author-email: yzx9 <yuan.zx@outlook.com>
6
- License: CC4.0 BY-NC-SA
6
+ License: Apache-2.0
7
7
  Project-URL: repository, https://github.com/yzx9/swcgeom
8
8
  Keywords: neuronscience,neuron,neuroanatomy,neuron-morphology
9
9
  Requires-Python: >=3.10
@@ -15,6 +15,7 @@ Requires-Dist: numpy >=1.22.3
15
15
  Requires-Dist: pandas >=1.4.2
16
16
  Requires-Dist: pynrrd >=1.0.0
17
17
  Requires-Dist: scipy >=1.9.1
18
+ Requires-Dist: sdflit >=0.2.1
18
19
  Requires-Dist: seaborn >=0.12.0
19
20
  Requires-Dist: tifffile >=2022.8.12
20
21
  Requires-Dist: typing-extensions >=4.4.0
@@ -30,8 +31,6 @@ Requires-Dist: urllib3 >=1.26.0 ; extra == 'all'
30
31
 
31
32
  # SWCGEOM
32
33
 
33
- <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a><br />
34
-
35
34
  [![Run tests](https://github.com/yzx9/swcgeom/actions/workflows/test.yml/badge.svg)](https://github.com/yzx9/swcgeom/actions/workflows/test.yml)
36
35
  [![Release to GitHub](https://github.com/yzx9/swcgeom/actions/workflows/github-publish.yml/badge.svg)](https://github.com/yzx9/swcgeom/releases)
37
36
  [![Release to PyPI](https://github.com/yzx9/swcgeom/actions/workflows/pypi-publish.yml/badge.svg)](https://pypi.org/project/swcgeom/)
@@ -67,4 +66,6 @@ Static analysis don't support import hook used in editable install for [PEP660](
67
66
 
68
67
  ## LICENSE
69
68
 
70
- This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
69
+ This work is licensed under a <a rel="license" href="https://www.apache.org/licenses/">Apache-2.0</a>.
70
+
71
+ Copyright (c) 2022-present, Zexin Yuan
@@ -1,5 +1,5 @@
1
1
  swcgeom/__init__.py,sha256=z88Zwcjv-ii7c7dYd9QPg9XrUVorQjtrgGbQCsEnQhc,265
2
- swcgeom/_version.py,sha256=ByxP_AGaDBx1nhN9W4fte2GtMXAPh9eMZ4pSGlztQPc,413
2
+ swcgeom/_version.py,sha256=oHv-EAjiXbJma3jZ0Tq6UPimiWYyyw2Ao9S8zdq9uWs,413
3
3
  swcgeom/analysis/__init__.py,sha256=esL_poW8u-_bmp7vR9ldcumX3_xodtaVfM1USqxQo5w,377
4
4
  swcgeom/analysis/branch_features.py,sha256=s6PTMwwvxrVtZXRZlQbUSIw4M9-1IG63kf-Nxc0tMB0,1958
5
5
  swcgeom/analysis/feature_extractor.py,sha256=coe07_bJau96BkimcnXzuf4KqjY5_QRLwqaumFsu_tQ,14031
@@ -8,55 +8,55 @@ swcgeom/analysis/path_features.py,sha256=iE21HBxAoGLxk_qK7MBwQhyUOBqNPcnk4urVHr9
8
8
  swcgeom/analysis/sholl.py,sha256=9hSW8rZm1gvSIgcEZg8IVPT8kzBgBfwqbwP4E8R7L44,6390
9
9
  swcgeom/analysis/trunk.py,sha256=L2tjUIUmrRQpah_W3ZETGWd16bDXJ5F8Sk2XBNGms0Q,5558
10
10
  swcgeom/analysis/visualization.py,sha256=mKOpzTPkLpr1ggGL1MZPZRTG92GEg4idLT4eN5z5KOs,5654
11
- swcgeom/analysis/volume.py,sha256=jC_HFpZ41D28JnSI5tjp5_zVkKAG47A7Z7WU9xmsezo,1918
11
+ swcgeom/analysis/volume.py,sha256=nWPR7wGOk3Wl5eh97YMws0X-2jk8K7lmFp4-03wL3lY,4628
12
12
  swcgeom/core/__init__.py,sha256=ZUudZavxAIUU6Q0lBHrQ4ybmL5lBfvzyYsTtpuih9wg,332
13
13
  swcgeom/core/branch.py,sha256=uuJCxaByRu-OdDZVWEffSFcmZWY-6ZWUhHN1M2Awj1s,3980
14
- swcgeom/core/branch_tree.py,sha256=sN0viBVg5A4r9dMCkGNAaVttrdR4bEoZZBbHZFKdXj4,1892
14
+ swcgeom/core/branch_tree.py,sha256=Ece6q1VNCRLLMj29N_MjXmmlHT8h4tpWCuDE0uSgKJo,1873
15
15
  swcgeom/core/node.py,sha256=HvfgsW4WU01hkRIPci8KF4bQMAkwtAxOGfUL4yUbuBs,3623
16
16
  swcgeom/core/path.py,sha256=CsEelHiDR0JPBP1dTvoCSRvX3kBlZxkQilosnncV4nQ,4188
17
- swcgeom/core/population.py,sha256=YZLAtkZKJeErOsE5MwhqieGjoMa7sWjFl5xxmXVPTco,8786
17
+ swcgeom/core/population.py,sha256=I9xSeGUveLhxkOg_5FWLcvf4yJVJ6j9_n03Hna3y_6w,8790
18
18
  swcgeom/core/segment.py,sha256=yabRdFj7KlkJP4V67jAlCIRzpHduNnq3bRBIRMuANfA,3158
19
19
  swcgeom/core/swc.py,sha256=lSYxAa25l6O8WZ9JtSSET-RZMr6EA1Tq_aXL_x0H9Rc,6795
20
- swcgeom/core/tree.py,sha256=oAx31r2jFzxSW7vnM17m8sMVVI3_xzxRyDQh19MPTlQ,12126
21
- swcgeom/core/tree_utils.py,sha256=xPy9b3MO43QR7VSvJvrwioXyQLGAPLotQjekn_-UiLg,7308
22
- swcgeom/core/tree_utils_impl.py,sha256=5Cb63ziVVLADnkjfuq1T-ePw2TQQ5TKk4gcPZR6f_wY,1123
20
+ swcgeom/core/tree.py,sha256=K2k7o8OZ9r2YeMmIebT8_0qvkwJYtLLzFHECz3fmmts,12365
21
+ swcgeom/core/tree_utils.py,sha256=3aCHghny5Z727sxkt6P8E2MMr34vK6irfPCelMn3vk4,7681
22
+ swcgeom/core/tree_utils_impl.py,sha256=kN2ByjqqQtZUfmC_ac25tXOaE-CMiV2lP58VxFphLEU,1616
23
23
  swcgeom/core/swc_utils/__init__.py,sha256=qghRxjtzvq5KKfN4HhvLpZNsGPfZQu-Jj2x62_5-TbQ,575
24
- swcgeom/core/swc_utils/assembler.py,sha256=RoMJ3RjLC4O7mk62QxXVTQ5SUHagrFmpEw3nOnnqeJo,4563
24
+ swcgeom/core/swc_utils/assembler.py,sha256=_ByaVFc61rfCS2p9QUw4g40uF4pZ6NJaDc--TcV4jWo,642
25
25
  swcgeom/core/swc_utils/base.py,sha256=huVxjuMLlTHbEb-KSEFDLgU0Ss3723t2Gr4Z_gQtl00,4737
26
26
  swcgeom/core/swc_utils/checker.py,sha256=E72GtLZ_1IqQQ7aWQGs0dZ3Z609__bw3EYQqeWrk-EI,2657
27
27
  swcgeom/core/swc_utils/io.py,sha256=6_--Qoe8kDja4PWsjwqRAvPJZNMFILFgauHaeWeGikU,6444
28
28
  swcgeom/core/swc_utils/normalizer.py,sha256=_Ysi8bSJ2JBnIGB8o6BvAg2mcz6xuJp9rgNLZqpLuR8,5083
29
- swcgeom/core/swc_utils/subtree.py,sha256=bd4XOLmRDfQSn_ktfQM3Hn8ONpCuZ_TdTWhE9-7QXW4,1999
29
+ swcgeom/core/swc_utils/subtree.py,sha256=43QITYvgXu3b_kfIod2Irrj3dSfrA-gTFev5VxzRafI,1995
30
30
  swcgeom/images/__init__.py,sha256=QBP1ZGGo2nWAcV7Krz-vbvW_jN4ChqXrrpoScXcUURs,96
31
31
  swcgeom/images/augmentation.py,sha256=v9zluYXmBEbafaDBTpvJovi4_KWJmHZZSvcYHzG0oWo,4099
32
- swcgeom/images/folder.py,sha256=urh60ITreGgEwSbCbgexJFM8_-C9WLAQ9jUN50sox10,4034
33
- swcgeom/images/io.py,sha256=VZWBq-_TMrKKdMaqpbZWZP6fCGIxWdhdIfb0ePcDy-4,20272
32
+ swcgeom/images/folder.py,sha256=2REkrdNghLm1z8kZ2PDVvtsupzog8kARkeMjLuLiLFo,4955
33
+ swcgeom/images/io.py,sha256=jUyKjtau8_5V-PN1kRsPHtP1OtueJi1zEf5-7PZ_tG8,21226
34
34
  swcgeom/transforms/__init__.py,sha256=Mi2mOgkQ50JbZ9LmgXgJIuAA5eio67oe2AOs2CCCxTQ,463
35
- swcgeom/transforms/base.py,sha256=22kkpQ11YCrH1SWWMHVqYjHp6cAlhslhdi1wKgAnT_s,3416
36
- swcgeom/transforms/branch.py,sha256=mdrTC9T4zENS9DdwlFaoFHcWDuFAgKgiNicJZ1gLsOc,5445
37
- swcgeom/transforms/geometry.py,sha256=zPmEf6ApJKzeZBbZ7qJYZXpY3-mrABN2dr7AUNqENiQ,6619
38
- swcgeom/transforms/image_stack.py,sha256=DSIkJzK_SxLB4bvwYBt0ACW5pbB_NJLT8raq2tjOE6E,7235
39
- swcgeom/transforms/images.py,sha256=tUl3dtqWfrhWR7WrOUc6LzWHnOzz3fwEgV3mMLRhn0c,908
40
- swcgeom/transforms/mst.py,sha256=B6ZRqeEfCHLHFu0tdOsOgplbYHra4VPYjnneXMU-cNY,6413
35
+ swcgeom/transforms/base.py,sha256=gN5Iqi-OHkYrsjllSOdxI6Yzav3jJGoi6kUPy-38FAs,4101
36
+ swcgeom/transforms/branch.py,sha256=R0rVti--u70IiUKyHSx6MsDYJyy6zSCf18Uia2Cmh28,5410
37
+ swcgeom/transforms/geometry.py,sha256=XR73fO_8T7otUFIllqKOWW0OnrsXBc7yA01oDT99yMc,7385
38
+ swcgeom/transforms/image_stack.py,sha256=KhZ26Ps88jk_7NkI9dkS2E7NZXUvMaN3Ln9WzJ-vPu0,5823
39
+ swcgeom/transforms/images.py,sha256=l5Hx8x27zoClUz3s11j2oj0Lt9ROh5JJfjoIU_vd3H8,898
40
+ swcgeom/transforms/mst.py,sha256=ceL_EWpCtoSy9zYD6wPP5zO68eNTrDl9JExoPLcE_Lw,6236
41
41
  swcgeom/transforms/path.py,sha256=Gk2iunGQMX7vE83bdo8xoDO-KAT1Vvep0iZs7oFLzFQ,1089
42
- swcgeom/transforms/population.py,sha256=ZrKfMAMx4l729f-JLgw0dnGIPtPUoV0ZZoNNyA5cBw8,826
43
- swcgeom/transforms/tree.py,sha256=Q5OnSti0ZeTNb-WpA_UZsDN7dhLN8YweEF_Siyrj66c,6420
44
- swcgeom/transforms/tree_assembler.py,sha256=UZ9OUg1bQNecYIY_7ippg3S8gpuoi617ZUE0jg6BrQE,3177
45
- swcgeom/utils/__init__.py,sha256=VeHspOo13k0Nxr4sZY5lT0amyaAE6Zfz96TF7sWEHp4,425
42
+ swcgeom/transforms/population.py,sha256=EmZ6ntuOKe8mXJxMW7nCUA-w2DVlEVe2n0IOVz49tCY,833
43
+ swcgeom/transforms/tree.py,sha256=Q45sVA7yi8pINV7ENOWPKz6DnEM3U5uJxwkFKNFS5VE,6262
44
+ swcgeom/transforms/tree_assembler.py,sha256=vi_X9CNo5IxHP5J7bRl2z91PWufU6HmYlz1iyfdPUxE,5121
45
+ swcgeom/utils/__init__.py,sha256=QfezYuQzgmPziNiWz2T1h77V-gjpuBoUi3mC-K-PZlI,427
46
46
  swcgeom/utils/debug.py,sha256=qay2qJpViLX82mzxdndxQFn-pi1vaEj9CbLGuGt8Y9k,465
47
47
  swcgeom/utils/download.py,sha256=By2qZezo6h1Ke_4YpSIhDgcisOrpjVqRmNzbhynC2xs,2834
48
48
  swcgeom/utils/dsu.py,sha256=3aCbtpnl_D0OXnowTS8-kuwnCS4BKBYL5ECiFQ1fUW8,1435
49
49
  swcgeom/utils/ellipse.py,sha256=LB3q5CIy75GEUdTauIpKySwIHaDrwXzzkBhOCnjJ8Vw,3259
50
50
  swcgeom/utils/file.py,sha256=1hchQDsPgn-i-Vz5OQtcogxav_ajCQ_OaEZCLmqczRg,2515
51
- swcgeom/utils/geometry_object.py,sha256=ayw9hzrxJXSIcEfYVSOXvPaQl8J9HYCGotGOfuH5RKA,7436
52
51
  swcgeom/utils/neuromorpho.py,sha256=CDK2tUM2pNwHv_lEserHhQs_VlY3Rn557-jtV63EFlk,14420
53
52
  swcgeom/utils/numpy_helper.py,sha256=A-F-eFdGktCHVAQ_HcXiFB3Y1YhhSNfAmtOl8483Dvo,1292
54
53
  swcgeom/utils/renderer.py,sha256=xHVZ06Z1MeKBPC3nKzuwA1HryzR0ga79y6johZA4-q0,7290
55
- swcgeom/utils/sdf.py,sha256=cmkHwdnh33u1gAXlzol5u9ZI3_SdMoMiY4pIkOgEcK0,5206
56
- swcgeom/utils/solid_geometry.py,sha256=8ao2GAme8kX-gCjB7JSGe2iGhbkGIy3T4Bg4TxsQNhI,1758
54
+ swcgeom/utils/sdf.py,sha256=K-LSnwwNsGF85GW1kNBaqXAAVesxZAEsrn0nvOA2LcA,10614
55
+ swcgeom/utils/solid_geometry.py,sha256=TV02jhcoCLCqtYA9hfE50LFD_VRfixMiOSiHB5Jb2_U,2431
57
56
  swcgeom/utils/transforms.py,sha256=PmP5fL_iVguq4GR2aqXhM0TeCsiFVnrPZMZG6zLohrE,6983
58
- swcgeom-0.13.2.dist-info/LICENSE,sha256=aiTJ_1to1Xx6PaByy-pSXg42VYzE4FvF6GIt69WSDDI,202
59
- swcgeom-0.13.2.dist-info/METADATA,sha256=feoVNhkkkzcDdqP1bgZd5IGiSN6dC54Tug3yPSDz2Bg,2575
60
- swcgeom-0.13.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
61
- swcgeom-0.13.2.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
62
- swcgeom-0.13.2.dist-info/RECORD,,
57
+ swcgeom/utils/volumetric_object.py,sha256=DVRGGmQrAL0oaW6hbNtp5TStbic9DfyJdCzsv2FNw2c,15134
58
+ swcgeom-0.15.0.dist-info/LICENSE,sha256=JPtohhZ4XURqoKI0ZqnMYb7dobCOoZR_n5EpnaLTp3E,11344
59
+ swcgeom-0.15.0.dist-info/METADATA,sha256=VJX8KlMJWpYCZ-bMUYy_kL05sAHXmvHLMqUepQaKNTQ,2347
60
+ swcgeom-0.15.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
61
+ swcgeom-0.15.0.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
62
+ swcgeom-0.15.0.dist-info/RECORD,,
@@ -1,255 +0,0 @@
1
- """Geometry object."""
2
-
3
- from abc import ABC, abstractmethod
4
- from functools import lru_cache
5
-
6
- import numpy as np
7
- import numpy.typing as npt
8
-
9
- from swcgeom.utils.solid_geometry import (
10
- find_sphere_line_intersection,
11
- find_unit_vector_on_plane,
12
- project_point_on_line,
13
- )
14
-
15
- __all__ = ["GeomObject", "GeomSphere", "GeomFrustumCone"]
16
-
17
- eps = 1e-6
18
-
19
-
20
- class GeomObject(ABC):
21
- """Geometry object."""
22
-
23
- @abstractmethod
24
- def get_volume(self) -> float:
25
- """Get volume."""
26
- raise NotImplementedError()
27
-
28
- @abstractmethod
29
- def get_intersect_volume(self, obj: "GeomObject") -> float:
30
- """Get intersect volume.
31
-
32
- Parameters
33
- ----------
34
- obj : GeometryObject
35
- Another geometry object.
36
-
37
- Returns
38
- -------
39
- volume : float
40
- Intersect volume.
41
- """
42
- raise NotImplementedError()
43
-
44
-
45
- class GeomSphere(GeomObject):
46
- """Geometry Sphere."""
47
-
48
- def __init__(self, center: npt.ArrayLike, radius: float):
49
- super().__init__()
50
-
51
- self.center = np.array(center)
52
- assert len(self.center) == 3
53
-
54
- self.radius = radius
55
-
56
- def get_volume(self) -> float:
57
- return self.calc_volume(self.radius)
58
-
59
- def get_volume_spherical_cap(self, h: float) -> float:
60
- return self.calc_volume_spherical_cap(self.radius, h)
61
-
62
- def get_intersect_volume_sphere(self, obj: "GeomSphere") -> float:
63
- return self.calc_intersect_volume_sphere(self, obj)
64
-
65
- def get_intersect_volume_sphere_frustum_cone(
66
- self, frustum_cone: "GeomFrustumCone"
67
- ) -> float:
68
- return calc_intersect_volume_sphere_frustum_cone(self, frustum_cone)
69
-
70
- def get_intersect_volume(self, obj: GeomObject) -> float:
71
- if isinstance(obj, GeomSphere):
72
- return self.get_intersect_volume_sphere(obj)
73
-
74
- if isinstance(obj, GeomFrustumCone):
75
- return self.get_intersect_volume_sphere_frustum_cone(obj)
76
-
77
- classname = obj.__class__.__name__
78
- raise NotImplementedError(f"unsupported geometry object: {classname}")
79
-
80
- @staticmethod
81
- def calc_volume(radius: float) -> float:
82
- r"""Calculate volume of sphere.
83
-
84
- \being{equation}
85
- V = \frac{4}{3} * π * r^3
86
- \end{equation}
87
-
88
- Returns
89
- -------
90
- volume : float
91
- Volume.
92
- """
93
- return 4 / 3 * np.pi * radius**3
94
-
95
- @staticmethod
96
- def calc_volume_spherical_cap(r: float, h: float) -> float:
97
- r"""Calculate the volume of a spherical cap.
98
-
99
- \being{equation}
100
- V = π * h^2 * (3r - h) / 3
101
- \end{equation}
102
-
103
- Parameters
104
- ----------
105
- r : float
106
- radius of the sphere
107
- h : float
108
- height of the spherical cap
109
-
110
- Returns
111
- -------
112
- volume : float
113
- volume of the spherical cap
114
- """
115
- return np.pi * h**2 * (3 * r - h) / 3
116
-
117
- @classmethod
118
- def calc_intersect_volume_sphere(
119
- cls, obj1: "GeomSphere", obj2: "GeomSphere"
120
- ) -> float:
121
- r"""Calculate intersect volume of two spheres.
122
-
123
- \being{equation}
124
- V = \frac{\pi}{12d} * (r_1 + r_2 - d)^2 (d^2 + 2d r_1 - 3r_1^2 + 2d r_2 - 3r_2^2 + 6 r_1r_2)
125
- \end{equation}
126
-
127
- Returns
128
- -------
129
- volume : float
130
- Intersect volume.
131
- """
132
-
133
- r1, r2 = obj1.radius, obj2.radius
134
- d = np.linalg.norm(obj1.center - obj2.center).item()
135
- if d > r1 + r2:
136
- return 0
137
-
138
- if d <= abs(r1 - r2):
139
- return cls.calc_volume(min(r1, r2))
140
-
141
- part1 = (np.pi / (12 * d)) * (r1 + r2 - d) ** 2
142
- part2 = (
143
- d**2 + 2 * d * r1 - 3 * r1**2 + 2 * d * r2 - 3 * r2**2 + 6 * r1 * r2
144
- )
145
- return part1 * part2
146
-
147
-
148
- class GeomFrustumCone(GeomObject):
149
- """Geometry Frustum."""
150
-
151
- def __init__(self, c1: npt.ArrayLike, r1: float, c2: npt.ArrayLike, r2: float):
152
- super().__init__()
153
-
154
- self.c1 = np.array(c1)
155
- assert len(self.c1) == 3
156
-
157
- self.c2 = np.array(c2)
158
- assert len(self.c2) == 3
159
-
160
- self.r1 = r1
161
- self.r2 = r2
162
-
163
- def height(self) -> float:
164
- """Get height of frustum."""
165
- return np.linalg.norm(self.c1 - self.c2).item()
166
-
167
- def get_volume(self) -> float:
168
- return self.calc_volume(self.r1, self.r2, self.height())
169
-
170
- def get_intersect_volume_sphere(self, sphere: GeomSphere) -> float:
171
- return calc_intersect_volume_sphere_frustum_cone(sphere, self)
172
-
173
- def get_intersect_volume(self, obj: GeomObject) -> float:
174
- if isinstance(obj, GeomSphere):
175
- return self.get_intersect_volume_sphere(obj)
176
-
177
- classname = obj.__class__.__name__
178
- raise NotImplementedError(f"unsupported geometry object: {classname}")
179
-
180
- @staticmethod
181
- def calc_volume(r1: float, r2: float, height: float) -> float:
182
- r"""Calculate volume of frustum.
183
-
184
- \being{equation}
185
- V = \frac{1}{3} * π * h * (r^2 + r * R + R^2)
186
- \end{equation}
187
-
188
- Returns
189
- -------
190
- volume : float
191
- Volume.
192
- """
193
- return (1 / 3) * np.pi * height * (r1**2 + r1 * r2 + r2**2)
194
-
195
-
196
- @lru_cache
197
- def calc_intersect_volume_sphere_frustum_cone(
198
- sphere: GeomSphere, frustum_cone: GeomFrustumCone
199
- ) -> float:
200
- r"""Calculate intersect volume of sphere and frustum cone.
201
-
202
- Returns
203
- -------
204
- volume : float
205
- Intersect volume.
206
- """
207
- h = frustum_cone.height()
208
- c1, r1 = sphere.center, sphere.radius
209
- if np.allclose(c1, frustum_cone.c1) and np.allclose(r1, frustum_cone.r1):
210
- c2, r2 = frustum_cone.c2, frustum_cone.r2
211
- elif np.allclose(c1, frustum_cone.c2) and np.allclose(r1, frustum_cone.r2):
212
- c2, r2 = frustum_cone.c1, frustum_cone.r1
213
- else:
214
- raise NotImplementedError("unsupported to calculate intersect volume")
215
-
216
- # Fast-Path: The surface of the frustum concentric with the sphere
217
- # is the surface with smaller radius
218
- if r2 - r1 >= -eps: # r2 >= r1:
219
- v_himisphere = GeomSphere.calc_volume_spherical_cap(r1, r1)
220
- if h >= r1:
221
- # The hemisphere is completely inside the frustum cone
222
- return v_himisphere
223
-
224
- # The frustum cone is lower than the hemisphere
225
- v_cap = GeomSphere.calc_volume_spherical_cap(r1, r1 - h)
226
- return v_himisphere - v_cap
227
-
228
- up = (c2 - c1) / np.linalg.norm(c2 - c1)
229
- v = find_unit_vector_on_plane(up)
230
-
231
- intersections = find_sphere_line_intersection(c1, r1, c1 + r1 * v, c2 + r2 * v)
232
- if len(intersections) == 0:
233
- # Tricky case: Since the intersection point not found with
234
- # numerical precision, we can simply assume that there are two
235
- # intersection points and at the same position
236
- intersections = [(0, c1 + r1 * v), (0, c1 + r1 * v)]
237
- assert len(intersections) == 2
238
- t, p = max(intersections, key=lambda x: x[0])
239
-
240
- # Fast-Path: The frustum cone is completely inside the sphere
241
- if t > 1 + eps:
242
- return frustum_cone.get_volume()
243
-
244
- M = project_point_on_line(c1, up, p)
245
- h1 = np.linalg.norm(M - c1).item()
246
- r3 = np.linalg.norm(M - p).item()
247
- v_cap1 = GeomSphere.calc_volume_spherical_cap(r1, r1 - h1)
248
- v_frustum = GeomFrustumCone.calc_volume(r1, r3, h1)
249
-
250
- # Fast-Path: The frustum cone is higher than the sphere
251
- if h >= r1:
252
- return v_cap1 + v_frustum
253
-
254
- v_cap2 = GeomSphere.calc_volume_spherical_cap(r1, r1 - h)
255
- return v_cap1 + v_frustum - v_cap2
@@ -1,3 +0,0 @@
1
- The code is released under the Creative Commons Attribution-NonCommercial-
2
- ShareAlike 4.0 International Public License for Noncommercial use only. Any
3
- commercial use should get formal permission first.