<commit_before>// ImageProcessor
// Class to handle the processing of the image sequence

#include "imageProcessor.h"

ImageProcessor::ImageProcessor()
{
    width = 480;
    height = 480;

    minVal = 0;
    maxVal = 255;
    bucketSize = 8;
    buckets = (maxVal + 1) / bucketSize;
}

ImageProcessor::~ImageProcessor()
{
    if (bucketData)
        delete bucketData;
}

// Set input file sequence
void ImageProcessor::setFiles(std::vector<std::string> fn)
{
    fileNames = fn;

    inferParameters();
    initializeData();
}

// Infer processor parameters from the first file
void ImageProcessor::inferParameters()
{
    if (fileNames.size() <= 0)
    {
        std::cerr << "Image list empty. Exiting." << std::endl;
        exit(EXIT_FAILURE);
    }

    frames = fileNames.size();

    cimg::CImg<unsigned char> inspectImage(fileNames[0].c_str());
    width = inspectImage.width();
    height = inspectImage.height();
    channels = inspectImage.spectrum();

    std::cout << "Image data" << std::endl;
    std::cout << "\tFrames:\t\t" << frames << std::endl;
    std::cout << "\tWidth:\t\t" << width << std::endl;
    std::cout << "\tHeight:\t\t" << height << std::endl;
    std::cout << "\tChannels:\t" << channels << std::endl;
}

// Set up the data structure to store bucket information
void ImageProcessor::initializeData()
{
    bucketData = new BucketData(width, height, buckets);
}

// Set the size of a bucket in terms of color intensity values
void ImageProcessor::setBucketSize(int newSize)
{
    bucketSize = newSize;
    buckets = (maxVal + 1) / bucketSize;
}

// Find the correspoding A Bucket for the color intensity value
int ImageProcessor::getABucket(int value)
{
    if (value < minVal)
        return 0;

    if (value > maxVal)
        return buckets - 1;

    return value / bucketSize;
}

// Find the corresponding B Bucket for the color intensity value
int ImageProcessor::getBBucket(int value)
{
    value += bucketSize / 2;

    if (value < minVal)
        return 0;

    if (value > maxVal - bucketSize / 2)
        return buckets - 1;

    return value / bucketSize;
}

// Process the image sequence and create final output
void ImageProcessor::processSequence()
{
    countBuckets();
    findBiggestBucket();
    refineSolution();
    createFinal();
}

// Read the image files and count the pixel values into buckets
void ImageProcessor::countBuckets()
{
    std::cout << std::endl << "Reading:\t";

    // Read image frames and count the buckets
    for (auto &file : fileNames)
    {
        cimg::CImg<unsigned char> newImage(file.c_str());

        std::cout << "|";

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int redPixel = newImage(i, j, 0, 0);
                int greenPixel = newImage(i, j, 0, 1);
                int bluePixel = newImage(i, j, 0, 2);

                int a_bucket = getABucket(redPixel);
                bucketData->redBucketA[i + j * width + a_bucket * (width * height)]++;

                int b_bucket = getBBucket(redPixel);
                bucketData->redBucketB[i + j * width + b_bucket * (width * height)]++;

                a_bucket = getABucket(greenPixel);
                bucketData->greenBucketA[i + j * width + a_bucket * (width * height)]++;

                b_bucket = getBBucket(greenPixel);
                bucketData->greenBucketB[i + j * width + b_bucket * (width * height)]++;

                a_bucket = getABucket(bluePixel);
                bucketData->blueBucketA[i + j * width + a_bucket * (width * height)]++;

                b_bucket = getBBucket(bluePixel);
                bucketData->blueBucketB[i + j * width + b_bucket * (width * height)]++;
            }
        }
    }
}

// Find the biggest bucket for each pixel
void ImageProcessor::findBiggestBucket()
{
    // Find the biggest bucket
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            // Red channel
            {
                int redMaxCount = 0;
                int redMaxBucket = -1;
                bool redMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->redBucketA[i + j * width + bucket * (width * height)] > redMaxCount)
                    {
                        redMaxCount = bucketData->redBucketA[i + j * width + bucket * (width * height)];
                        redMaxBucket = bucket;
                        redMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > redMaxCount)
                    {
                        redMaxCount = bucketData->redBucketB[i + j * width + bucket * (width * height)];
                        redMaxBucket = bucket;
                        redMaxTypeA = false;
                    }
                }

                bucketData->redFinalBucket[idx].id = redMaxBucket;
                bucketData->redFinalBucket[idx].isABucket = redMaxTypeA;
                bucketData->redFinalBucket[idx].diff = redMaxCount;
            }

            // Green channel
            {
                int greenMaxCount = 0;
                int greenMaxBucket = -1;
                bool greenMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->greenBucketA[i + j * width + bucket * (width * height)] > greenMaxCount)
                    {
                        greenMaxCount = bucketData->greenBucketA[i + j * width + bucket * (width * height)];
                        greenMaxBucket = bucket;
                        greenMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > greenMaxCount)
                    {
                        greenMaxCount = bucketData->greenBucketB[i + j * width + bucket * (width * height)];
                        greenMaxBucket = bucket;
                        greenMaxTypeA = false;
                    }
                }

                bucketData->greenFinalBucket[idx].id = greenMaxBucket;
                bucketData->greenFinalBucket[idx].isABucket = greenMaxTypeA;
                bucketData->greenFinalBucket[idx].diff = greenMaxCount;
            }

            // Blue channel
            {
                int blueMaxCount = 0;
                int blueMaxBucket = -1;
                bool blueMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->redBucketA[i + j * width + bucket * (width * height)] > blueMaxCount)
                    {
                        blueMaxCount = bucketData->blueBucketA[i + j * width + bucket * (width * height)];
                        blueMaxBucket = bucket;
                        blueMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > blueMaxCount)
                    {
                        blueMaxCount = bucketData->blueBucketB[i + j * width + bucket * (width * height)];
                        blueMaxBucket = bucket;
                        blueMaxTypeA = false;
                    }
                }

                bucketData->blueFinalBucket[idx].id = blueMaxBucket;
                bucketData->blueFinalBucket[idx].isABucket = blueMaxTypeA;
                bucketData->blueFinalBucket[idx].diff = blueMaxCount;
            }
        }
    }
}

// Optional step to let neighboring buckets with stronger confidence influence the bucket values of
// weak confidence pixels
void ImageProcessor::refineSolution()
{
    short int confidenceLow = (short int)(0.5f * frames);
    short int confidenceHigh = (short int)(0.75f * frames);

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            // Check to see if the pixel has a low-confidence solution
            if (bucketData->greenFinalBucket[idx].diff < confidenceLow)
            {
                bool done = false;

                // Iterate through the pixel neighborhood for high confidence values
                for (int m = i - 1; m < i + 1 && !done; m++)
                {
                    for (int n = j - 1; n < j + 1 && !done; n++)
                    {
                        if (m >= 0 && m < width && n >= 0 && n < height)
                        {
                            int neighIndex = m + n * width;

                            if (bucketData->greenFinalBucket[neighIndex].diff > confidenceHigh)
                            {
                                // Replace the current pixel's bucket with the neighbor's
                                bucketData->greenFinalBucket[idx] = bucketData->greenFinalBucket[neighIndex];
                                // Zero out the confidence
                                bucketData->greenFinalBucket[idx].diff = 0;

                                // Break out of the two innermost loops
                                done = true;
                            }
                        }
                    }
                }
            }
        }
    }
}

