Skip to content

Commit

Permalink
Merge pull request #75 from fwilliams/update_numpyeigen
Browse files Browse the repository at this point in the history
  • Loading branch information
fwilliams authored Sep 10, 2023
2 parents 2ff54e9 + 0526892 commit cf0c166
Show file tree
Hide file tree
Showing 27 changed files with 59 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"${workspaceFolder}/external/geogram/src/lib",
"${workspaceFolder}/src",
"${workspaceFolder}/external",
"${env:CONDA_PREFIX}/envs/point-cloud-utils/include/python3.9"
"${env:CONDA_PREFIX}/envs/point-cloud-utils/include/python3.10",
"${env:CONDA_PREFIX}/envs/point-cloud-utils/lib/python3.10/site-packages/numpy/core/include/"
],
"macFrameworkPath": [
"${default}"
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ set(EXTERNAL_DEP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)
include(DownloadExternalDeps)
download_dep(numpyeigen
GIT_REPOSITORY https://github.com/fwilliams/numpyeigen.git
GIT_TAG 70f3f100f23e9fc5888edcfd9ad38312b222c7ea
GIT_TAG master
)
list(APPEND CMAKE_MODULE_PATH ${EXTERNAL_DEP_DIR}/numpyeigen/cmake)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Expand Down
5 changes: 2 additions & 3 deletions point_cloud_utils/_point_cloud_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@ def _validate_point_radius_internal(p, r):
def voxel_grid_geometry(ijk, voxel_size=np.array((1., 1., 1.)), voxel_origin=np.array((0., 0., 0.)), gap_fraction=0.0):
"""
Generate a triangle mesh of cubes for voxel coordinates ijk. The [0, 0, 0] voxel has its
bottom-back-left corner at voxel_origin and each voxel has voxel_size.
center at voxel_origin and each voxel has voxel_size.
Args:
ijk np.ndarray: [num_voxels, 3] array of integer voxel coordinates
voxel_size: Float or triple representing the size of each voxel.
Defaults to np.array((1., 1., 1.)).
voxel_origin: Bottom-back-left coordinate of the [0, 0, 0] voxel.
Defaults to np.array((0., 0., 0.)).
voxel_origin: Center coordinate of the [0, 0, 0] voxel. Defaults to np.array((0., 0., 0.)).
gap_fraction: Fraction of a voxel to leave as a gap between voxels (default 0.0)
Returns:
Expand Down
2 changes: 1 addition & 1 deletion src/closest_point_on_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Compute distances from a set of points p to a triangle mesh (v, f)
npe_function(closest_points_on_mesh)
npe_arg(p, dense_float, dense_double)
npe_arg(v, npe_matches(p))
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_doc(closest_points_on_mesh_doc)
npe_begin_code()
{
Expand Down
2 changes: 1 addition & 1 deletion src/connected_components.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Determine the connected components of a mesh
npe_function(connected_components)
npe_doc(connected_components_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
Eigen::SparseMatrix<npe_Scalar_f> A;
Expand Down
6 changes: 3 additions & 3 deletions src/curvature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Estimate principal curvature directions and magnitudes for a mesh
)Qu8mg5v7";
npe_function(mesh_principal_curvatures)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_default_arg(r, double, -1.0)
npe_doc(mesh_principal_curvatures_doc)
npe_begin_code()
Expand Down Expand Up @@ -94,7 +94,7 @@ npe_end_code()
//)Qu8mg5v7";
//npe_function(mesh_mean_and_gaussian_curvatures)
//npe_arg(v, dense_float, dense_double)
//npe_arg(f, dense_int, dense_long, dense_longlong)
//npe_arg(f, dense_int32, dense_int64)
//npe_doc(mesh_mean_and_gaussian_curvatures_doc)
//npe_begin_code()
//{
Expand Down Expand Up @@ -122,7 +122,7 @@ npe_end_code()
//)Qu8mg5v7";
//npe_function(pointcloud_apss_curvature)
//npe_arg(v, dense_float, dense_double)
//npe_arg(f, dense_int, dense_long, dense_longlong)
//npe_arg(f, dense_int32, dense_int64)
//npe_doc(pointcloud_apss_curvature_doc)
//npe_begin_code()
//{
Expand Down
2 changes: 1 addition & 1 deletion src/face_areas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Compute the areas of each face of a triangle mesh
)Qu8mg5v7";
npe_function(mesh_face_areas)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64)
npe_default_arg(num_threads, int, -1)
npe_doc(triangle_mesh_face_areas_doc)
npe_begin_code()
Expand Down
2 changes: 1 addition & 1 deletion src/fast_winding_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ at a set of query points
)igl_Qu8mg5v7";
npe_function(triangle_soup_fast_winding_number)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(p, npe_matches(v))
npe_doc(triangle_soup_fast_winding_number_doc)
npe_begin_code()
Expand Down
2 changes: 1 addition & 1 deletion src/flood_fill_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void flood_fill(EigenMat& grid,


npe_function(_flood_fill_3d_internal)
npe_arg(grid, dense_int, dense_long, dense_longlong, dense_float, dense_double)
npe_arg(grid, dense_int32, dense_int64, dense_float, dense_double)
npe_arg(seed_x, int)
npe_arg(seed_y, int)
npe_arg(seed_z, int)
Expand Down
2 changes: 1 addition & 1 deletion src/lloyd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ Lloyd's algorithm (https://en.wikipedia.org/wiki/Lloyd%27s_algorithm).

npe_function(sample_mesh_lloyd)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(num_samples, int)
npe_default_arg(num_lloyd, int, 10)
npe_default_arg(num_newton, int, 10)
Expand Down
2 changes: 1 addition & 1 deletion src/manifold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Convert a mesh into a watertight manifold using the [Manifold](https://arxiv.org
)igl_Qu8mg5v7";
npe_function(make_mesh_watertight)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_default_arg(resolution, double, 20000)
npe_default_arg(seed, int, -1)
npe_doc(make_mesh_watertight_doc)
Expand Down
2 changes: 1 addition & 1 deletion src/marching_cubes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ See Also:
npe_function(marching_cubes_sparse_voxel_grid)
npe_arg(grid_scalars, dense_float, dense_double)
npe_arg(grid_coordinates, dense_float, dense_double)
npe_arg(cube_indices, dense_int, dense_long, dense_longlong)
npe_arg(cube_indices, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(isovalue, double)
npe_doc(marching_cubes_sparse_voxel_grid_doc)
npe_begin_code()
Expand Down
2 changes: 1 addition & 1 deletion src/mesh_decimate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Decimate a (manifold) triangle mesh by collapsing edges
)Qu8mg5v7";
npe_function(decimate_triangle_mesh)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(max_faces, int)
npe_default_arg(decimation_heuristic, std::string, "shortest_edge")
npe_doc(decimate_triangle_mesh_doc)
Expand Down
13 changes: 6 additions & 7 deletions src/mesh_for_voxels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace {
const MatrixIJK& in_ijk,
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& out_v,
Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& out_f) {

std::array<int, 36> indices = {
//Top
2, 7, 6,
Expand Down Expand Up @@ -60,7 +59,7 @@ namespace {
Eigen::Vector3d vertex(vertices[vi * 3 + 0] * (1.0 - gap_fraction) + 0.5 * gap_fraction,
vertices[vi * 3 + 1] * (1.0 - gap_fraction) + 0.5 * gap_fraction,
vertices[vi * 3 + 2] * (1.0 - gap_fraction) + 0.5 * gap_fraction);
Eigen::Vector3d voxel_translation(in_ijk(i, 0), in_ijk(i, 1), in_ijk(i, 2));
Eigen::Vector3d voxel_translation((double) in_ijk(i, 0), (double) in_ijk(i, 1), (double) in_ijk(i, 2));
vertex += voxel_translation;
vertex.array() *= vox_size.array();
vertex += vox_origin;
Expand All @@ -82,10 +81,10 @@ namespace {


npe_function(_voxel_mesh_internal)
npe_arg(ijk, dense_int, dense_long, dense_longlong)
npe_arg(ijk, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(gap_fraction, double)
npe_arg(vox_origin, dense_double)
npe_arg(vox_size, dense_double)
npe_arg(vox_origin, dense_float, dense_double)
npe_arg(vox_size, dense_float, dense_double)
npe_begin_code()
using MatrixI = Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
using MatrixF = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
Expand All @@ -99,12 +98,12 @@ npe_begin_code()
throw pybind11::value_error("Invalid shape");
}

Eigen::Vector3d vsize = vox_size;
Eigen::Vector3d vsize = vox_size.template cast<double>();

if (vsize[0] <= 0.0 || vsize[1] <= 0.0 || vsize[2] <= 0.0) {
throw pybind11::value_error("Voxel size must be positive");
}
Eigen::Vector3d vorgn = vox_origin;
Eigen::Vector3d vorgn = vox_origin.template cast<double>();

MatrixF geom_vertices;
MatrixI geom_faces;
Expand Down
4 changes: 2 additions & 2 deletions src/mesh_normals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Compute vertex normals of a mesh from its vertices and faces using face area wei
npe_function(estimate_mesh_vertex_normals)
npe_doc(estimate_mesh_vertex_normals_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_default_arg(weighting_type, std::string, std::string("uniform"))
npe_begin_code()
{
Expand Down Expand Up @@ -65,7 +65,7 @@ Compute vertex normals of a mesh from its vertices and faces using face area wei
npe_function(estimate_mesh_face_normals)
npe_doc(estimate_mesh_face_normals_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
validate_mesh(v, f);
Expand Down
14 changes: 7 additions & 7 deletions src/morton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Add morton codes together (corresponding to adding the vectors they encode)
)Qu8mg5v7";
npe_function(morton_add)
npe_arg(codes_1, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes_2, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes_1, dense_uint32, dense_uint64)
npe_arg(codes_2, dense_uint32, dense_uint64)
npe_default_arg(num_threads, int, -1)
npe_doc(morton_add)
npe_begin_code()
Expand Down Expand Up @@ -104,8 +104,8 @@ Subtract morton codes from each other (corresponding to adding the vectors they

)Qu8mg5v7";
npe_function(morton_subtract)
npe_arg(codes_1, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes_2, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes_1, dense_uint32, dense_uint64)
npe_arg(codes_2, dense_uint32, dense_uint64)
npe_default_arg(num_threads, int, -1)
npe_doc(morton_subtract)
npe_begin_code()
Expand Down Expand Up @@ -183,7 +183,7 @@ Encode n 3D points using Morton coding, possibly sorting them

)Qu8mg5v7";
npe_function(morton_encode)
npe_arg(pts, dense_int, dense_long, dense_longlong)
npe_arg(pts, dense_int32, dense_int64)
npe_default_arg(num_threads, int, -1)
npe_doc(morton_encode)
npe_begin_code()
Expand Down Expand Up @@ -251,7 +251,7 @@ Decode n points along a Morton curve into 3D points

)Qu8mg5v7";
npe_function(morton_decode)
npe_arg(codes, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes, dense_uint32, dense_uint64)
npe_doc(morton_decode)
npe_default_arg(num_threads, int, -1)
npe_begin_code()
Expand Down Expand Up @@ -322,7 +322,7 @@ Queries a sorted array of morton encoded points to find the (approximate) k near

)Qu8mg5v7";
npe_function(morton_knn)
npe_arg(codes, dense_uint, dense_ulong, dense_ulonglong)
npe_arg(codes, dense_uint32, dense_uint64)
npe_arg(qcodes, npe_matches(codes))
npe_arg(k, int)
npe_default_arg(sort_dist, bool, true)
Expand Down
2 changes: 1 addition & 1 deletion src/orient_mesh_faces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Consistently orient faces of a mesh within each connected component
)igl_Qu8mg5v7";
npe_function(orient_mesh_faces)
npe_doc(orient_mesh_faces_doc)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_default_arg(weighting_type, std::string, std::string("uniform"))
npe_begin_code()
{
Expand Down
2 changes: 1 addition & 1 deletion src/point_areas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ at a set of query points
)igl_Qu8mg5v7";
npe_function(estimate_point_cloud_areas)
npe_arg(p, dense_float, dense_double)
npe_arg(i, dense_int, dense_long, dense_longlong)
npe_arg(i, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(n, npe_matches(v))
npe_doc(estimate_point_cloud_areas_doc)
npe_begin_code()
Expand Down
4 changes: 2 additions & 2 deletions src/ray_mesh_intersection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void hack_extra_ray_mesh_bindings(pybind11::module& m) {

npe_function(_populate_ray_intersector_internal)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(isector, std::shared_ptr<igl::embree::EmbreeIntersector>)
npe_begin_code()
igl::embree::EmbreeIntersector::PointMatrixType v_copy = v.template cast<float>();
Expand Down Expand Up @@ -106,7 +106,7 @@ Compute intersection between a set of rays and a triangle mesh
)Qu8mg5v7";
npe_function(ray_mesh_intersection)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(ray_o, npe_matches(v))
npe_arg(ray_d, npe_matches(v))
npe_default_arg(ray_near, double, 0.0)
Expand Down
2 changes: 1 addition & 1 deletion src/remove_duplicates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ See also:
npe_function(deduplicate_mesh_vertices)
npe_doc(remove_duplicate_mesh_vertices_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(epsilon, double)
npe_default_arg(return_index, bool, true)
npe_begin_code()
Expand Down
2 changes: 1 addition & 1 deletion src/remove_unreferenced_mesh_vertices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ some threshold
npe_function(remove_unreferenced_mesh_vertices)
npe_doc(remove_unreferenced_mesh_vertices_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
validate_mesh(v, f);
Expand Down
4 changes: 2 additions & 2 deletions src/sample_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Downsample a point set (possibly on a mesh) so that samples are approximately ev
)Qu8mg5v7";
npe_function(sample_mesh_poisson_disk)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(num_samples, int)
npe_default_arg(radius, double, 0.0)
npe_default_arg(use_geodesic_distance, bool, true)
Expand Down Expand Up @@ -231,7 +231,7 @@ Generate uniformly distributed random point samples on a mesh
)Qu8mg5v7";
npe_function(sample_mesh_random)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(num_samples, int)
npe_default_arg(random_seed, unsigned int, 0)
npe_doc(sample_mesh_random_doc)
Expand Down
2 changes: 1 addition & 1 deletion src/signed_distance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Computes signed distances of a point cloud with respect to a Mesh using Fast Win
npe_function(signed_distance_to_mesh)
npe_arg(p, dense_float, dense_double)
npe_arg(v, npe_matches(p))
npe_arg(f, dense_int, dense_long, dense_longlong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_default_arg(lower_bound, float, -std::numeric_limits<float>::infinity())
npe_default_arg(upper_bound, float, std::numeric_limits<float>::infinity())
npe_doc(signed_distance_doc)
Expand Down
2 changes: 1 addition & 1 deletion src/smooth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Smooth a mesh using Laplacian smoothing
npe_function(laplacian_smooth_mesh)
npe_doc(laplacian_smooth_mesh_doc)
npe_arg(v, dense_float, dense_double)
npe_arg(f, dense_int, dense_longlong, dense_uint, dense_ulonglong)
npe_arg(f, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(num_iters, int)
npe_default_arg(use_cotan_weights, bool, false)
npe_begin_code()
Expand Down
10 changes: 5 additions & 5 deletions src/sparse_voxel_grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ npe_end_code()


npe_function(dilate_sparse_voxel_grid_internal)
npe_arg(grid_coordinates, dense_int, dense_long, dense_longlong)
npe_arg(grid_coordinates, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
validate_sparse_voxel_grid(grid_coordinates);
Expand Down Expand Up @@ -244,7 +244,7 @@ npe_end_code()


npe_function(erode_sparse_voxel_grid_internal)
npe_arg(grid_coordinates, dense_int, dense_long, dense_longlong)
npe_arg(grid_coordinates, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
validate_sparse_voxel_grid(grid_coordinates);
Expand Down Expand Up @@ -327,7 +327,7 @@ npe_end_code()


npe_function(subdivide_sparse_voxel_grid_internal)
npe_arg(grid_coordinates, dense_int, dense_long, dense_longlong)
npe_arg(grid_coordinates, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_begin_code()
{
validate_sparse_voxel_grid(grid_coordinates);
Expand Down Expand Up @@ -383,7 +383,7 @@ npe_end_code()


npe_function(sparse_voxel_grid_to_hex_mesh_internal)
npe_arg(grid_coordinates, dense_int, dense_long, dense_longlong)
npe_arg(grid_coordinates, dense_int32, dense_int64, dense_uint32, dense_uint64)
npe_arg(gx, double) // voxel size along x
npe_arg(gy, double) // voxel size along y
npe_arg(gz, double) // voxel size along z
Expand Down Expand Up @@ -471,7 +471,7 @@ Find the indices of the voxels which lie on the boundary of a sparse voxel grid

)Qu8mg5v7";
npe_function(sparse_voxel_grid_boundary)
npe_arg(grid_coordinates, dense_int, dense_long, dense_longlong)
npe_arg(grid_coordinates, dense_int32, dense_int64, dense_uint32, dense_uint64)
// npe_doc(sparse_voxel_grid_boundary_doc)
npe_begin_code()
{
Expand Down
Loading

0 comments on commit cf0c166

Please sign in to comment.