Skip to content

Commit 913f13b

Browse files
committed
Version 18.40
1 parent 387fa8a commit 913f13b

File tree

7 files changed

+89
-59
lines changed

7 files changed

+89
-59
lines changed

README.md

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<center><h2>Adaptive Multigrid Solvers (Version 18.35)</h2></center>
1+
<center><h2>Adaptive Multigrid Solvers (Version 18.40)</h2></center>
22
<center>
33
<a href="#LINKS">links</a>
44
<a href="#COMPILATION">compilation</a>
@@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo
2929
<a href="https://www.cs.jhu.edu/~misha/MyPapers/CGF23.pdf">[Kazhdan and Hoppe, 2023]</a>
3030
<br>
3131
<b>Executables: </b>
32-
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.35/AdaptiveSolvers.x64.zip">Win64</a><br>
32+
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.40/AdaptiveSolvers.x64.zip">Win64</a><br>
3333
<b>Source Code:</b>
34-
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.35/AdaptiveSolvers.zip">ZIP</a> <a href="https://github.com/mkazhdan/PoissonRecon">GitHub</a><br>
34+
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.40/AdaptiveSolvers.zip">ZIP</a> <a href="https://github.com/mkazhdan/PoissonRecon">GitHub</a><br>
3535
<b>Older Versions:</b>
36+
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.35/">V18.35</a>,
3637
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.31/">V18.31</a>,
3738
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.30/">V18.30</a>,
3839
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.20/">V18.20</a>,
@@ -1054,11 +1055,11 @@ If both the <b>--keep</b> flag and the <b>--fraction</b> flag are set, the <b>--
10541055
In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in <CODE>Reconstructors.h</CODE> and <CODE>Extrapolator.h</CODE>
10551056
Using the functionality requires requires choosing a finite element type and defining input oriented-point stream and output vertex and face streams. In the descriptions below, the template parameter <CODE>Real</CODE> is the floating point type used to represent data (typically <code>float</code>) and <CODE>Dim</CODE> is the integer dimension of the space (fixed at <CODE>Dim</CODE>=3).
10561057
<UL>
1057-
<LI>The template parameter <CODE>FEMSig</CODE> describes the 1D finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued <CODE>Degree</CODE> and boundary type <CODE>BType</CODE> (one of <CODE>BOUNDARY_FREE</CODE>, <CODE>BOUNDARY_DIRICHLET</CODE>, and <CODE>BOUNDARY_NEUMANN</CODE> defined in <CODE>BSplineData.h</CODE>), the signature is defined as (<CODE>Reconstruction.example.cppy</CODE> line 308):
1058+
<LI>The template parameter <CODE>FEMSig</CODE> describes the 1D finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued <CODE>Degree</CODE> and boundary type <CODE>BType</CODE> (one of <CODE>BOUNDARY_FREE</CODE>, <CODE>BOUNDARY_DIRICHLET</CODE>, and <CODE>BOUNDARY_NEUMANN</CODE> defined in <CODE>BSplineData.h</CODE>), the signature is defined as:
10581059
<PRE>
10591060
<CODE>static const unsigned int FEMSig = FEMDegreeAndBType&lt; Degree , BoundaryType &gt;::Signature;</CODE>
10601061
</PRE>
1061-
<LI>The template parameter <CODE>FEMSIgs</CODE> describes the tensor-product finite element type, typically defined as an "isotropic" element with the same 1D finite element type across all <CODE>Dim</CODE> dimensions. It is defined as (<CODE>Reconstruction.example.cppy</CODE> line 314):
1062+
<LI>The template parameter <CODE>FEMSIgs</CODE> describes the tensor-product finite element type, typically defined as an "isotropic" element with the same 1D finite element type across all <CODE>Dim</CODE> dimensions. It is defined as:
10621063
<PRE>
10631064
<CODE>using FEMSigs = IsotropicUIntPack&lt; Dim , FEMSig &gt;;</CODE>
10641065
</PRE>
@@ -1117,22 +1118,22 @@ This method returns the extrapolated value at the prescribed position.
11171118
<UL>
11181119
These steps can be found in the <code>Reconstruction.example.cpp</code> code.
11191120
<UL>
1120-
<LI>The finite-elements signature is created in line 308.
1121-
<LI>An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 374.
1122-
<LI>An output polygon stream that pushes the polygon to an <code>std::vector</code> of <code>std::vector&lt; int &gt;</code>s is defined in lines 213-230 and constructed in line 384.
1123-
<LI>An output vertex stream that pushes just the position information to an <code>std::vector</code> of <code>Real</code>s is desfined in lines 223-244 and constructed in line 385.
1124-
<LI>The reconstructor is constructed in line 377.
1125-
<LI>The level-set extraction is performed on line 388.
1126-
<LI>The evaluator is created on line 334.
1127-
<LI>The evaluator is used to query the values and gradients of the implicit function in line 327.
1128-
<LI>The extrapolator is constructed on line 406.
1129-
<LI>The extrapolator is evaluated at the vertex positions at line 416.
1121+
<LI>The finite-elements signatures are created in lines 308 and 311.
1122+
<LI>An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 379.
1123+
<LI>An output polygon stream that pushes the polygon to an <code>std::vector</code> of <code>std::vector&lt; int &gt;</code>s is defined in lines 213-230 and constructed in line 389.
1124+
<LI>An output vertex stream that pushes just the position information to an <code>std::vector</code> of <code>Real</code>s is desfined in lines 223-244 and constructed in line 390.
1125+
<LI>The implicit representation is computed in line 382.
1126+
<LI>The level-set extraction is performed on line 393.
1127+
<LI>The evaluator is created on line 340.
1128+
<LI>The evaluator is used to query the values and gradients of the implicit function in line 333.
1129+
<LI>The extrapolator is constructed on line 411.
1130+
<LI>The extrapolator is evaluated at the vertex positions at line 421.
11301131
</UL>
1131-
Note that a similar approach can be used to perform the <A HREF="http://mesh.brown.edu/ssd/">Smoothed Signed Distance</A> reconstruction (lines 452 and 453).<BR>
1132+
Note that a similar approach can be used to perform the <A HREF="http://mesh.brown.edu/ssd/">Smoothed Signed Distance</A> reconstruction (lines 459 and 460).<BR>
11321133
The approach also supports reconstruction of meshes with auxiliary information like color, with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the <CODE>RGBColor</CODE> type defined in lines 67-82). The auxiliary inform is derived in one of two ways:
11331134
<OL>
1134-
<LI> As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 343-470)
1135-
<LI> Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 397-418)
1135+
<LI> As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 349-375)
1136+
<LI> Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 400-427)
11361137
</OL>
11371138
</UL>
11381139
</DL>
@@ -1712,6 +1713,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
17121713
<LI> Removed the confidence bias option.
17131714
</OL>
17141715