// Create final color image and a confidence mask, then display them
void ImageProcessor::createFinal()
{
    std::vector<float> accRed(width * height);
    std::vector<float> accGreen(width * height);
    std::vector<float> accBlue(width * height);
    std::vector<int> count(width * height);

    std::cout << std::endl << "Averaging:\t";

    // Average out all the pixel values from the biggest bucket
    for (auto &file : fileNames)
    {
        cimg::CImg<unsigned char> newImage(file.c_str());

        std::cout << "|";

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int idx = i + j * width;

                int pixelRed = newImage(i, j, 0, 0);
                int pixelGreen = newImage(i, j, 0, 1);
                int pixelBlue = newImage(i, j, 0, 2);

                // Test red
//                BucketEntry redEntry = bucketData->redFinalBucket[i + j * width];

//                if (redEntry.isABucket && redEntry.id != getABucket(pixelRed))
//                    continue;

//                if (!redEntry.isABucket && redEntry.id != getBBucket(pixelRed))
//                    continue;

                // Test green
                BucketEntry greenEntry = bucketData->greenFinalBucket[idx];

                if (greenEntry.isABucket && greenEntry.id != getABucket(pixelGreen))
                    continue;

                if (!greenEntry.isABucket && greenEntry.id != getBBucket(pixelGreen))
                    continue;

                // Test blue
//                BucketEntry blueEntry = bucketData->blueFinalBucket[i + j * width];

//                if (blueEntry.isABucket && blueEntry.id != getABucket(pixelBlue))
//                    continue;

//                if (!blueEntry.isABucket && blueEntry.id != getBBucket(pixelBlue))
//                    continue;

                accRed[i + j * width] += pixelRed;
                accGreen[i + j * width] += pixelGreen;
                accBlue[i + j * width] += pixelBlue;
                count[i + j * width]++;

                // OLD CODE OLD CODE
                //if (bucketData->redFinalBucket[i + j * width].isABucket)
                //{
                //	int pixABucket = getABucket(pixelRed);

                //	if (pixABucket == bucketData->redFinalBucket[i + j * width].id)
                //	{
                //		accRed[i + j * width] += pixelRed;
                //		accGreen[i + j * width] += newImage(i, j, 0, 1);
                //		accBlue[i + j * width] += newImage(i, j, 0, 2);
                //		count[i + j * width]++;
                //	}
                //}
                //else
                //{
                //	int pixBBucket = getBBucket(pixelRed);

                //	if (pixBBucket == bucketData->redFinalBucket[i + j * width].id)
                //	{
                //		accRed[i + j * width] += pixelRed;
                //		accGreen[i + j * width] += newImage(i, j, 0, 1);
                //		accBlue[i + j * width] += newImage(i, j, 0, 2);
                //		count[i + j * width]++;
                //	}
                //}
                // OLD CODE OLD CODE
            }
        }
    }

    // Paint the final result in a window
    cimg::CImg<unsigned char> reconstructionImage(width, height, 1, 3, 0);
    cimg::CImgDisplay main_disp(width, height, "Reconstructed background");

    // Paint the confidence mask
    cimg::CImg<unsigned char> confidenceImage(width, height, 1, 3, 0);
    cimg::CImgDisplay aux_disp(width, height, "Confidence mask");

    // Paint the green buckets for debugging
    cimg::CImg<unsigned char> greenBucketImage(width, height, 1, 1, 0);
    cimg::CImgDisplay green_disp(width, height, "Green buckets");

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            reconstructionImage(i, j, 0, 0) = (unsigned char) (accRed[i + j * width] / count[i + j * width]);
            reconstructionImage(i, j, 0, 1) = (unsigned char) (accGreen[i + j * width] / count[i + j * width]);
            reconstructionImage(i, j, 0, 2) = (unsigned char) (accBlue[i + j * width] / count[i + j * width]);

            int confidence = (int) (count[i + j * width] * ((float)256.0f / frames));
            confidence = std::min(confidence, 255);

            confidenceImage(i, j, 0, 0) = (unsigned char) confidence;
            confidenceImage(i, j, 0, 1) = (unsigned char) confidence;
            confidenceImage(i, j, 0, 2) = (unsigned char) confidence;

            if(count[idx] < 1)
            {
                confidenceImage(i, j, 0, 0) = 255;
                confidenceImage(i, j, 0, 1) = 0;
                confidenceImage(i, j, 0, 2) = 0;
            }

            BucketEntry greenEntry = bucketData->greenFinalBucket[i + j * width];
            unsigned char valueGreen = greenEntry.id * bucketSize;

            if(!greenEntry.isABucket)
                valueGreen -= bucketSize / 2;

            greenBucketImage(i, j, 0, 0) = valueGreen;

        }
        main_disp.render(reconstructionImage);
        main_disp.paint();

        aux_disp.render(confidenceImage);
        aux_disp.paint();

        green_disp.render(greenBucketImage);
        green_disp.paint();
    }

    std::cout << std::endl;

    // Write the final color image to file
    std::remove("output.png");
    reconstructionImage.save_png("output.png");

    // Write out the confidence mask
    std::remove("confidence.png");
    confidenceImage.save_png("confidence.png");

    while (!main_disp.is_closed())
    {
        main_disp.wait();
    }
}
<commit_msg>Cleaned up index notation with precalculated variable<commit_after>// ImageProcessor
// Class to handle the processing of the image sequence

#include "imageProcessor.h"

ImageProcessor::ImageProcessor()
{
    width = 480;
    height = 480;

    minVal = 0;
    maxVal = 255;
    bucketSize = 8;
    buckets = (maxVal + 1) / bucketSize;
}

ImageProcessor::~ImageProcessor()
{
    if (bucketData)
        delete bucketData;
}

// Set input file sequence
void ImageProcessor::setFiles(std::vector<std::string> fn)
{
    fileNames = fn;

    inferParameters();
    initializeData();
}

// Infer processor parameters from the first file
void ImageProcessor::inferParameters()
{
    if (fileNames.size() <= 0)
    {
        std::cerr << "Image list empty. Exiting." << std::endl;
        exit(EXIT_FAILURE);
    }

    frames = fileNames.size();

    cimg::CImg<unsigned char> inspectImage(fileNames[0].c_str());
    width = inspectImage.width();
    height = inspectImage.height();
    channels = inspectImage.spectrum();

    std::cout << "Image data" << std::endl;
    std::cout << "\tFrames:\t\t" << frames << std::endl;
    std::cout << "\tWidth:\t\t" << width << std::endl;
    std::cout << "\tHeight:\t\t" << height << std::endl;
    std::cout << "\tChannels:\t" << channels << std::endl;
}

// Set up the data structure to store bucket information
void ImageProcessor::initializeData()
{
    bucketData = new BucketData(width, height, buckets);
}

// Set the size of a bucket in terms of color intensity values
void ImageProcessor::setBucketSize(int newSize)
{
    bucketSize = newSize;
    buckets = (maxVal + 1) / bucketSize;
}

// Find the correspoding A Bucket for the color intensity value
int ImageProcessor::getABucket(int value)
{
    if (value < minVal)
        return 0;

    if (value > maxVal)
        return buckets - 1;

    return value / bucketSize;
}

// Find the corresponding B Bucket for the color intensity value
int ImageProcessor::getBBucket(int value)
{
    value += bucketSize / 2;

    if (value < minVal)
        return 0;

    if (value > maxVal - bucketSize / 2)
        return buckets - 1;

    return value / bucketSize;
}

// Process the image sequence and create final output
void ImageProcessor::processSequence()
{
    countBuckets();
    findBiggestBucket();
    refineSolution();
    createFinal();
}

// Read the image files and count the pixel values into buckets
void ImageProcessor::countBuckets()
{
    std::cout << std::endl << "Reading:\t";

    // Read image frames and count the buckets
    for (auto &file : fileNames)
    {
        cimg::CImg<unsigned char> newImage(file.c_str());

        std::cout << "|";

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int redPixel = newImage(i, j, 0, 0);
                int greenPixel = newImage(i, j, 0, 1);
                int bluePixel = newImage(i, j, 0, 2);

                int a_bucket = getABucket(redPixel);
                bucketData->redBucketA[i + j * width + a_bucket * (width * height)]++;

                int b_bucket = getBBucket(redPixel);
                bucketData->redBucketB[i + j * width + b_bucket * (width * height)]++;

                a_bucket = getABucket(greenPixel);
                bucketData->greenBucketA[i + j * width + a_bucket * (width * height)]++;

                b_bucket = getBBucket(greenPixel);
                bucketData->greenBucketB[i + j * width + b_bucket * (width * height)]++;

                a_bucket = getABucket(bluePixel);
                bucketData->blueBucketA[i + j * width + a_bucket * (width * height)]++;

                b_bucket = getBBucket(bluePixel);
                bucketData->blueBucketB[i + j * width + b_bucket * (width * height)]++;
            }
        }
    }
}

