1212// See the license for the specific language governing permissions and
1313// limitations under the license.
1414
15- use crate :: {
16- make_icosphere, make_vertices, table:: PaddedTable , DataOnVertex , IcoSphere , Vector3 , Vertices ,
17- } ;
15+ use crate :: { make_icosphere, make_vertices, table:: PaddedTable , IcoSphere , Vector3 , Vertex } ;
1816use anyhow:: Result ;
1917use core:: f64:: consts:: PI ;
2018use get_size:: GetSize ;
@@ -44,19 +42,28 @@ pub type Face = [u16; 3];
4442///
4543/// https://en.wikipedia.org/wiki/Geodesic_polyhedron
4644/// 12 vertices will always have 5 neighbors; the rest will have 6.
45+ ///
46+ /// Vertex positions and neighbor information are available through a shared pointer.
47+ /// To enable concurrent write access, data is wrapped with `OnceLock` which allows
48+ /// setting data only once.
4749#[ derive( Clone , GetSize ) ]
4850pub struct IcoTable < T : Clone + GetSize > {
4951 /// Reference counted pointer to vertex positions and neighbours
5052 /// We want only *one* copy of this, hence the ref. counted, thread-safe pointer
51- #[ get_size( size = 3 ) ]
52- vertices : Arc < OnceLock < Vec < Vertices > > > ,
53+ #[ get_size( size = 8 ) ]
54+ vertices : Arc < OnceLock < Vec < Vertex > > > ,
5355 /// Vertex information (position, data, neighbors)
54- data : Vec < DataOnVertex < T > > ,
56+ #[ get_size( size_fn = oncelock_size_helper) ]
57+ data : Vec < OnceLock < T > > ,
58+ }
59+
60+ fn oncelock_size_helper < T : GetSize > ( value : & Vec < OnceLock < T > > ) -> usize {
61+ value. get_size ( ) + std:: mem:: size_of :: < T > ( ) * value. len ( )
5562}
5663
5764impl < T : Clone + GetSize > IcoTable < T > {
5865 /// Iterator over vertices `(positions, neighbors)`
59- pub fn iter_vertices ( & self ) -> impl Iterator < Item = & Vertices > {
66+ pub fn iter_vertices ( & self ) -> impl Iterator < Item = & Vertex > {
6067 self . vertices . get ( ) . unwrap ( ) . iter ( )
6168 }
6269 /// Get i'th vertex position
@@ -65,7 +72,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
6572 }
6673 /// Get i'th data or `None`` if uninitialized
6774 pub fn get_data ( & self , index : usize ) -> & OnceLock < T > {
68- & self . data [ index] . data
75+ & self . data [ index]
6976 }
7077 /// Get i'th neighbors
7178 pub fn get_neighbors ( & self , index : usize ) -> & [ u16 ] {
@@ -89,12 +96,9 @@ impl<T: Clone + GetSize> IcoTable<T> {
8996 }
9097
9198 /// Generate table based on an existing vertices pointer and optionally set default data
92- pub fn from_vertices ( vertices : Arc < OnceLock < Vec < Vertices > > > , data : Option < T > ) -> Self {
99+ pub fn from_vertices ( vertices : Arc < OnceLock < Vec < Vertex > > > , data : Option < T > ) -> Self {
93100 let num_vertices = vertices. get ( ) . unwrap ( ) . len ( ) ;
94- let data = match data {
95- Some ( data) => DataOnVertex :: from ( data) ,
96- None => DataOnVertex :: uninitialized ( ) ,
97- } ;
101+ let data = data. map ( |d| OnceLock :: from ( d) ) . unwrap_or ( OnceLock :: new ( ) ) ;
98102 Self {
99103 vertices,
100104 data : vec ! [ data; num_vertices] ,
@@ -108,7 +112,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
108112 }
109113 Self {
110114 vertices : Arc :: new ( OnceLock :: from ( make_vertices ( icosphere) ) ) ,
111- data : vec ! [ DataOnVertex :: uninitialized ( ) ; icosphere. raw_points( ) . len( ) ] ,
115+ data : vec ! [ OnceLock :: new ( ) ; icosphere. raw_points( ) . len( ) ] ,
112116 }
113117 }
114118
@@ -138,7 +142,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
138142 /// The function takes the index of the vertex and its position
139143 /// Due to the `OnceLock` wrap, this can be done only once!
140144 pub fn set_vertex_data ( & self , f : impl Fn ( usize , & Vector3 ) -> T ) -> anyhow:: Result < ( ) > {
141- if self . data . iter ( ) . any ( |v| v. data . get ( ) . is_some ( ) ) {
145+ if self . data . iter ( ) . any ( |v| v. get ( ) . is_some ( ) ) {
142146 anyhow:: bail!( "Data already set for some vertices" )
143147 }
144148 self . iter ( ) . enumerate ( ) . try_for_each ( |( i, ( pos, _, data) ) | {
@@ -154,14 +158,14 @@ impl<T: Clone + GetSize> IcoTable<T> {
154158 ///
155159 /// After this call, `set_vertex_data` can be called again.
156160 pub fn clear_vertex_data ( & mut self ) {
157- for vertex in self . data . iter_mut ( ) {
158- vertex . data = OnceLock :: new ( ) ;
161+ for data in self . data . iter_mut ( ) {
162+ * data = OnceLock :: new ( ) ;
159163 }
160164 }
161165
162166 /// Get data associated with each vertex
163167 pub fn vertex_data ( & self ) -> impl Iterator < Item = & T > {
164- self . data . iter ( ) . map ( |v| v. data . get ( ) . unwrap ( ) )
168+ self . data . iter ( ) . map ( |v| v. get ( ) . unwrap ( ) )
165169 }
166170
167171 /// Transform vertex positions using a function
@@ -173,7 +177,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
173177 . map ( |v| {
174178 let pos = f ( & v. pos ) ;
175179 let neighbors = v. neighbors . clone ( ) ;
176- Vertices { pos, neighbors }
180+ Vertex { pos, neighbors }
177181 } )
178182 . collect_vec ( ) ;
179183 self . vertices = Arc :: new ( OnceLock :: from ( new_vertices) ) ;
@@ -437,9 +441,9 @@ impl IcoTable<f64> {
437441 pub fn interpolate ( & self , point : & Vector3 ) -> f64 {
438442 let face = self . nearest_face ( point) ;
439443 let bary = self . barycentric ( point, & face) ;
440- bary[ 0 ] * self . data [ face[ 0 ] as usize ] . data . get ( ) . unwrap ( )
441- + bary[ 1 ] * self . data [ face[ 1 ] as usize ] . data . get ( ) . unwrap ( )
442- + bary[ 2 ] * self . data [ face[ 2 ] as usize ] . data . get ( ) . unwrap ( )
444+ bary[ 0 ] * self . data [ face[ 0 ] as usize ] . get ( ) . unwrap ( )
445+ + bary[ 1 ] * self . data [ face[ 1 ] as usize ] . get ( ) . unwrap ( )
446+ + bary[ 2 ] * self . data [ face[ 2 ] as usize ] . get ( ) . unwrap ( )
443447 }
444448 /// Generate table based on a minimum number of vertices on the subdivided icosaedron
445449 ///
0 commit comments