1716+
<a href="https://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version18.31/">Version 18.40</a>:
1717+
<OL>
1718+
<LI> Added support for extrapolator accumulation.
1719+
</OL>
1720+
17151721
</DETAILS>
17161722

17171723
<hr>

Src/Extrapolator.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@ namespace PoissonRecon
9898
XForm< Real , Dim+1 > worldToUnitCubeTransform( void ) const { return _worldToUnitCube; }
9999

100100
AuxData operator()( unsigned int t , Point< Real , Dim > p ){ return _value(t,p); }
101+
AuxData operator()( Point< Real , Dim > p ){ return _value(0,p); }
101102

102-
AuxData operator()( Point< Real , Dim > p ){ return operator()( 0 , p ); }
103+
void evaluate( unsigned int t , Point< Real , Dim > p , AuxData &data ){ return _evaluate( t , p , data ); }
104+
void evaluate( Point< Real , Dim > p , AuxData &data ){ return _evaluate( 0 , p , data ); }
103105

104106
protected:
105107
typename FEMTree< Dim , Real >::template MultiThreadedSparseEvaluator< IsotropicUIntPack< Dim , DataSig > , ProjectiveData< AuxData , Real > > *_auxEvaluator = nullptr;
@@ -113,6 +115,23 @@ namespace PoissonRecon
113115
_auxEvaluator->addValue( q , pData );
114116
return pData.value();
115117
}
118+
119+
void _evaluate( unsigned int t , Point< Real , Dim > p , AuxData &data )
120+
{
121+
Point< Real , Dim > q = _worldToUnitCube * p;
122+
for( unsigned int d=0 ; d<Dim ; d++ ) if( q[d]<0 || q[d]>1 ) throw OutOfUnitCubeException(p,q);
123+
124+
Real weight = (Real)0.;
125+
data *= 0;
126+
127+
auto Accumulation = [&weight,&data]( const ProjectiveData< AuxData , Real > &pData , Real scale )
128+
{
129+
weight += pData.weight * scale;
130+
data += pData.data * scale;
131+
};
132+
_auxEvaluator->accumulate( q , Accumulation );
133+
if( weight ) data /= weight;
134+
}
116135
};
117136