// Find the biggest bucket for each pixel
void ImageProcessor::findBiggestBucket()
{
    // Find the biggest bucket
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            // Red channel
            {
                int redMaxCount = 0;
                int redMaxBucket = -1;
                bool redMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->redBucketA[i + j * width + bucket * (width * height)] > redMaxCount)
                    {
                        redMaxCount = bucketData->redBucketA[i + j * width + bucket * (width * height)];
                        redMaxBucket = bucket;
                        redMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > redMaxCount)
                    {
                        redMaxCount = bucketData->redBucketB[i + j * width + bucket * (width * height)];
                        redMaxBucket = bucket;
                        redMaxTypeA = false;
                    }
                }

                bucketData->redFinalBucket[idx].id = redMaxBucket;
                bucketData->redFinalBucket[idx].isABucket = redMaxTypeA;
                bucketData->redFinalBucket[idx].diff = redMaxCount;
            }

            // Green channel
            {
                int greenMaxCount = 0;
                int greenMaxBucket = -1;
                bool greenMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->greenBucketA[i + j * width + bucket * (width * height)] > greenMaxCount)
                    {
                        greenMaxCount = bucketData->greenBucketA[i + j * width + bucket * (width * height)];
                        greenMaxBucket = bucket;
                        greenMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > greenMaxCount)
                    {
                        greenMaxCount = bucketData->greenBucketB[i + j * width + bucket * (width * height)];
                        greenMaxBucket = bucket;
                        greenMaxTypeA = false;
                    }
                }

                bucketData->greenFinalBucket[idx].id = greenMaxBucket;
                bucketData->greenFinalBucket[idx].isABucket = greenMaxTypeA;
                bucketData->greenFinalBucket[idx].diff = greenMaxCount;
            }

            // Blue channel
            {
                int blueMaxCount = 0;
                int blueMaxBucket = -1;
                bool blueMaxTypeA = true;

                for (int bucket = 0; bucket < buckets; bucket++)
                {
                    if (bucketData->redBucketA[i + j * width + bucket * (width * height)] > blueMaxCount)
                    {
                        blueMaxCount = bucketData->blueBucketA[i + j * width + bucket * (width * height)];
                        blueMaxBucket = bucket;
                        blueMaxTypeA = true;
                    }
                    if (bucketData->redBucketB[i + j * width + bucket * (width * height)] > blueMaxCount)
                    {
                        blueMaxCount = bucketData->blueBucketB[i + j * width + bucket * (width * height)];
                        blueMaxBucket = bucket;
                        blueMaxTypeA = false;
                    }
                }

                bucketData->blueFinalBucket[idx].id = blueMaxBucket;
                bucketData->blueFinalBucket[idx].isABucket = blueMaxTypeA;
                bucketData->blueFinalBucket[idx].diff = blueMaxCount;
            }
        }
    }
}

// Optional step to let neighboring buckets with stronger confidence influence the bucket values of
// weak confidence pixels
void ImageProcessor::refineSolution()
{
    short int confidenceLow = (short int)(0.5f * frames);
    short int confidenceHigh = (short int)(0.75f * frames);

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            // Check to see if the pixel has a low-confidence solution
            if (bucketData->greenFinalBucket[idx].diff < confidenceLow)
            {
                bool done = false;

                // Iterate through the pixel neighborhood for high confidence values
                for (int m = i - 1; m < i + 1 && !done; m++)
                {
                    for (int n = j - 1; n < j + 1 && !done; n++)
                    {
                        if (m >= 0 && m < width && n >= 0 && n < height)
                        {
                            int neighIndex = m + n * width;

                            if (bucketData->greenFinalBucket[neighIndex].diff > confidenceHigh)
                            {
                                // Replace the current pixel's bucket with the neighbor's
                                bucketData->greenFinalBucket[idx] = bucketData->greenFinalBucket[neighIndex];
                                // Zero out the confidence
                                bucketData->greenFinalBucket[idx].diff = 0;

                                // Break out of the two innermost loops
                                done = true;
                            }
                        }
                    }
                }
            }
        }
    }
}

// Create final color image and a confidence mask, then display them
void ImageProcessor::createFinal()
{
    std::vector<float> accRed(width * height);
    std::vector<float> accGreen(width * height);
    std::vector<float> accBlue(width * height);
    std::vector<int> count(width * height);

    std::cout << std::endl << "Averaging:\t";

    // Average out all the pixel values from the biggest bucket
    for (auto &file : fileNames)
    {
        cimg::CImg<unsigned char> newImage(file.c_str());

        std::cout << "|";

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                int idx = i + j * width;

                int pixelRed = newImage(i, j, 0, 0);
                int pixelGreen = newImage(i, j, 0, 1);
                int pixelBlue = newImage(i, j, 0, 2);

                // Test red
//                BucketEntry redEntry = bucketData->redFinalBucket[i + j * width];

//                if (redEntry.isABucket && redEntry.id != getABucket(pixelRed))
//                    continue;

//                if (!redEntry.isABucket && redEntry.id != getBBucket(pixelRed))
//                    continue;

                // Test green
                BucketEntry greenEntry = bucketData->greenFinalBucket[idx];

                if (greenEntry.isABucket && greenEntry.id != getABucket(pixelGreen))
                    continue;

                if (!greenEntry.isABucket && greenEntry.id != getBBucket(pixelGreen))
                    continue;

                // Test blue
//                BucketEntry blueEntry = bucketData->blueFinalBucket[i + j * width];

//                if (blueEntry.isABucket && blueEntry.id != getABucket(pixelBlue))
//                    continue;

//                if (!blueEntry.isABucket && blueEntry.id != getBBucket(pixelBlue))
//                    continue;

                accRed[idx] += pixelRed;
                accGreen[idx] += pixelGreen;
                accBlue[idx] += pixelBlue;
                count[idx]++;

                // OLD CODE OLD CODE
                //if (bucketData->redFinalBucket[i + j * width].isABucket)
                //{
                //	int pixABucket = getABucket(pixelRed);

                //	if (pixABucket == bucketData->redFinalBucket[i + j * width].id)
                //	{
                //		accRed[i + j * width] += pixelRed;
                //		accGreen[i + j * width] += newImage(i, j, 0, 1);
                //		accBlue[i + j * width] += newImage(i, j, 0, 2);
                //		count[i + j * width]++;
                //	}
                //}
                //else
                //{
                //	int pixBBucket = getBBucket(pixelRed);

                //	if (pixBBucket == bucketData->redFinalBucket[i + j * width].id)
                //	{
                //		accRed[i + j * width] += pixelRed;
                //		accGreen[i + j * width] += newImage(i, j, 0, 1);
                //		accBlue[i + j * width] += newImage(i, j, 0, 2);
                //		count[i + j * width]++;
                //	}
                //}
                // OLD CODE OLD CODE
            }
        }
    }

    // Paint the final result in a window
    cimg::CImg<unsigned char> reconstructionImage(width, height, 1, 3, 0);
    cimg::CImgDisplay main_disp(width, height, "Reconstructed background");

    // Paint the confidence mask
    cimg::CImg<unsigned char> confidenceImage(width, height, 1, 3, 0);
    cimg::CImgDisplay aux_disp(width, height, "Confidence mask");

    // Paint the green buckets for debugging
    cimg::CImg<unsigned char> greenBucketImage(width, height, 1, 1, 0);
    cimg::CImgDisplay green_disp(width, height, "Green buckets");

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int idx = i + j * width;

            reconstructionImage(i, j, 0, 0) = (unsigned char) (accRed[i + j * width] / count[i + j * width]);
            reconstructionImage(i, j, 0, 1) = (unsigned char) (accGreen[i + j * width] / count[i + j * width]);
            reconstructionImage(i, j, 0, 2) = (unsigned char) (accBlue[i + j * width] / count[i + j * width]);

            int confidence = (int) (count[i + j * width] * ((float)256.0f / frames));
            confidence = std::min(confidence, 255);

            confidenceImage(i, j, 0, 0) = (unsigned char) confidence;
            confidenceImage(i, j, 0, 1) = (unsigned char) confidence;
            confidenceImage(i, j, 0, 2) = (unsigned char) confidence;

            if(count[idx] < 1)
            {
                confidenceImage(i, j, 0, 0) = 255;
                confidenceImage(i, j, 0, 1) = 0;
                confidenceImage(i, j, 0, 2) = 0;
            }

            BucketEntry greenEntry = bucketData->greenFinalBucket[i + j * width];
            unsigned char valueGreen = greenEntry.id * bucketSize;

            if(!greenEntry.isABucket)
                valueGreen -= bucketSize / 2;

            greenBucketImage(i, j, 0, 0) = valueGreen;

        }
        main_disp.render(reconstructionImage);
        main_disp.paint();

        aux_disp.render(confidenceImage);
        aux_disp.paint();

        green_disp.render(greenBucketImage);
        green_disp.paint();
    }

    std::cout << std::endl;

    // Write the final color image to file
    std::remove("output.png");
    reconstructionImage.save_png("output.png");

    // Write out the confidence mask
    std::remove("confidence.png");
    confidenceImage.save_png("confidence.png");

    while (!main_disp.is_closed())
    {
        main_disp.wait();
    }
}
<|endoftext|>


<commit_before>#include "BeaconTile.h"

Tile* BeaconTile::beacon = NULL;

