function [ptCloudPath,labelsPath,weights] = helperCropPointCloudsAndMergeLabels( ...
    gridSize,datasetPath,numPoints,writeFiles,numClasses)
% helperCropPointCloudsAndMergeLabels is used to crop and store the point
% cloud and it's corresponding labels according to the grid sizes.
%
%   This is an example helper function that is subject to change or removal
%   in future releases.

% Copyright 2021 MathWorks, Inc.
weights = ones(1,numClasses);
fileNames = dir(datasetPath);
ptCloudPath = fullfile(datasetPath,'PointCloud');
labelsPath =  fullfile(datasetPath,'Labels');
num = 1;
if writeFiles
    weights = zeros(1,numClasses);
    for j = 1:size(fileNames,1)
        if ~endsWith(fileNames(j).name,'las') && ...
                ~endsWith(fileNames(j).name,'laz')
            continue;
        end
        filePath = fullfile(fileNames(j).folder,fileNames(j).name);
        lasReader = lasFileReader(filePath);
        [pc,attr] = readPointCloud(lasReader, ...
            'Attributes','Classification');
        labels = attr.Classification;
        pc = select(pc,labels~=0);
        labels = labels(labels~=0);
        weights = weights + helperCalculateWeights(labels,numClasses);

        % Calculate the number of grids.
        numGridsX = round(diff(pc.XLimits)/gridSize(1));
        numGridsY = round(diff(pc.YLimits)/gridSize(2));

        [~,~,~,indx,indy] = histcounts2(pc.Location(:,1), ...
            pc.Location(:,2),[numGridsX,numGridsY], ...
            'XBinLimits',pc.XLimits,'YBinLimits',pc.YLimits);
        ind = sub2ind([numGridsX,numGridsY],indx,indy);

        for i=1:numGridsX*numGridsY
            idx = ind==i;
            ptCloudDense = select(pc,idx);
            labelsDense= labels(idx);

            [ptCloudSparse,labelsSparse] = helperDownsamplePoints( ...
                ptCloudDense,labelsDense,numPoints);

            limits = [ptCloudDense.XLimits;ptCloudDense.YLimits;...
                ptCloudDense.ZLimits];
            ptCloudSparseLocation = ptCloudSparse.Location;
            ptCloudSparseLocation(1:2,:) = limits(:,1:2)';
            ptCloudSparseUpdated = pointCloud(ptCloudSparseLocation, ...
                'Intensity',ptCloudSparse.Intensity, ...
                'Color',ptCloudSparse.Color, ...
                'Normal',ptCloudSparse.Normal);

            ptCloudOutSparse = helperNormalizePointCloud( ...
                ptCloudSparseUpdated);
            labelsOutSparse = permute(labelsSparse,[1,3,2]);

            if ~exist(ptCloudPath, 'dir')
                mkdir(ptCloudPath)
            end
            ptCloudSavePath = fullfile(ptCloudPath, ...
                sprintf('%03d.pcd',num));
            if ~exist(labelsPath, 'dir')
                mkdir(labelsPath)
            end
            labelsSavePath = fullfile(labelsPath, ...
                sprintf('%03d.png',num));

            % Save the point cloud as pcd and image in png format
            % in the given locations
            pcwrite(ptCloudOutSparse,ptCloudSavePath);
            imwrite(labelsOutSparse,labelsSavePath);
            num = num+1;
        end
    end
end
end


function weights = helperCalculateWeights(labels, numClasses)
% helperCalculateWeights computes weights of each class in the point cloud.
%
%   This is an example helper function that is subject to change or removal
%   in future releases.

% Copyright 2021 MathWorks, Inc.
weights = zeros(1,numClasses);
for i=1:numClasses
    weights(i) = sum(labels==i);
end
end