118137
template< typename Real , unsigned int Dim , typename AuxData , unsigned int DataDegree >

Src/FEMTree.Evaluation.inl

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,15 +550,43 @@ void FEMTree< Dim , Real >::MultiThreadedSparseEvaluator< UIntPack< FEMSigs ...
550550
_tree->template _addEvaluation< T , SparseNodeData< T , FEMSignatures > , 0 >( _coefficients , p , _tree->_globalToLocal( node->depth() ) , *_pointEvaluator , nKey , t );
551551
}
552552

553+
template< unsigned int Dim , class Real >
554+
template< unsigned int ... FEMSigs , typename T >
555+
template< typename AccumulationFunctor/*=std::function< void ( const T & , Real s ) > */ >
556+
void FEMTree< Dim , Real >::MultiThreadedSparseEvaluator< UIntPack< FEMSigs ... > , T >::accumulate( Point< Real , Dim > p , AccumulationFunctor &Accumulate , int thread , const FEMTreeNode *node )
557+
{
558+
if( !node ) node = _tree->leaf( p );
559+
ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread];
560+
nKey.getNeighbors( node );
561+
_tree->template _accumulate< T , SparseNodeData< T , FEMSignatures > , 0 , AccumulationFunctor >( _coefficients , p , _tree->_globalToLocal( node->depth() ) , *_pointEvaluator , nKey , Accumulate );
562+
}
563+
553564
template< unsigned int Dim , class Real >
554565
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs >
555566
void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const
556567
{
557-
_addEvaluation< V , Coefficients , D , DataSigs ... >( coefficients , p , _globalToLocal( dataKey.depth() ) , pointEvaluator , dataKey , value );
568+
auto AF = [&value]( const V &w , Real s ){ value += w * s; };
569+
_accumulate< V , Coefficients , D , decltype(AF) , DataSigs ... >( coefficients , p , pointEvaluator , dataKey , AF );
558570
}
571+
559572
template< unsigned int Dim , class Real >
560573
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs >
561574
void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const
575+
{
576+
auto AF = [&value]( const V &w , Real s ){ value += w * s; };
577+
_accumulate< V , Coefficients , D , decltype(AF) , DataSigs... >( coefficients , p , pointDepth , pointEvaluator , dataKey , AF );
578+
}
579+
580+
template< unsigned int Dim , class Real >
581+
template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor , unsigned int ... DataSigs >
582+
void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &Accumulate ) const
583+
{
584+
_accumulate< V , Coefficients , D , AccumulationFunctor , DataSigs ... >( coefficients , p , _globalToLocal( dataKey.depth() ) , pointEvaluator , dataKey , Accumulate );
585+
}
586+
587+
template< unsigned int Dim , class Real >
588+
template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor , unsigned int ... DataSigs >
589+
void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &Accumulate ) const
562590
{
563591
typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes;
564592
PointEvaluatorState< UIntPack< DataSigs ... > , ZeroUIntPack< Dim > > state;
@@ -582,7 +610,7 @@ void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , P
582610
if( v )
583611
{
584612
LocalDepth d ; LocalOffset off ; _localDepthAndOffset( nodes[i] , d , off );
585-
value += (*v) * (Real)state.value( off , derivatives );
613+
Accumulate( *v , (Real)state.value( off , derivatives ) );
586614
}
587615
}
588616
}