BeaconTile::BeaconTile(int id) : Tile(id, &Material::metal) {
	tex = getTextureUVCoordinateSet("glass", 0);
	secondary_tex = getTextureUVCoordinateSet("obsidian", 0);
	terciary_tex = getTextureUVCoordinateSet("beacon", 0);
	//fourth_tex = getTextureUVCoordinateSet("beacon_beam", 0);
	//fifth_tex = getTextureUVCoordinateSet("beacon_beam", 1);
	beacon->renderPass = Tile::glass->renderPass;
	Tile::solid[id] = false;
	Tile::lightBlock[id] = 0;
	new TileItem(id - 256);
}

bool BeaconTile::isCubeShaped() {
     return false;
}

bool BeaconTile::isSolidRender() {
     return false;
}

const TextureUVCoordinateSet& BeaconTile::getTexture(signed char side, int data) {
	return side == 0 ? tex : (side == 1 ? secondary_tex : terciary_tex);
}
<commit_msg>Hopefully fix the beacon.<commit_after>#include "BeaconTile.h"

Tile* BeaconTile::beacon = NULL;

BeaconTile::BeaconTile(int id) : Tile(id, &Material::metal) {
	tex = getTextureUVCoordinateSet("glass", 0);
	secondary_tex = getTextureUVCoordinateSet("obsidian", 0);
	terciary_tex = getTextureUVCoordinateSet("diamond_block", 0);
	//fourth_tex = getTextureUVCoordinateSet("beacon_beam", 0);
	//fifth_tex = getTextureUVCoordinateSet("beacon_beam", 1);
	beacon->renderPass = Tile::glass->renderPass;
	Tile::solid[id] = false;
	Tile::lightBlock[id] = 0;
	new TileItem(id - 256);
}

bool BeaconTile::isCubeShaped() {
     return false;
}

bool BeaconTile::isSolidRender() {
     return false;
}

const TextureUVCoordinateSet& BeaconTile::getTexture(signed char side, int data) {
	return side == 0 ? tex : (side == 1 ? secondary_tex : terciary_tex);
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "monitor.h"
#include "monitor_p.h"

#include "collectionlistjob.h"
#include "collectionstatusjob.h"
#include "itemfetchjob.h"
#include "notificationmanagerinterface.h"
#include "notificationmessage.h"
#include "session.h"

#include <kdebug.h>

#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>

#include <QtCore/QDebug>
#include <QtCore/QTimer>

using namespace Akonadi;

class Monitor::Private
{
  public:
    Private( Monitor *parent )
      : mParent( parent ),
        fetchCollection( false ),
        fetchCollectionStatus( false ),
        fetchAllParts( false )
    {
    }

    Monitor *mParent;
    org::kde::Akonadi::NotificationManager *nm;
    Collection::List collections;
    QSet<QByteArray> resources;
    QSet<int> items;
    QSet<QString> mimetypes;
    bool monitorAll;
    QList<QByteArray> sessions;
    QStringList mFetchParts;
    QHash<KJob*,NotificationMessage> pendingJobs;

    bool isCollectionMonitored( int collection, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) || resources.contains( resource ) )
        return true;
      return false;
    }

    bool isItemMonitored( uint item, int collection, int collectionDest,
                          const QString &mimetype, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) ||
           isCollectionMonitored( collectionDest ) ||items.contains( item ) ||
           resources.contains( resource ) || mimetypes.contains( mimetype ) )
        return true;
      return false;
    }

    bool isSessionIgnored( const QByteArray &sessionId ) const
    {
      return sessions.contains( sessionId );
    }

    bool connectToNotificationManager();

    // private slots
    void sessionDestroyed( QObject* );
    void slotStatusChangedFinished( KJob* );
    void slotFlushRecentlyChangedCollections();

    void slotNotify( const NotificationMessage::List &msgs );
    void slotItemJobFinished( KJob* job );
    void slotCollectionJobFinished( KJob *job );

    void emitItemNotification( const NotificationMessage &msg, const Item &item = Item(),
                               const Collection &collection = Collection(), const Collection &collectionDest = Collection() );
    void emitCollectionNotification( const NotificationMessage &msg, const Collection &col = Collection(),
                                     const Collection &par = Collection() );

    bool fetchCollection;
    bool fetchCollectionStatus;
    bool fetchAllParts;

  private:
    // collections that need a status update
    QSet<int> recentlyChangedCollections;

    bool isCollectionMonitored( int collection ) const
    {
      if ( collections.contains( Collection( collection ) ) )
        return true;
      if ( collections.contains( Collection::root() ) )
        return true;
      return false;
    }

    void fetchStatus( int colId )
    {
      CollectionStatusJob *job = new CollectionStatusJob( Collection( colId ), mParent );
      connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotStatusChangedFinished(KJob*)) );
    }

    void notifyCollectionStatusWatchers( int collection, const QByteArray &resource )
    {
      if ( isCollectionMonitored( collection, resource ) ) {
        if (recentlyChangedCollections.empty() )
          QTimer::singleShot( 500, mParent, SLOT(slotFlushRecentlyChangedCollections()) );
        recentlyChangedCollections.insert( collection );
      }
    }
};

bool Monitor::Private::connectToNotificationManager()
{
  NotificationMessage::registerDBusTypes();

  if ( !nm )
    nm = new org::kde::Akonadi::NotificationManager( QLatin1String( "org.kde.Akonadi" ),
                                                     QLatin1String( "/notifications" ),
                                                     QDBusConnection::sessionBus(), mParent );
  else
    return true;

  if ( !nm ) {
    qWarning() << "Unable to connect to notification manager";
  } else {
    connect( nm, SIGNAL(notify(Akonadi::NotificationMessage::List)),
             mParent, SLOT(slotNotify(Akonadi::NotificationMessage::List)) );
    return true;
  }
  return false;
}

void Monitor::Private::sessionDestroyed( QObject * object )
{
  Session* session = qobject_cast<Session*>( object );
  if ( session )
    sessions.removeAll( session->sessionId() );
}

void Monitor::Private::slotStatusChangedFinished( KJob* job )
{
  if ( job->error() ) {
    qWarning() << "Error on fetching collection status: " << job->errorText();
  } else {
    CollectionStatusJob *statusJob = static_cast<CollectionStatusJob*>( job );
    emit mParent->collectionStatusChanged( statusJob->collection().id(), statusJob->status() );
  }
}

void Monitor::Private::slotFlushRecentlyChangedCollections()
{
  foreach( int collection, recentlyChangedCollections ) {
    if ( fetchCollectionStatus ) {
      fetchStatus( collection );
    } else {
      static const CollectionStatus dummyStatus;
      emit mParent->collectionStatusChanged( collection, dummyStatus );
    }
  }
  recentlyChangedCollections.clear();
}

void Monitor::Private::slotNotify( const NotificationMessage::List &msgs )
{
  foreach ( const NotificationMessage msg, msgs ) {
    if ( isSessionIgnored( msg.sessionId() ) )
      continue;

    if ( msg.type() == NotificationMessage::Item ) {
      notifyCollectionStatusWatchers( msg.parentCollection(), msg.resource() );
      if ( !isItemMonitored( msg.uid(), msg.parentCollection(), msg.parentDestCollection(), msg.mimeType(), msg.resource() ) )
        continue;
      if ( !mFetchParts.isEmpty() &&
           ( msg.operation() == NotificationMessage::Add || msg.operation() == NotificationMessage::Move )) {
        ItemCollectionFetchJob *job = new ItemCollectionFetchJob( DataReference( msg.uid(), msg.remoteId() ),
                                                                  msg.parentCollection(), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      if ( !mFetchParts.isEmpty() && msg.operation() == NotificationMessage::Modify ) {
        ItemFetchJob *job = new ItemFetchJob( DataReference( msg.uid(), msg.remoteId() ), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      emitItemNotification( msg );
    } else if ( msg.type() == NotificationMessage::Collection ) {
      if ( msg.operation() != NotificationMessage::Remove && fetchCollection ) {
        Collection::List list;
        list << Collection( msg.uid() );
        if ( msg.operation() == NotificationMessage::Add )
          list << Collection( msg.parentCollection() );
        CollectionListJob *job = new CollectionListJob( list, mParent );
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotCollectionJobFinished(KJob*)) );
        continue;
      }
      if ( msg.operation() == NotificationMessage::Remove ) {
        // no need for status updates anymore
        recentlyChangedCollections.remove( msg.uid() );
      }
      emitCollectionNotification( msg );
    } else {
      qWarning() << "Received unknown change notification!";
    }
  }
}

void Monitor::Private::emitItemNotification( const NotificationMessage &msg, const Item &item,
                                             const Collection &collection, const Collection &collectionDest  )
{
  Q_ASSERT( msg.type() == NotificationMessage::Item );
  Collection col = collection;
  Collection colDest = collectionDest;
  if ( !col.isValid() ) {
    col = Collection( msg.parentCollection() );
    col.setResource( QString::fromUtf8( msg.resource() ) );
  }
  if ( !colDest.isValid() ) {
    colDest = Collection( msg.parentDestCollection() );
    // FIXME setResource here required ?
  }
  Item it = item;
  if ( !it.isValid() ) {
    it = Item( DataReference( msg.uid(), msg.remoteId() ) );
    it.setMimeType( msg.mimeType() );
  }
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->itemAdded( it, col );
      break;
    case NotificationMessage::Modify:
      emit mParent->itemChanged( it, msg.itemParts() );
      break;
    case NotificationMessage::Move:
      emit mParent->itemMoved( it, col, colDest );
      break;
    case NotificationMessage::Remove:
      emit mParent->itemRemoved( it.reference() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitItemNotification()", "Invalid enum value" );
  }
}

void Monitor::Private::emitCollectionNotification( const NotificationMessage &msg, const Collection &col,
                                                   const Collection &par )
{
  Q_ASSERT( msg.type() == NotificationMessage::Collection );
  Collection collection = col;
  if ( !collection.isValid() ) {
    collection = Collection( msg.uid() );
    collection.setParent( msg.parentCollection() );
    collection.setResource( QString::fromUtf8( msg.resource() ) );
    collection.setRemoteId( msg.remoteId() );
  }
  Collection parent = par;
  if ( !parent.isValid() )
    parent = Collection( msg.parentCollection() );
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->collectionAdded( collection, parent );
      break;
    case NotificationMessage::Modify:
      emit mParent->collectionChanged( collection );
      break;
    case NotificationMessage::Remove:
      emit mParent->collectionRemoved( collection.id(), collection.remoteId() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitCollectionNotification", "Invalid enum value" );
  }
}

void Monitor::Private::slotItemJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching item:" << job->errorText();
  } else {
    Item item;
    Collection col;
    ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
    if ( fetchJob && fetchJob->items().count() > 0 )
      item = fetchJob->items().first();
    ItemCollectionFetchJob *cfjob = qobject_cast<ItemCollectionFetchJob*>( job );
    if ( cfjob ) {
      item = cfjob->item();
      col = cfjob->collection();
    }
    emitItemNotification( msg, item, col );
  }
}

void Monitor::Private::slotCollectionJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching collection:" << job->errorText();
  } else {
    Collection col, parent;
    CollectionListJob *listJob = qobject_cast<CollectionListJob*>( job );
    if ( listJob && listJob->collections().count() > 0 )
      col = listJob->collections().first();
    if ( listJob && listJob->collections().count() > 1 && msg.operation() == NotificationMessage::Add ) {
      parent = listJob->collections().at( 1 );
      if ( col.id() != msg.uid() )
        qSwap( col, parent );
    }
    emitCollectionNotification( msg, col, parent );
  }
}

Monitor::Monitor( QObject *parent ) :
    QObject( parent ),
    d( new Private( this ) )
{
  d->nm = 0;
  d->monitorAll = false;
  d->connectToNotificationManager();
}

Monitor::~Monitor()
{
  delete d;
}

void Monitor::monitorCollection( const Collection &collection )
{
  d->collections << collection;
}

void Monitor::monitorItem( const DataReference & ref )
{
  d->items.insert( ref.id() );
}

void Monitor::monitorResource(const QByteArray & resource)
{
  d->resources.insert( resource );
}

void Monitor::monitorMimeType(const QString & mimetype)
{
  d->mimetypes.insert( mimetype );
}

void Akonadi::Monitor::monitorAll()
{
  d->monitorAll = true;
}

void Monitor::ignoreSession(Session * session)
{
  d->sessions << session->sessionId();
}

void Monitor::fetchCollection(bool enable)
{
  d->fetchCollection = enable;
}

void Monitor::addFetchPart( const QString &identifier )
{
  if ( !d->mFetchParts.contains( identifier ) )
    d->mFetchParts.append( identifier );
}

void Monitor::fetchCollectionStatus(bool enable)
{
  d->fetchCollectionStatus = enable;
}

void Monitor::fetchAllParts()
{
  d->fetchAllParts = true;
}