Src/FEMTree.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,8 +2302,14 @@ namespace PoissonRecon
23022302
template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias );
23032303
template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim );
23042304
template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim );
2305-
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const;
2306-
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const;
2305+
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs >
2306+
void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const;
2307+
template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs >
2308+
void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const;
2309+
template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor /*=std::function< void ( const V & , Real s ) > */ , unsigned int ... DataSigs >
2310+
void _accumulate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &AF ) const;
2311+
template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor /*=std::function< void ( const V & , Real s ) > */ , unsigned int ... DataSigs >
2312+
void _accumulate( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &AF ) const;
23072313

23082314
public:
23092315

@@ -2513,6 +2519,8 @@ namespace PoissonRecon
25132519
MultiThreadedSparseEvaluator( const FEMTree* tree , const SparseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() );
25142520
~MultiThreadedSparseEvaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator; }
25152521
void addValue( Point< Real , Dim > p , T &t , int thread=0 , const FEMTreeNode* node=NULL );
2522+
template< typename AccumulationFunctor/*=std::function< void ( const T & , Real s ) > */ >
2523+
void accumulate( Point< Real , Dim > p , AccumulationFunctor &Accumulate , int thread=0 , const FEMTreeNode* node=NULL );
25162524
};
25172525

25182526
protected:

Src/PoissonRecon.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ CmdLineParameter< float >
102102
Confidence( "confidence" , 0.f ) ,
103103
CGSolverAccuracy( "cgAccuracy" , 1e-3f ) ,
104104
LowDepthCutOff( "lowDepthCutOff" , 0.f ) ,
105-
TargetValue( "targetValue" , 0.5f ) ,
106105
PointWeight( "pointWeight" );
107106

108107
CmdLineReadable* params[] =
@@ -140,7 +139,6 @@ CmdLineReadable* params[] =
140139
&ThreadChunkSize ,
141140
&LowDepthCutOff ,
142141
&AlignmentDir ,
143-
&TargetValue ,
144142
&GridCoordinates ,
145143
NULL
146144
};
@@ -168,7 +166,6 @@ void ShowUsage(char* ex)
168166
printf( "\t[--%s <scale factor>=%f]\n" , Scale.name , Scale.value );
169167
printf( "\t[--%s <minimum number of samples per node>=%f]\n" , SamplesPerNode.name, SamplesPerNode.value );
170168
printf( "\t[--%s <interpolation weight>=%.3e * <b-spline degree>]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier * Reconstructor::Poisson::DefaultFEMDegree );
171-
printf( "\t[--%s <target value>=%f]\n" , TargetValue.name , TargetValue.value );
172169
printf( "\t[--%s <iterations>=%d]\n" , Iters.name , Iters.value );
173170
printf( "\t[--%s]\n" , ExactInterpolation.name );
174171
printf( "\t[--%s <pull factor>=%f]\n" , DataX.name , DataX.value );
@@ -327,7 +324,6 @@ void Execute( const AuxDataFactory &auxDataFactory )
327324
sParams.pointWeight = (Real)PointWeight.value;
328325
sParams.samplesPerNode = (Real)SamplesPerNode.value;
329326
sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value;
330-
sParams.targetValue = (Real)TargetValue.value;
331327
sParams.perLevelDataScaleFactor = (Real)DataX.value;
332328
sParams.depth = (unsigned int)Depth.value;
333329
sParams.baseDepth = (unsigned int)BaseDepth.value;

Src/PreProcessor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ DAMAGE.
4646
#define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15.
4747
#endif // BIG_DATA
4848

49-
#define ADAPTIVE_SOLVERS_VERSION "18.35" // The version of the code
49+
#define ADAPTIVE_SOLVERS_VERSION "18.40" // The version of the code
5050
#define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation
5151

5252
#define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth

0 commit comments

Comments
 (0)