#include "monitor.moc"
<commit_msg>If you just have fetchAllParts enabled, mFetchParts is empty... So without this patch, the monitor returns Items without payload, which leads to crashes in resources. Volker, is that ok?<commit_after>/*
    Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "monitor.h"
#include "monitor_p.h"

#include "collectionlistjob.h"
#include "collectionstatusjob.h"
#include "itemfetchjob.h"
#include "notificationmanagerinterface.h"
#include "notificationmessage.h"
#include "session.h"

#include <kdebug.h>

#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>

#include <QtCore/QDebug>
#include <QtCore/QTimer>

using namespace Akonadi;

class Monitor::Private
{
  public:
    Private( Monitor *parent )
      : mParent( parent ),
        fetchCollection( false ),
        fetchCollectionStatus( false ),
        fetchAllParts( false )
    {
    }

    Monitor *mParent;
    org::kde::Akonadi::NotificationManager *nm;
    Collection::List collections;
    QSet<QByteArray> resources;
    QSet<int> items;
    QSet<QString> mimetypes;
    bool monitorAll;
    QList<QByteArray> sessions;
    QStringList mFetchParts;
    QHash<KJob*,NotificationMessage> pendingJobs;

    bool isCollectionMonitored( int collection, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) || resources.contains( resource ) )
        return true;
      return false;
    }

    bool isItemMonitored( uint item, int collection, int collectionDest,
                          const QString &mimetype, const QByteArray &resource ) const
    {
      if ( monitorAll || isCollectionMonitored( collection ) ||
           isCollectionMonitored( collectionDest ) ||items.contains( item ) ||
           resources.contains( resource ) || mimetypes.contains( mimetype ) )
        return true;
      return false;
    }

    bool isSessionIgnored( const QByteArray &sessionId ) const
    {
      return sessions.contains( sessionId );
    }

    bool connectToNotificationManager();

    // private slots
    void sessionDestroyed( QObject* );
    void slotStatusChangedFinished( KJob* );
    void slotFlushRecentlyChangedCollections();

    void slotNotify( const NotificationMessage::List &msgs );
    void slotItemJobFinished( KJob* job );
    void slotCollectionJobFinished( KJob *job );

    void emitItemNotification( const NotificationMessage &msg, const Item &item = Item(),
                               const Collection &collection = Collection(), const Collection &collectionDest = Collection() );
    void emitCollectionNotification( const NotificationMessage &msg, const Collection &col = Collection(),
                                     const Collection &par = Collection() );

    bool fetchCollection;
    bool fetchCollectionStatus;
    bool fetchAllParts;

  private:
    // collections that need a status update
    QSet<int> recentlyChangedCollections;

    bool isCollectionMonitored( int collection ) const
    {
      if ( collections.contains( Collection( collection ) ) )
        return true;
      if ( collections.contains( Collection::root() ) )
        return true;
      return false;
    }

    void fetchStatus( int colId )
    {
      CollectionStatusJob *job = new CollectionStatusJob( Collection( colId ), mParent );
      connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotStatusChangedFinished(KJob*)) );
    }

    void notifyCollectionStatusWatchers( int collection, const QByteArray &resource )
    {
      if ( isCollectionMonitored( collection, resource ) ) {
        if (recentlyChangedCollections.empty() )
          QTimer::singleShot( 500, mParent, SLOT(slotFlushRecentlyChangedCollections()) );
        recentlyChangedCollections.insert( collection );
      }
    }
};

bool Monitor::Private::connectToNotificationManager()
{
  NotificationMessage::registerDBusTypes();

  if ( !nm )
    nm = new org::kde::Akonadi::NotificationManager( QLatin1String( "org.kde.Akonadi" ),
                                                     QLatin1String( "/notifications" ),
                                                     QDBusConnection::sessionBus(), mParent );
  else
    return true;

  if ( !nm ) {
    qWarning() << "Unable to connect to notification manager";
  } else {
    connect( nm, SIGNAL(notify(Akonadi::NotificationMessage::List)),
             mParent, SLOT(slotNotify(Akonadi::NotificationMessage::List)) );
    return true;
  }
  return false;
}

void Monitor::Private::sessionDestroyed( QObject * object )
{
  Session* session = qobject_cast<Session*>( object );
  if ( session )
    sessions.removeAll( session->sessionId() );
}

void Monitor::Private::slotStatusChangedFinished( KJob* job )
{
  if ( job->error() ) {
    qWarning() << "Error on fetching collection status: " << job->errorText();
  } else {
    CollectionStatusJob *statusJob = static_cast<CollectionStatusJob*>( job );
    emit mParent->collectionStatusChanged( statusJob->collection().id(), statusJob->status() );
  }
}

void Monitor::Private::slotFlushRecentlyChangedCollections()
{
  foreach( int collection, recentlyChangedCollections ) {
    if ( fetchCollectionStatus ) {
      fetchStatus( collection );
    } else {
      static const CollectionStatus dummyStatus;
      emit mParent->collectionStatusChanged( collection, dummyStatus );
    }
  }
  recentlyChangedCollections.clear();
}

void Monitor::Private::slotNotify( const NotificationMessage::List &msgs )
{
  foreach ( const NotificationMessage msg, msgs ) {
    if ( isSessionIgnored( msg.sessionId() ) )
      continue;

    if ( msg.type() == NotificationMessage::Item ) {
      notifyCollectionStatusWatchers( msg.parentCollection(), msg.resource() );
      if ( !isItemMonitored( msg.uid(), msg.parentCollection(), msg.parentDestCollection(), msg.mimeType(), msg.resource() ) )
        continue;
      if ( !mFetchParts.isEmpty() &&
           ( msg.operation() == NotificationMessage::Add || msg.operation() == NotificationMessage::Move ) || fetchAllParts ) {
        ItemCollectionFetchJob *job = new ItemCollectionFetchJob( DataReference( msg.uid(), msg.remoteId() ),
                                                                  msg.parentCollection(), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      if ( !mFetchParts.isEmpty() && msg.operation() == NotificationMessage::Modify ) {
        ItemFetchJob *job = new ItemFetchJob( DataReference( msg.uid(), msg.remoteId() ), mParent );
        foreach( QString part, mFetchParts )
          job->addFetchPart( part );
        if ( fetchAllParts )
          job->fetchAllParts();
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotItemJobFinished(KJob*)) );
        continue;
      }
      emitItemNotification( msg );
    } else if ( msg.type() == NotificationMessage::Collection ) {
      if ( msg.operation() != NotificationMessage::Remove && fetchCollection ) {
        Collection::List list;
        list << Collection( msg.uid() );
        if ( msg.operation() == NotificationMessage::Add )
          list << Collection( msg.parentCollection() );
        CollectionListJob *job = new CollectionListJob( list, mParent );
        pendingJobs.insert( job, msg );
        connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotCollectionJobFinished(KJob*)) );
        continue;
      }
      if ( msg.operation() == NotificationMessage::Remove ) {
        // no need for status updates anymore
        recentlyChangedCollections.remove( msg.uid() );
      }
      emitCollectionNotification( msg );
    } else {
      qWarning() << "Received unknown change notification!";
    }
  }
}

void Monitor::Private::emitItemNotification( const NotificationMessage &msg, const Item &item,
                                             const Collection &collection, const Collection &collectionDest  )
{
  Q_ASSERT( msg.type() == NotificationMessage::Item );
  Collection col = collection;
  Collection colDest = collectionDest;
  if ( !col.isValid() ) {
    col = Collection( msg.parentCollection() );
    col.setResource( QString::fromUtf8( msg.resource() ) );
  }
  if ( !colDest.isValid() ) {
    colDest = Collection( msg.parentDestCollection() );
    // FIXME setResource here required ?
  }
  Item it = item;
  if ( !it.isValid() ) {
    it = Item( DataReference( msg.uid(), msg.remoteId() ) );
    it.setMimeType( msg.mimeType() );
  }
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->itemAdded( it, col );
      break;
    case NotificationMessage::Modify:
      emit mParent->itemChanged( it, msg.itemParts() );
      break;
    case NotificationMessage::Move:
      emit mParent->itemMoved( it, col, colDest );
      break;
    case NotificationMessage::Remove:
      emit mParent->itemRemoved( it.reference() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitItemNotification()", "Invalid enum value" );
  }
}

void Monitor::Private::emitCollectionNotification( const NotificationMessage &msg, const Collection &col,
                                                   const Collection &par )
{
  Q_ASSERT( msg.type() == NotificationMessage::Collection );
  Collection collection = col;
  if ( !collection.isValid() ) {
    collection = Collection( msg.uid() );
    collection.setParent( msg.parentCollection() );
    collection.setResource( QString::fromUtf8( msg.resource() ) );
    collection.setRemoteId( msg.remoteId() );
  }
  Collection parent = par;
  if ( !parent.isValid() )
    parent = Collection( msg.parentCollection() );
  switch ( msg.operation() ) {
    case NotificationMessage::Add:
      emit mParent->collectionAdded( collection, parent );
      break;
    case NotificationMessage::Modify:
      emit mParent->collectionChanged( collection );
      break;
    case NotificationMessage::Remove:
      emit mParent->collectionRemoved( collection.id(), collection.remoteId() );
      break;
    default:
      Q_ASSERT_X( false, "Monitor::Private::emitCollectionNotification", "Invalid enum value" );
  }
}

void Monitor::Private::slotItemJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching item:" << job->errorText();
  } else {
    Item item;
    Collection col;
    ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
    if ( fetchJob && fetchJob->items().count() > 0 )
      item = fetchJob->items().first();
    ItemCollectionFetchJob *cfjob = qobject_cast<ItemCollectionFetchJob*>( job );
    if ( cfjob ) {
      item = cfjob->item();
      col = cfjob->collection();
    }
    emitItemNotification( msg, item, col );
  }
}

void Monitor::Private::slotCollectionJobFinished( KJob* job )
{
  if ( !pendingJobs.contains( job ) ) {
    kWarning() <<"unknown job - wtf is going on here?";
    return;
  }
  NotificationMessage msg = pendingJobs.take( job );
  if ( job->error() ) {
    kWarning() <<"Error on fetching collection:" << job->errorText();
  } else {
    Collection col, parent;
    CollectionListJob *listJob = qobject_cast<CollectionListJob*>( job );
    if ( listJob && listJob->collections().count() > 0 )
      col = listJob->collections().first();
    if ( listJob && listJob->collections().count() > 1 && msg.operation() == NotificationMessage::Add ) {
      parent = listJob->collections().at( 1 );
      if ( col.id() != msg.uid() )
        qSwap( col, parent );
    }
    emitCollectionNotification( msg, col, parent );
  }
}

Monitor::Monitor( QObject *parent ) :
    QObject( parent ),
    d( new Private( this ) )
{
  d->nm = 0;
  d->monitorAll = false;
  d->connectToNotificationManager();
}

Monitor::~Monitor()
{
  delete d;
}

void Monitor::monitorCollection( const Collection &collection )
{
  d->collections << collection;
}

void Monitor::monitorItem( const DataReference & ref )
{
  d->items.insert( ref.id() );
}

void Monitor::monitorResource(const QByteArray & resource)
{
  d->resources.insert( resource );
}

void Monitor::monitorMimeType(const QString & mimetype)
{
  d->mimetypes.insert( mimetype );
}

void Akonadi::Monitor::monitorAll()
{
  d->monitorAll = true;
}

void Monitor::ignoreSession(Session * session)
{
  d->sessions << session->sessionId();
}

void Monitor::fetchCollection(bool enable)
{
  d->fetchCollection = enable;
}

void Monitor::addFetchPart( const QString &identifier )
{
  if ( !d->mFetchParts.contains( identifier ) )
    d->mFetchParts.append( identifier );
}

void Monitor::fetchCollectionStatus(bool enable)
{
  d->fetchCollectionStatus = enable;
}

void Monitor::fetchAllParts()
{
  d->fetchAllParts = true;
}

#include "monitor.moc"
<|endoftext|>


<commit_before>#ifndef VENTURA_REACTIVE_LINUX_INOTIFY_HPP
#define VENTURA_REACTIVE_LINUX_INOTIFY_HPP

#include <silicium/observable/observer.hpp>
#include <silicium/error_or.hpp>
#include <silicium/exchange.hpp>
#include <silicium/throw_last_error.hpp>
#include <ventura/linux/inotify_watch_descriptor.hpp>
#include <ventura/absolute_path.hpp>
#include <ventura/path_segment.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/swap.hpp>
#include <boost/optional.hpp>
#include <boost/ref.hpp>
#include <dirent.h>

#define VENTURA_HAS_INOTIFY_OBSERVABLE SILICIUM_HAS_EXCEPTIONS

namespace ventura
{
	namespace linux
	{
#if VENTURA_HAS_INOTIFY_OBSERVABLE
		struct file_notification
		{
			boost::uint32_t mask;
			path_segment name;
			int watch_descriptor;

			file_notification() BOOST_NOEXCEPT : mask(0), watch_descriptor(-1)
			{
			}

			explicit file_notification(boost::uint32_t mask, path_segment name, int watch_descriptor) BOOST_NOEXCEPT
			    : mask(mask),
			      name(std::move(name)),
			      watch_descriptor(watch_descriptor)
			{
			}
		};

		struct inotify_observable
		{
			typedef std::vector<file_notification> element_type;

			inotify_observable() BOOST_NOEXCEPT
			{
			}

			explicit inotify_observable(boost::asio::io_service &io)
			    : notifier(Si::make_unique<boost::asio::posix::stream_descriptor>(boost::ref(io)))
			{
				int fd = inotify_init();
				if (fd < 0)
				{
					Si::throw_last_error();
				}
				try
				{
					notifier->assign(fd);
				}
				catch (...)
				{
					close(fd);
					throw;
				}
			}

			Si::error_or<watch_descriptor> watch(absolute_path const &target, boost::uint32_t mask) BOOST_NOEXCEPT
			{
				assert(notifier);
				int const wd = inotify_add_watch(notifier->native_handle(), target.c_str(), mask);
				if (wd < 0)
				{
					return Si::get_last_error();
				}
				return watch_descriptor(notifier->native_handle(), wd);
			}

			template <class Observer>
			void async_get_one(Observer &&receiver)
			{
				std::size_t const min_buffer_size = sizeof(inotify_event) + NAME_MAX + 1;
				std::size_t const additional_buffer = 8192;
				read_buffer.resize(min_buffer_size + additional_buffer);
				assert(notifier);
				notifier->async_read_some(
				    boost::asio::buffer(read_buffer),
				    [ this, SILICIUM_CAPTURE_EXPRESSION(receiver, std::forward<Observer>(receiver)) ](
				        boost::system::error_code error, std::size_t bytes_read) mutable
				    {
					    if (error)
					    {
						    if (error == boost::asio::error::operation_aborted)
						    {
							    return;
						    }
						    throw std::logic_error("not implemented");
					    }
					    else
					    {
						    std::vector<file_notification> changes;
						    for (std::size_t i = 0; i < bytes_read;)
						    {
							    inotify_event const &event =
							        *reinterpret_cast<inotify_event const *>(read_buffer.data() + i);
							    Si::optional<path_segment> segment = path_segment::create(boost::filesystem::path(
							        event.name + 0, std::find(event.name + 0, event.name + event.len, '\0')));
							    assert(segment);
							    changes.emplace_back(file_notification{event.mask, std::move(*segment), event.wd});
							    i += sizeof(inotify_event);
							    i += event.len;
						    }
						    std::forward<Observer>(receiver).got_element(std::move(changes));
					    }
					});
			}

		private:
			std::unique_ptr<boost::asio::posix::stream_descriptor> notifier;
			std::vector<char> read_buffer;
		};
#endif
	}
}

#endif
<commit_msg>fix for Linux<commit_after>#ifndef VENTURA_REACTIVE_LINUX_INOTIFY_HPP
#define VENTURA_REACTIVE_LINUX_INOTIFY_HPP

#include <silicium/observable/observer.hpp>
#include <silicium/error_or.hpp>
#include <silicium/exchange.hpp>
#include <silicium/throw_last_error.hpp>
#include <ventura/linux/inotify_watch_descriptor.hpp>
#include <ventura/absolute_path.hpp>
#include <ventura/path_segment.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/swap.hpp>
#include <boost/optional.hpp>
#include <boost/ref.hpp>
#include <dirent.h>

#define VENTURA_HAS_INOTIFY_OBSERVABLE SILICIUM_HAS_EXCEPTIONS

namespace ventura
{
	namespace linux
	{
#if VENTURA_HAS_INOTIFY_OBSERVABLE
		struct file_notification
		{
			boost::uint32_t mask;
			path_segment name;
			int watch_descriptor;

			file_notification() BOOST_NOEXCEPT : mask(0), watch_descriptor(-1)
			{
			}

			explicit file_notification(boost::uint32_t mask, path_segment name, int watch_descriptor) BOOST_NOEXCEPT
			    : mask(mask),
			      name(std::move(name)),
			      watch_descriptor(watch_descriptor)
			{
			}
		};

		struct inotify_observable
		{
			typedef std::vector<file_notification> element_type;

			inotify_observable() BOOST_NOEXCEPT
			{
			}

			explicit inotify_observable(boost::asio::io_service &io)
			    : notifier(Si::make_unique<boost::asio::posix::stream_descriptor>(boost::ref(io)))
			{
				int fd = inotify_init();
				if (fd < 0)
				{
					Si::throw_last_error();
				}
				try
				{
					notifier->assign(fd);
				}
				catch (...)
				{
					close(fd);
					throw;
				}
			}

			Si::error_or<watch_descriptor> watch(absolute_path const &target, boost::uint32_t mask) BOOST_NOEXCEPT
			{
				assert(notifier);
				int const wd = inotify_add_watch(notifier->native_handle(), target.c_str(), mask);
				if (wd < 0)
				{
					return Si::get_last_error();
				}
				return watch_descriptor(notifier->native_handle(), wd);
			}

			template <class Observer>
			void async_get_one(Observer &&receiver)
			{
				std::size_t const min_buffer_size = sizeof(inotify_event) + NAME_MAX + 1;
				std::size_t const additional_buffer = 8192;
				read_buffer.resize(min_buffer_size + additional_buffer);
				assert(notifier);
				notifier->async_read_some(
				    boost::asio::buffer(read_buffer),
				    [ this, SILICIUM_CAPTURE_EXPRESSION(receiver, std::forward<Observer>(receiver)) ](
				        boost::system::error_code error, std::size_t bytes_read) mutable
				    {
					    if (error)
					    {
						    if (error == boost::asio::error::operation_aborted)
						    {
							    return;
						    }
						    throw std::logic_error("not implemented");
					    }
					    else
					    {
						    std::vector<file_notification> changes;
						    for (std::size_t i = 0; i < bytes_read;)
						    {
							    inotify_event const &event =
							        *reinterpret_cast<inotify_event const *>(read_buffer.data() + i);
							    Si::optional<path_segment> segment = path_segment::create(path(
							        event.name + 0, std::find(event.name + 0, event.name + event.len, '\0')));
							    assert(segment);
							    changes.emplace_back(file_notification{event.mask, std::move(*segment), event.wd});
							    i += sizeof(inotify_event);
							    i += event.len;
						    }
						    std::forward<Observer>(receiver).got_element(std::move(changes));
					    }
					});
			}

		private:
			std::unique_ptr<boost::asio::posix::stream_descriptor> notifier;
			std::vector<char> read_buffer;
		};
#endif
	}
}

#endif
<|endoftext|>


<commit_before>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the \"License\");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an \"AS IS\" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#pragma once

#include <string>

const std::string complex_xml =
"<mesh id=\"1\" type=\"cyl\" pitch=\"1.26\">"
"    <radii>0.54 0.62</radii>"
"    <sub_radii>5 2</sub_radii>"
"    <sub_azi>8</sub_azi>"
"</mesh>"
"<mesh id=\"2\" type=\"rect\" pitch=\"1.26\">"
"    <sub_x>3</sub_x>"
"    <sub_y>3</sub_y>"
"</mesh>"
""
"<material_lib path=\"../c5g7.xsl\">"
"    <material id=\"1\" name=\"UO2-3.3\" />"
"    <material id=\"2\" name=\"MOX-4.3\" />"
"    <material id=\"6\" name=\"Moderator\" />"
"    <material id=\"7\" name=\"GuideTube\" />"
"    <material id=\"8\" name=\"CRod\" />"
"</material_lib>"
""
"<!-- UO2 pin -->"
"<pin id=\"1\" mesh=\"1\">"
"    1 6 6"
"</pin>"
"<!-- MOx-4.3 pin -->"
"<pin id=\"2\" mesh=\"1\">"
"    2 6 6"
"</pin>"
"<!-- MOx-7.0 pin -->"
"<pin id=\"3\" mesh=\"1\">"
"    3 6 6"
"</pin>"
"<!-- MOx-8.7 pin -->"
"<pin id=\"4\" mesh=\"1\">"
"    4 6 6"
"</pin>"
"<!-- Fission Chamber -->"
"<pin id=\"5\" mesh=\"1\">"
"    5 6 6"
"</pin>"
"<!-- Moderator  -->"
"<pin id=\"6\" mesh=\"2\">"
"    6 6 6"
"    6 6 6"
"    6 6 6"
"</pin>"
""
"<!-- Guide Tube -->"
"<pin id=\"7\" mesh=\"1\">"
"    7 6 6"
"</pin>"
""
"<!-- Control Rod -->"
"<pin id=\"8\" mesh=\"1\">"
"    8 6 6"
"</pin>"
""
""
"<!-- Unrodded UO2 -->"
"<lattice id=\"1\" nx=\"3\" ny=\"3\">"
"    1 1 1"
"    1 7 1"
"    1 1 1"
"</lattice>"
"<!-- Rodded UO2 -->"
"<lattice id=\"11\" nx=\"3\" ny=\"3\">"
"    1 8 1"
"    1 8 1"
"    1 1 1"
"</lattice>"
"<!-- Unrodded MOx -->"
"<lattice id=\"2\" nx=\"3\" ny=\"3\">"
"    2 2 2"
"    2 7 2"
"    2 2 2"
"</lattice>"
"<!-- Rodded MOx -->"
"<lattice id=\"22\" nx=\"3\" ny=\"3\">"
"    2 2 2"
"    2 8 2"
"    2 2 2"
"</lattice>"
""
"<!-- Reflector, rodded -->"
"<lattice id=\"33\" nx=\"3\" ny=\"3\">"
"    6 6 6"
"    6 8 6"
"    6 6 6"
"</lattice>"
""
"<assembly id=\"1\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        {11 11 11 11 11}"
"        {11 11 11 11 11}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"    </lattices>"
"</assembly>"
"<assembly id=\"2\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"    </lattices>"
"</assembly>"
"<assembly id=\"3\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"    </lattices>"
"</assembly>"
""
"<core nx=\"2\" ny=\"2\""
"    north=\"reflect\""
"    south=\"reflect\""
"    east=\"reflect\""
"    west=\"reflect\""
"    top=\"vacuum\""
"    bottom=\"reflect\">"
"    1 2"
"    2 3"
"</core>";
<commit_msg>Split up portions of inputs.hpp<commit_after>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the \"License\");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an \"AS IS\" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#pragma once

#include <string>

/*
This is a sufficiently complicated example that it should exercise most of the
features and variability of the CoreMesh class and its various clients. There
are square and non-square lattices, macroplanes of various sizes, non-uniform
plane heights.
 */
const std::string pinmesh_xml =
"<mesh id=\"1\" type=\"cyl\" pitch=\"1.26\">"
"    <radii>0.54 0.62</radii>"
"    <sub_radii>5 2</sub_radii>"
"    <sub_azi>8</sub_azi>"
"</mesh>"
"<mesh id=\"2\" type=\"rect\" pitch=\"1.26\">"
"    <sub_x>3</sub_x>"
"    <sub_y>3</sub_y>"
"</mesh>";

const std::string material_xml =
"<material_lib path=\"c5g7.xsl\">"
"    <material id=\"1\" name=\"UO2-3.3\" />"
"    <material id=\"2\" name=\"MOX-4.3\" />"
"    <material id=\"6\" name=\"Moderator\" />"
"    <material id=\"7\" name=\"GuideTube\" />"
"    <material id=\"8\" name=\"CRod\" />"
"</material_lib>";

const std::string pin_xml =
"<!-- UO2 pin -->"
"<pin id=\"1\" mesh=\"1\">"
"    1 6 6"
"</pin>"
"<!-- MOx-4.3 pin -->"
"<pin id=\"2\" mesh=\"1\">"
"    2 6 6"
"</pin>"
"<!-- Moderator  -->"
"<pin id=\"6\" mesh=\"2\">"
"    6 6 6"
"    6 6 6"
"    6 6 6"
"</pin>"
""
"<!-- Guide Tube -->"
"<pin id=\"7\" mesh=\"1\">"
"    7 6 6"
"</pin>"
""
"<!-- Control Rod -->"
"<pin id=\"8\" mesh=\"1\">"
"    8 6 6"
"</pin>";

const std::string lattice_xml =
"<!-- Unrodded UO2 -->"
"<lattice id=\"1\" nx=\"3\" ny=\"3\">"
"    1 1 1"
"    1 7 1"
"    1 1 1"
"</lattice>"
"<!-- Rodded UO2 -->"
"<lattice id=\"11\" nx=\"3\" ny=\"3\">"
"    1 8 1"
"    1 8 1"
"    1 1 1"
"</lattice>"
"<!-- Unrodded MOx -->"
"<lattice id=\"2\" nx=\"3\" ny=\"3\">"
"    2 2 2"
"    2 7 2"
"    2 2 2"
"</lattice>"
"<!-- Rodded MOx -->"
"<lattice id=\"22\" nx=\"3\" ny=\"3\">"
"    2 2 2"
"    2 8 2"
"    2 2 2"
"</lattice>"
""
"<!-- Reflector, rodded -->"
"<lattice id=\"33\" nx=\"3\" ny=\"3\">"
"    6 6 6"
"    6 8 6"
"    6 6 6"
"</lattice>"
"<!-- South boundary lattice -->"
"<lattice id=\"101\" nx=\"3\" ny=\"2\">"
"    1 1 1"
"    2 2 2"
"</lattice>"
"<!-- East boundary lattice -->"
"<lattice id=\"102\" nx=\"2\" ny=\"3\">"
"    1 2"
"    1 2"
"    1 2"
"</lattice>"
"<!-- South boundary lattice -->"
"<lattice id=\"103\" nx=\"2\" ny=\"2\">"
"    1 2"
"    2 2"
"</lattice>"
"<!-- South boundary reflector -->"
"<lattice id=\"201\" nx=\"3\" ny=\"2\">"
"    6 6 6"
"    6 6 6"
"</lattice>"
"<!-- East boundary reflector -->"
"<lattice id=\"202\" nx=\"2\" ny=\"3\">"
"    6 6"
"    6 6"
"    6 6"
"</lattice>"
"<!-- South boundary reflector -->"
"<lattice id=\"203\" nx=\"2\" ny=\"2\">"
"    6 6"
"    6 6"
"</lattice>";

const std::string assembly_xml =
"<assembly id=\"1\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"         33 33 33 33 33"
"        11 11 {11 11 11}"
"        {11 11 11 11 11}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"    </lattices>"
"</assembly>"
"<assembly id=\"2\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"         33 33 33 33 33"
"         2  2  {2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"        { 2  2  2  2  2}"
"    </lattices>"
"</assembly>"
"<assembly id=\"3\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {33 33 33 33 33}"
"        {33 33 33 33 33}"
"        33 33 33 33 33"
"         1  1  {1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"        { 1  1  1  1  1}"
"    </lattices>"
"</assembly>"
"<assembly id=\"11\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {201 201 201 201 201}"
"        {201 201 201 201 201}"
"         201 201 201 201 201"
"        101 101 {101 101 101}"
"        {101 101 101 101 101}"
"        {101 101 101 101 101}"
"        {101 101 101 101 101}"
"        {101 101 101 101 101}"
"        {101 101 101 101 101}"
"    </lattices>"
"</assembly>"
"<assembly id=\"12\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {202 202 202 202 202}"
"        {202 202 202 202 202}"
"         202 202 202 202 202"
"         102 102 {102 102 102}"
"        {102 102 102 102 102}"
"        {102 102 102 102 102}"
"        {102 102 102 102 102}"
"        {102 102 102 102 102}"
"        {102 102 102 102 102}"
"    </lattices>"
"</assembly>"
"<assembly id=\"13\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {203 203 203 203 203}"
"        {203 203 203 203 203}"
"         203 203 203 203 203"
"        103 103 {103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"    </lattices>"
"</assembly>"
"<assembly id=\"100\" np=\"45\" hz=\"1.428\">"
"    <lattices>"
"        {203 203 203 203 203}"
"        {203 203 203 203 203}"
"         203 203 203 203 203"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"        {103 103 103 103 103}"
"    </lattices>"
"</assembly>";

const std::string complex_xml =
pinmesh_xml + material_xml + pin_xml + lattice_xml + assembly_xml +
"<core nx=\"3\" ny=\"3\""
"    north=\"reflect\""
"    south=\"reflect\""
"    east=\"reflect\""
"    west=\"reflect\""
"    top=\"vacuum\""
"    bottom=\"reflect\">"
"     1  2 12"
"     2  3 12"
"    11 11 13"
"</core>";
<|endoftext|>