<commit_before>#include <FAST/Data/ImagePyramid.hpp>
#include <FAST/Data/Image.hpp>
#include "PatchGenerator.hpp"

namespace fast {

PatchGenerator::PatchGenerator() {
    createInputPort<SpatialDataObject>(0); // Either ImagePyramid or Image/Volume
    createInputPort<Image>(1, false); // Optional mask
    createOutputPort<Image>(0);

    m_width = -1;
    m_height = -1;
    m_depth = -1;
    m_stop = false;
    m_streamIsStarted = false;
    m_firstFrameIsInserted = false;
    m_level = 0;
    mIsModified = true;

    createIntegerAttribute("patch-size", "Patch size", "", 0);
    createIntegerAttribute("patch-level", "Patch level", "Patch level used for image pyramid inputs", m_level);
    createFloatAttribute("patch-overlap", "Patch overlap", "Patch overlap in percent", m_overlapPercent);
    createFloatAttribute("mask-threshold", "Mask threshold", "Threshold, in percent, for how much of the candidate patch must be inside the mask to be accepted", m_maskThreshold);
}

PatchGenerator::PatchGenerator(int width, int height, int depth, int level, float percent, float maskThreshold) : PatchGenerator() {
    setPatchSize(width, height, depth);
    setPatchLevel(level);
    setOverlap(percent);
    setMaskThreshold(maskThreshold);
}

void PatchGenerator::loadAttributes() {
    auto patchSize = getIntegerListAttribute("patch-size");
    if(patchSize.size() == 2) {
        setPatchSize(patchSize[0], patchSize[1]);
    } else if(patchSize.size() == 3) {
        setPatchSize(patchSize[0], patchSize[1], patchSize[2]);
    } else {
        throw Exception("Incorrect number of size parameters in patch-size. Expected 2 or 3");
    }

    setPatchLevel(getIntegerAttribute("patch-level"));
    setOverlap(getFloatAttribute("patch-overlap"));
    setMaskThreshold(getFloatAttribute("mask-threshold"));
}

PatchGenerator::~PatchGenerator() {
    stop();
}

void PatchGenerator::generateStream() {
    Image::pointer previousPatch;

    // TODO implement support for different overlap in different dimensions
    int overlapInPixelsX = (int) std::round(m_overlapPercent * (float) m_width);
    int overlapInPixelsY = (int) std::round(m_overlapPercent * (float) m_height);
    int overlapInPixelsZ = (int) std::round(m_overlapPercent * (float) m_depth);
    int patchWidthWithoutOverlap = m_width - overlapInPixelsX * 2;
    int patchHeightWithoutOverlap = m_height - overlapInPixelsY * 2;
    int patchDepthWithoutOverlap = m_depth - overlapInPixelsZ * 2;

    if(m_inputImagePyramid) {
        if(m_width % 2 != 0 || m_height % 2 != 0)
            throw Exception("Patch size must be dividable by 2");
        const int levelWidth = m_inputImagePyramid->getLevelWidth(m_level);
        const int levelHeight = m_inputImagePyramid->getLevelHeight(m_level);
        const int TIFFmultiplumCriteria = 16;
        if(patchWidthWithoutOverlap % TIFFmultiplumCriteria > 0 || patchHeightWithoutOverlap % TIFFmultiplumCriteria > 0) {
            // Resulting patch size must be a multiple of 16
            overlapInPixelsX = overlapInPixelsX + (patchWidthWithoutOverlap % TIFFmultiplumCriteria)/2;
            overlapInPixelsY = overlapInPixelsY + (patchHeightWithoutOverlap % TIFFmultiplumCriteria)/2;
            reportWarning() << "Patch size must be a multiple of " << TIFFmultiplumCriteria << " (TIFF limitation). Adding some overlap (" << overlapInPixelsX << ", " << overlapInPixelsY << ") to fix." << reportEnd();
            patchWidthWithoutOverlap = m_width - overlapInPixelsX * 2;
            patchHeightWithoutOverlap = m_height - overlapInPixelsY * 2;
            if(patchWidthWithoutOverlap % TIFFmultiplumCriteria > 0 || patchHeightWithoutOverlap % TIFFmultiplumCriteria > 0)
                throw Exception("Error in compensation of patch size..");
        }
        const int patchesX = std::ceil((float) levelWidth / (float) patchWidthWithoutOverlap);
        const int patchesY = std::ceil((float) levelHeight / (float) patchHeightWithoutOverlap);

        for(int patchY = 1; patchY < patchesY; ++patchY) {
            for(int patchX = 1; patchX < patchesX; ++patchX) {
                mRuntimeManager->startRegularTimer("create patch");
                int patchWidth = m_width;
                if(patchX*patchWidthWithoutOverlap + patchWidth - overlapInPixelsX >= levelWidth) {
                    patchWidth = levelWidth - patchX * patchWidthWithoutOverlap + overlapInPixelsX - 1;
                }
                int patchHeight = m_height;
                if(patchY*patchHeightWithoutOverlap + patchHeight - overlapInPixelsY >= levelHeight) {
                    patchHeight = levelHeight - patchY * patchHeightWithoutOverlap + overlapInPixelsY - 1;
                }

                if(m_inputMask) {
                    // If a mask exist, check if this patch should be included or not
                    // At least half of the patch should be clasified as foreground
                    auto access = m_inputMask->getImageAccess(ACCESS_READ);
                    auto croppedMask = m_inputMask->crop(
                        Vector2i(
                            round(m_inputMask->getWidth() * ((float)patchX / patchesX)),
                            round(m_inputMask->getHeight() * ((float)patchY / patchesY))
                        ),
                        Vector2i(
                            round(m_inputMask->getWidth() * (1.0f/patchesX)),
                            round(m_inputMask->getHeight() * (1.0f/patchesY))
                        )
                    );
                    float average = croppedMask->calculateAverageIntensity();
                    if(average < m_maskThreshold)  // A specific percentage of the mask has to be foreground to be assessed
                        continue;
                }
                reportInfo() << "Generating patch " << patchX << " " << patchY << reportEnd();
                auto access = m_inputImagePyramid->getAccess(ACCESS_READ);
                // TODO handle edge cases
                if(patchWidth < overlapInPixelsX*2 || patchHeight < overlapInPixelsY*2)
                    continue;
                auto patch = access->getPatchAsImage(m_level, patchX * patchWidthWithoutOverlap - overlapInPixelsX, patchY * patchHeightWithoutOverlap - overlapInPixelsY,
                                                                  patchWidth,
                                                                  patchHeight);

                // Store some frame data useful for patch stitching
                patch->setFrameData("original-width", std::to_string(levelWidth));
                patch->setFrameData("original-height", std::to_string(levelHeight));
                patch->setFrameData("patchid-x", std::to_string(patchX));
                patch->setFrameData("patchid-y", std::to_string(patchY));
                // Target width/height of patches
                patch->setFrameData("patch-width", std::to_string(m_width));
                patch->setFrameData("patch-height", std::to_string(m_height));
                patch->setFrameData("patch-overlap-x", std::to_string(overlapInPixelsX));
                patch->setFrameData("patch-overlap-y", std::to_string(overlapInPixelsY));
                patch->setFrameData("patch-spacing-x", std::to_string(patch->getSpacing().x()));
                patch->setFrameData("patch-spacing-y", std::to_string(patch->getSpacing().y()));
                patch->setFrameData("patch-level", std::to_string(m_level));
                patch->setFrameData("progress", std::to_string((float)(patchX+patchY*patchesX)/(patchesX*patchesY)));

                mRuntimeManager->stopRegularTimer("create patch");
                try {
                    if(previousPatch) {
                        addOutputData(0, previousPatch, false);
                        frameAdded();
                    }
                } catch(ThreadStopped &e) {
                    std::unique_lock<std::mutex> lock(m_stopMutex);
                    m_stop = true;
                    break;
                }
                previousPatch = patch;
                std::unique_lock<std::mutex> lock(m_stopMutex);
                if(m_stop)
                    break;
            }
            std::unique_lock<std::mutex> lock(m_stopMutex);
            if(m_stop) {
                //m_streamIsStarted = false;
                m_firstFrameIsInserted = false;
                break;
            }
        }
    } else if(m_inputVolume) {
        const int width = m_inputVolume->getWidth();
        const int height = m_inputVolume->getHeight();
        const int depth = m_inputVolume->getDepth();
        auto transformData = SceneGraph::getEigenTransformFromData(m_inputVolume).data();
        std::string transformString;
        for(int i = 0; i < 16; ++i)
            transformString += std::to_string(transformData[i]) + " ";

        const int patchesX = std::ceil((float) width / (float) patchWidthWithoutOverlap);
        const int patchesY = std::ceil((float) height / (float) patchHeightWithoutOverlap);
        const int patchesZ = std::ceil((float) depth / (float) patchDepthWithoutOverlap);

        for(int patchZ = 0; patchZ < patchesZ; ++patchZ) {
        for(int patchY = 0; patchY < patchesY; ++patchY) {
        for(int patchX = 0; patchX < patchesX; ++patchX) {
            mRuntimeManager->startRegularTimer("create patch");

            int patchWidth = m_width;
            if(patchX*patchWidthWithoutOverlap + patchWidth - overlapInPixelsX >= width) {
                patchWidth = width - patchX * patchWidthWithoutOverlap + overlapInPixelsX - 1;
            }
            int patchHeight = m_height;
            if(patchY*patchHeightWithoutOverlap + patchHeight - overlapInPixelsY >= height) {
                patchHeight = height - patchY * patchHeightWithoutOverlap + overlapInPixelsY - 1;
            }
            int patchDepth = m_depth;
            if(patchZ*patchDepthWithoutOverlap + patchDepth - overlapInPixelsZ >= depth) {
                patchDepth = depth - patchZ * patchDepthWithoutOverlap + overlapInPixelsZ - 1;
            }

            int x = patchX * patchWidthWithoutOverlap - overlapInPixelsX;
            int y = patchY * patchHeightWithoutOverlap - overlapInPixelsY;
            int z = patchZ * patchDepthWithoutOverlap - overlapInPixelsZ;

            auto patch = m_inputVolume->crop(Vector3i(x, y, z), Vector3i(patchWidth, patchHeight, patchDepth), true);
            patch->setFrameData("original-width", std::to_string(width));
            patch->setFrameData("original-height", std::to_string(height));
            patch->setFrameData("original-depth", std::to_string(depth));
            patch->setFrameData("original-transform", transformString);
            patch->setFrameData("patch-offset-x", std::to_string(x));
            patch->setFrameData("patch-offset-y", std::to_string(y));
            patch->setFrameData("patch-offset-z", std::to_string(z));
            patch->setFrameData("patch-width", std::to_string(m_width));
            patch->setFrameData("patch-height", std::to_string(m_height));
            patch->setFrameData("patch-depth", std::to_string(m_depth));
            patch->setFrameData("patchid-x", std::to_string(patchX));
            patch->setFrameData("patchid-y", std::to_string(patchY));
            patch->setFrameData("patchid-z", std::to_string(patchZ));
            patch->setFrameData("patch-overlap-x", std::to_string(overlapInPixelsX));
            patch->setFrameData("patch-overlap-y", std::to_string(overlapInPixelsY));
            patch->setFrameData("patch-overlap-z", std::to_string(overlapInPixelsZ));
            Vector3f spacing = m_inputVolume->getSpacing();
            patch->setFrameData("patch-spacing-x", std::to_string(spacing.x()));
            patch->setFrameData("patch-spacing-y", std::to_string(spacing.y()));
            patch->setFrameData("patch-spacing-z", std::to_string(spacing.z()));
            patch->setFrameData("progress", std::to_string((float)(patchX+patchY*patchesX+patchZ*patchesX*patchesY)/(patchesX*patchesY*patchesZ)));
            try {
                if(previousPatch) {
                    addOutputData(0, previousPatch, false);
                    frameAdded();
                    //std::this_thread::sleep_for(std::chrono::seconds(2));
                }
            } catch(ThreadStopped &e) {
                std::unique_lock<std::mutex> lock(m_stopMutex);
                m_stop = true;
                break;
            }
            mRuntimeManager->stopRegularTimer("create patch");
            previousPatch = patch;
            std::unique_lock<std::mutex> lock(m_stopMutex);
            if(m_stop)
                break;
        }}}
    } else {
        throw Exception("Unsupported data object given to PatchGenerator");
    }
    // Add final patch, and mark it has last frame
    previousPatch->setLastFrame(getNameOfClass());
    try {
        addOutputData(0, previousPatch, false);
    } catch(ThreadStopped &e) {

    }
    reportInfo() << "Done generating patches" << reportEnd();
}

void PatchGenerator::execute() {
    if(m_width <= 0 || m_height <= 0 || m_depth <= 0)
        throw Exception("Width, height and depth must be set to a positive number");

    auto input = getInputData<SpatialDataObject>();
    m_inputImagePyramid = std::dynamic_pointer_cast<ImagePyramid>(input);
    m_inputVolume = std::dynamic_pointer_cast<Image>(input);

    if(mInputConnections.count(1) > 0) {
        // If a mask was given store it
        m_inputMask = getInputData<Image>(1);
    }

    startStream();
    waitForFirstFrame();
}

void PatchGenerator::setPatchSize(int width, int height, int depth) {
    m_width = width;
    m_height = height;
    m_depth = depth;
    mIsModified = true;
}

void PatchGenerator::setPatchLevel(int level) {
    m_level = level;
    mIsModified = true;
}

void PatchGenerator::setOverlap(float percent) {
    if(percent < 0 || percent > 1)
        throw Exception("Overlap percent must be >= 0 && <= 1");
    m_overlapPercent = percent;
    mIsModified = true;
}

void PatchGenerator::setMaskThreshold(float percent) {
    if(percent < 0 || percent > 1)
        throw Exception("Mask threshold must be >= 0 && <= 1");
    m_maskThreshold = percent;
    mIsModified = true;
}

}<commit_msg>Fixed bug in PatchGenerator causing wrong sizes of patches.<commit_after>#include <FAST/Data/ImagePyramid.hpp>
#include <FAST/Data/Image.hpp>
#include "PatchGenerator.hpp"

namespace fast {

PatchGenerator::PatchGenerator() {
    createInputPort<SpatialDataObject>(0); // Either ImagePyramid or Image/Volume
    createInputPort<Image>(1, false); // Optional mask
    createOutputPort<Image>(0);

    m_width = -1;
    m_height = -1;
    m_depth = -1;
    m_stop = false;
    m_streamIsStarted = false;
    m_firstFrameIsInserted = false;
    m_level = 0;
    mIsModified = true;

    createIntegerAttribute("patch-size", "Patch size", "", 0);
    createIntegerAttribute("patch-level", "Patch level", "Patch level used for image pyramid inputs", m_level);
    createFloatAttribute("patch-overlap", "Patch overlap", "Patch overlap in percent", m_overlapPercent);
    createFloatAttribute("mask-threshold", "Mask threshold", "Threshold, in percent, for how much of the candidate patch must be inside the mask to be accepted", m_maskThreshold);
}

PatchGenerator::PatchGenerator(int width, int height, int depth, int level, float percent, float maskThreshold) : PatchGenerator() {
    setPatchSize(width, height, depth);
    setPatchLevel(level);
    setOverlap(percent);
    setMaskThreshold(maskThreshold);
}

void PatchGenerator::loadAttributes() {
    auto patchSize = getIntegerListAttribute("patch-size");
    if(patchSize.size() == 2) {
        setPatchSize(patchSize[0], patchSize[1]);
    } else if(patchSize.size() == 3) {
        setPatchSize(patchSize[0], patchSize[1], patchSize[2]);
    } else {
        throw Exception("Incorrect number of size parameters in patch-size. Expected 2 or 3");
    }

    setPatchLevel(getIntegerAttribute("patch-level"));
    setOverlap(getFloatAttribute("patch-overlap"));
    setMaskThreshold(getFloatAttribute("mask-threshold"));
}

PatchGenerator::~PatchGenerator() {
    stop();
}

void PatchGenerator::generateStream() {
    Image::pointer previousPatch;

    // TODO implement support for different overlap in different dimensions
    int overlapInPixelsX = (int) std::round(m_overlapPercent * (float) m_width);
    int overlapInPixelsY = (int) std::round(m_overlapPercent * (float) m_height);
    int overlapInPixelsZ = (int) std::round(m_overlapPercent * (float) m_depth);
    int patchWidthWithoutOverlap = m_width - overlapInPixelsX * 2;
    int patchHeightWithoutOverlap = m_height - overlapInPixelsY * 2;
    int patchDepthWithoutOverlap = m_depth - overlapInPixelsZ * 2;

    if(m_inputImagePyramid) {
        if(m_width % 2 != 0 || m_height % 2 != 0)
            throw Exception("Patch size must be dividable by 2");
        const int levelWidth = m_inputImagePyramid->getLevelWidth(m_level);
        const int levelHeight = m_inputImagePyramid->getLevelHeight(m_level);
        const int TIFFmultiplumCriteria = 16;
        if(patchWidthWithoutOverlap % TIFFmultiplumCriteria > 0 || patchHeightWithoutOverlap % TIFFmultiplumCriteria > 0) {
            // Resulting patch size must be a multiple of 16
            overlapInPixelsX = overlapInPixelsX + (patchWidthWithoutOverlap % TIFFmultiplumCriteria)/2;
            overlapInPixelsY = overlapInPixelsY + (patchHeightWithoutOverlap % TIFFmultiplumCriteria)/2;
            reportWarning() << "Patch size must be a multiple of " << TIFFmultiplumCriteria << " (TIFF limitation). Adding some overlap (" << overlapInPixelsX << ", " << overlapInPixelsY << ") to fix." << reportEnd();
            patchWidthWithoutOverlap = m_width - overlapInPixelsX * 2;
            patchHeightWithoutOverlap = m_height - overlapInPixelsY * 2;
            if(patchWidthWithoutOverlap % TIFFmultiplumCriteria > 0 || patchHeightWithoutOverlap % TIFFmultiplumCriteria > 0)
                throw Exception("Error in compensation of patch size..");
        }
        const int patchesX = std::ceil((float) levelWidth / (float) patchWidthWithoutOverlap);
        const int patchesY = std::ceil((float) levelHeight / (float) patchHeightWithoutOverlap);

        for(int patchY = 1; patchY < patchesY; ++patchY) {
            for(int patchX = 1; patchX < patchesX; ++patchX) {
                mRuntimeManager->startRegularTimer("create patch");
                int patchWidth = m_width;
                if(patchX*patchWidthWithoutOverlap + patchWidth - overlapInPixelsX >= levelWidth) {
                    patchWidth = levelWidth - patchX * patchWidthWithoutOverlap + overlapInPixelsX - 1;
                }
                int patchHeight = m_height;
                if(patchY*patchHeightWithoutOverlap + patchHeight - overlapInPixelsY >= levelHeight) {
                    patchHeight = levelHeight - patchY * patchHeightWithoutOverlap + overlapInPixelsY - 1;
                }

                if(m_inputMask) {
                    // If a mask exist, check if this patch should be included or not
                    // At least half of the patch should be clasified as foreground
                    auto access = m_inputMask->getImageAccess(ACCESS_READ);
                    auto croppedMask = m_inputMask->crop(
                        Vector2i(
                            round(m_inputMask->getWidth() * ((float)patchX / patchesX)),
                            round(m_inputMask->getHeight() * ((float)patchY / patchesY))
                        ),
                        Vector2i(
                            round(m_inputMask->getWidth() * (1.0f/patchesX)),
                            round(m_inputMask->getHeight() * (1.0f/patchesY))
                        )
                    );
                    float average = croppedMask->calculateAverageIntensity();
                    if(average < m_maskThreshold)  // A specific percentage of the mask has to be foreground to be assessed
                        continue;
                }
                reportInfo() << "Generating patch " << patchX << " " << patchY << reportEnd();
                auto access = m_inputImagePyramid->getAccess(ACCESS_READ);
                // TODO handle edge cases
                if(patchWidth < overlapInPixelsX*2 || patchHeight < overlapInPixelsY*2)
                    continue;
                auto patch = access->getPatchAsImage(m_level, patchX * patchWidthWithoutOverlap - overlapInPixelsX, patchY * patchHeightWithoutOverlap - overlapInPixelsY,
                                                                  patchWidth,
                                                                  patchHeight);

                // Store some frame data useful for patch stitching
                patch->setFrameData("original-width", std::to_string(levelWidth));
                patch->setFrameData("original-height", std::to_string(levelHeight));
                patch->setFrameData("patchid-x", std::to_string(patchX));
                patch->setFrameData("patchid-y", std::to_string(patchY));
                // Target width/height of patches
                patch->setFrameData("patch-width", std::to_string(m_width));
                patch->setFrameData("patch-height", std::to_string(m_height));
                patch->setFrameData("patch-overlap-x", std::to_string(overlapInPixelsX));
                patch->setFrameData("patch-overlap-y", std::to_string(overlapInPixelsY));
                patch->setFrameData("patch-spacing-x", std::to_string(patch->getSpacing().x()));
                patch->setFrameData("patch-spacing-y", std::to_string(patch->getSpacing().y()));
                patch->setFrameData("patch-level", std::to_string(m_level));
                patch->setFrameData("progress", std::to_string((float)(patchX+patchY*patchesX)/(patchesX*patchesY)));

                mRuntimeManager->stopRegularTimer("create patch");
                try {
                    if(previousPatch) {
                        addOutputData(0, previousPatch, false);
                        frameAdded();
                    }
                } catch(ThreadStopped &e) {
                    std::unique_lock<std::mutex> lock(m_stopMutex);
                    m_stop = true;
                    break;
                }
                previousPatch = patch;
                std::unique_lock<std::mutex> lock(m_stopMutex);
                if(m_stop)
                    break;
            }
            std::unique_lock<std::mutex> lock(m_stopMutex);
            if(m_stop) {
                //m_streamIsStarted = false;
                m_firstFrameIsInserted = false;
                break;
            }
        }
    } else if(m_inputVolume) {
        const int width = m_inputVolume->getWidth();
        const int height = m_inputVolume->getHeight();
        const int depth = m_inputVolume->getDepth();
        auto transformData = SceneGraph::getEigenTransformFromData(m_inputVolume).data();
        std::string transformString;
        for(int i = 0; i < 16; ++i)
            transformString += std::to_string(transformData[i]) + " ";

        const int patchesX = std::ceil((float) width / (float) patchWidthWithoutOverlap);
        const int patchesY = std::ceil((float) height / (float) patchHeightWithoutOverlap);
        const int patchesZ = std::ceil((float) depth / (float) patchDepthWithoutOverlap);

        for(int patchZ = 0; patchZ < patchesZ; ++patchZ) {
        for(int patchY = 0; patchY < patchesY; ++patchY) {
        for(int patchX = 0; patchX < patchesX; ++patchX) {
            mRuntimeManager->startRegularTimer("create patch");

            int patchWidth = m_width;
            if(patchX*patchWidthWithoutOverlap + patchWidth - overlapInPixelsX > width) {
                patchWidth = width - patchX * patchWidthWithoutOverlap + overlapInPixelsX - 1;
            }
            int patchHeight = m_height;
            if(patchY*patchHeightWithoutOverlap + patchHeight - overlapInPixelsY > height) {
                patchHeight = height - patchY * patchHeightWithoutOverlap + overlapInPixelsY - 1;
            }
            int patchDepth = m_depth;
            if(patchZ*patchDepthWithoutOverlap + patchDepth - overlapInPixelsZ > depth) {
                patchDepth = depth - patchZ * patchDepthWithoutOverlap + overlapInPixelsZ - 1;
            }

            int x = patchX * patchWidthWithoutOverlap - overlapInPixelsX;
            int y = patchY * patchHeightWithoutOverlap - overlapInPixelsY;
            int z = patchZ * patchDepthWithoutOverlap - overlapInPixelsZ;

            reportInfo() << "Creating 2D image patch at offset " << x << " " << y << " " << z << " with size " << patchWidth << " " << patchHeight << " " << patchDepth << reportEnd();
            auto patch = m_inputVolume->crop(Vector3i(x, y, z), Vector3i(patchWidth, patchHeight, patchDepth), true);
            patch->setFrameData("original-width", std::to_string(width));
            patch->setFrameData("original-height", std::to_string(height));
            patch->setFrameData("original-depth", std::to_string(depth));
            patch->setFrameData("original-transform", transformString);
            patch->setFrameData("patch-offset-x", std::to_string(x));
            patch->setFrameData("patch-offset-y", std::to_string(y));
            patch->setFrameData("patch-offset-z", std::to_string(z));
            patch->setFrameData("patch-width", std::to_string(m_width));
            patch->setFrameData("patch-height", std::to_string(m_height));
            patch->setFrameData("patch-depth", std::to_string(m_depth));
            patch->setFrameData("patchid-x", std::to_string(patchX));
            patch->setFrameData("patchid-y", std::to_string(patchY));
            patch->setFrameData("patchid-z", std::to_string(patchZ));
            patch->setFrameData("patch-overlap-x", std::to_string(overlapInPixelsX));
            patch->setFrameData("patch-overlap-y", std::to_string(overlapInPixelsY));
            patch->setFrameData("patch-overlap-z", std::to_string(overlapInPixelsZ));
            Vector3f spacing = m_inputVolume->getSpacing();
            patch->setFrameData("patch-spacing-x", std::to_string(spacing.x()));
            patch->setFrameData("patch-spacing-y", std::to_string(spacing.y()));
            patch->setFrameData("patch-spacing-z", std::to_string(spacing.z()));
            patch->setFrameData("progress", std::to_string((float)(patchX+patchY*patchesX+patchZ*patchesX*patchesY)/(patchesX*patchesY*patchesZ)));
            try {
                if(previousPatch) {
                    addOutputData(0, previousPatch, false);
                    frameAdded();
                    //std::this_thread::sleep_for(std::chrono::seconds(2));
                }
            } catch(ThreadStopped &e) {
                std::unique_lock<std::mutex> lock(m_stopMutex);
                m_stop = true;
                break;
            }
            mRuntimeManager->stopRegularTimer("create patch");
            previousPatch = patch;
            std::unique_lock<std::mutex> lock(m_stopMutex);
            if(m_stop)
                break;
        }}}
    } else {
        throw Exception("Unsupported data object given to PatchGenerator");
    }
    // Add final patch, and mark it has last frame
    previousPatch->setLastFrame(getNameOfClass());
    try {
        addOutputData(0, previousPatch, false);
    } catch(ThreadStopped &e) {

    }
    reportInfo() << "Done generating patches" << reportEnd();
}

void PatchGenerator::execute() {
    if(m_width <= 0 || m_height <= 0 || m_depth <= 0)
        throw Exception("Width, height and depth must be set to a positive number");

    auto input = getInputData<SpatialDataObject>();
    m_inputImagePyramid = std::dynamic_pointer_cast<ImagePyramid>(input);
    m_inputVolume = std::dynamic_pointer_cast<Image>(input);

    if(mInputConnections.count(1) > 0) {
        // If a mask was given store it
        m_inputMask = getInputData<Image>(1);
    }

    startStream();
    waitForFirstFrame();
}

void PatchGenerator::setPatchSize(int width, int height, int depth) {
    m_width = width;
    m_height = height;
    m_depth = depth;
    mIsModified = true;
}

void PatchGenerator::setPatchLevel(int level) {
    m_level = level;
    mIsModified = true;
}

void PatchGenerator::setOverlap(float percent) {
    if(percent < 0 || percent > 1)
        throw Exception("Overlap percent must be >= 0 && <= 1");
    m_overlapPercent = percent;
    mIsModified = true;
}

void PatchGenerator::setMaskThreshold(float percent) {
    if(percent < 0 || percent > 1)
        throw Exception("Mask threshold must be >= 0 && <= 1");
    m_maskThreshold = percent;
    mIsModified = true;
}

}<|endoftext|>


<commit_before>//===- GCOVr.cpp - LLVM coverage tool -------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// GCOV implements the interface to read and write coverage files that use
// 'gcov' format.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GCOV.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/system_error.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// GCOVFile implementation.

/// ~GCOVFile - Delete GCOVFile and its content.
GCOVFile::~GCOVFile() {
  DeleteContainerPointers(Functions);
}

/// isGCDAFile - Return true if Format identifies a .gcda file.
static bool isGCDAFile(GCOV::GCOVFormat Format) {
  return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404;
}

/// isGCNOFile - Return true if Format identifies a .gcno file.
static bool isGCNOFile(GCOV::GCOVFormat Format) {
  return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404;
}

/// read - Read GCOV buffer.
bool GCOVFile::read(GCOVBuffer &Buffer) {
  GCOV::GCOVFormat Format = Buffer.readGCOVFormat();
  if (Format == GCOV::InvalidGCOV)
    return false;

  unsigned i = 0;
  while (1) {
    GCOVFunction *GFun = NULL;
    if (isGCDAFile(Format)) {
      // Use existing function while reading .gcda file.
      assert(i < Functions.size() && ".gcda data does not match .gcno data");
      GFun = Functions[i];
    } else if (isGCNOFile(Format)){
      GFun = new GCOVFunction();
      Functions.push_back(GFun);
    }
    if (!GFun || !GFun->read(Buffer, Format))
      break;
    ++i;
  }
  return true;
}

/// dump - Dump GCOVFile content on standard out for debugging purposes.
void GCOVFile::dump() {
  for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
         E = Functions.end(); I != E; ++I)
    (*I)->dump();
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFile::collectLineCounts(FileInfo &FI) {
  for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
         E = Functions.end(); I != E; ++I)
    (*I)->collectLineCounts(FI);
}

//===----------------------------------------------------------------------===//
// GCOVFunction implementation.

/// ~GCOVFunction - Delete GCOVFunction and its content.
GCOVFunction::~GCOVFunction() {
  DeleteContainerPointers(Blocks);
}

/// read - Read a aunction from the buffer. Return false if buffer cursor
/// does not point to a function tag.
bool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
  if (!Buff.readFunctionTag())
    return false;

  Buff.readInt(); // Function header length
  Ident = Buff.readInt();
  Buff.readInt(); // Checksum #1
  if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402)
    Buff.readInt(); // Checksum #2

  Name = Buff.readString();
  if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404)
    Filename = Buff.readString();

  if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) {
    Buff.readArcTag();
    uint32_t Count = Buff.readInt() / 2;
    for (unsigned i = 0, e = Count; i != e; ++i) {
      Blocks[i]->addCount(Buff.readInt64());
    }
    return true;
  }

  LineNumber = Buff.readInt();

  // read blocks.
  bool BlockTagFound = Buff.readBlockTag();
  (void)BlockTagFound;
  assert(BlockTagFound && "Block Tag not found!");
  uint32_t BlockCount = Buff.readInt();
  for (int i = 0, e = BlockCount; i != e; ++i) {
    Buff.readInt(); // Block flags;
    Blocks.push_back(new GCOVBlock(i));
  }

  // read edges.
  while (Buff.readEdgeTag()) {
    uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
    uint32_t BlockNo = Buff.readInt();
    assert(BlockNo < BlockCount && "Unexpected Block number!");
    for (int i = 0, e = EdgeCount; i != e; ++i) {
      Blocks[BlockNo]->addEdge(Buff.readInt());
      Buff.readInt(); // Edge flag
    }
  }

  // read line table.
  while (Buff.readLineTag()) {
    uint32_t LineTableLength = Buff.readInt();
    uint32_t Size = Buff.getCursor() + LineTableLength*4;
    uint32_t BlockNo = Buff.readInt();
    assert(BlockNo < BlockCount && "Unexpected Block number!");
    GCOVBlock *Block = Blocks[BlockNo];
    Buff.readInt(); // flag
    while (Buff.getCursor() != (Size - 4)) {
      StringRef Filename = Buff.readString();
      if (Buff.getCursor() == (Size - 4)) break;
      while (uint32_t L = Buff.readInt())
        Block->addLine(Filename, L);
    }
    Buff.readInt(); // flag
  }
  return true;
}

/// dump - Dump GCOVFunction content on standard out for debugging purposes.
void GCOVFunction::dump() {
  outs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
  for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
         E = Blocks.end(); I != E; ++I)
    (*I)->dump();
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFunction::collectLineCounts(FileInfo &FI) {
  for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
         E = Blocks.end(); I != E; ++I)
    (*I)->collectLineCounts(FI);
}

//===----------------------------------------------------------------------===//
// GCOVBlock implementation.

/// ~GCOVBlock - Delete GCOVBlock and its content.
GCOVBlock::~GCOVBlock() {
  Edges.clear();
  DeleteContainerSeconds(Lines);
}

void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
  GCOVLines *&LinesForFile = Lines[Filename];
  if (!LinesForFile)
    LinesForFile = new GCOVLines();
  LinesForFile->add(LineNo);
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVBlock::collectLineCounts(FileInfo &FI) {
  for (StringMap<GCOVLines *>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    I->second->collectLineCounts(FI, I->first(), Counter);
}

/// dump - Dump GCOVBlock content on standard out for debugging purposes.
void GCOVBlock::dump() {
  outs() << "Block : " << Number << " Counter : " << Counter << "\n";
  if (!Edges.empty()) {
    outs() << "\tEdges : ";
    for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end();
         I != E; ++I)
      outs() << (*I) << ",";
    outs() << "\n";
  }
  if (!Lines.empty()) {
    outs() << "\tLines : ";
    for (StringMap<GCOVLines *>::iterator LI = Lines.begin(),
           LE = Lines.end(); LI != LE; ++LI) {
      outs() << LI->first() << " -> ";
      LI->second->dump();
      outs() << "\n";
    }
  }
}

//===----------------------------------------------------------------------===//
// GCOVLines implementation.

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename,
                                  uint64_t Count) {
  for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    FI.addLineCount(Filename, *I, Count);
}

/// dump - Dump GCOVLines content on standard out for debugging purposes.
void GCOVLines::dump() {
  for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    outs() << (*I) << ",";
}

//===----------------------------------------------------------------------===//
// FileInfo implementation.

/// addLineCount - Add line count for the given line number in a file.
void FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) {
  if (LineInfo.find(Filename) == LineInfo.end()) {
    OwningPtr<MemoryBuffer> Buff;
    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
      errs() << Filename << ": " << ec.message() << "\n";
      return;
    }
    StringRef AllLines = Buff.take()->getBuffer();
    LineCounts L(AllLines.count('\n'));
    L[Line-1] = Count;
    LineInfo[Filename] = L;
    return;
  }
  LineCounts &L = LineInfo[Filename];
  L[Line-1] = Count;
}

/// print -  Print source files with collected line count information.
void FileInfo::print(StringRef gcnoFile, StringRef gcdaFile) {
  for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end();
       I != E; ++I) {
    StringRef Filename = I->first();
    outs() << "        -:    0:Source:" << Filename << "\n";
    outs() << "        -:    0:Graph:" << gcnoFile << "\n";
    outs() << "        -:    0:Data:" << gcdaFile << "\n";
    LineCounts &L = LineInfo[Filename];
    OwningPtr<MemoryBuffer> Buff;
    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
      errs() << Filename << ": " << ec.message() << "\n";
      return;
    }
    StringRef AllLines = Buff.take()->getBuffer();
    for (unsigned i = 0, e = L.size(); i != e; ++i) {
      if (L[i])
        outs() << format("%9lu:", L[i]);
      else
        outs() << "        -:";
      std::pair<StringRef, StringRef> P = AllLines.split('\n');
      if (AllLines != P.first)
        outs() << format("%5u:", i+1) << P.first;
      outs() << "\n";
      AllLines = P.second;
    }
  }
}

<commit_msg>llvm-cov: fix a typo and rename a variable.<commit_after>//===- GCOVr.cpp - LLVM coverage tool -------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// GCOV implements the interface to read and write coverage files that use
// 'gcov' format.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GCOV.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/system_error.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// GCOVFile implementation.

/// ~GCOVFile - Delete GCOVFile and its content.
GCOVFile::~GCOVFile() {
  DeleteContainerPointers(Functions);
}

/// isGCDAFile - Return true if Format identifies a .gcda file.
static bool isGCDAFile(GCOV::GCOVFormat Format) {
  return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404;
}

/// isGCNOFile - Return true if Format identifies a .gcno file.
static bool isGCNOFile(GCOV::GCOVFormat Format) {
  return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404;
}

/// read - Read GCOV buffer.
bool GCOVFile::read(GCOVBuffer &Buffer) {
  GCOV::GCOVFormat Format = Buffer.readGCOVFormat();
  if (Format == GCOV::InvalidGCOV)
    return false;

  unsigned i = 0;
  while (1) {
    GCOVFunction *GFun = NULL;
    if (isGCDAFile(Format)) {
      // Use existing function while reading .gcda file.
      assert(i < Functions.size() && ".gcda data does not match .gcno data");
      GFun = Functions[i];
    } else if (isGCNOFile(Format)){
      GFun = new GCOVFunction();
      Functions.push_back(GFun);
    }
    if (!GFun || !GFun->read(Buffer, Format))
      break;
    ++i;
  }
  return true;
}

/// dump - Dump GCOVFile content on standard out for debugging purposes.
void GCOVFile::dump() {
  for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
         E = Functions.end(); I != E; ++I)
    (*I)->dump();
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFile::collectLineCounts(FileInfo &FI) {
  for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(),
         E = Functions.end(); I != E; ++I)
    (*I)->collectLineCounts(FI);
}

//===----------------------------------------------------------------------===//
// GCOVFunction implementation.

/// ~GCOVFunction - Delete GCOVFunction and its content.
GCOVFunction::~GCOVFunction() {
  DeleteContainerPointers(Blocks);
}

/// read - Read a function from the buffer. Return false if buffer cursor
/// does not point to a function tag.
bool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
  if (!Buff.readFunctionTag())
    return false;

  Buff.readInt(); // Function header length
  Ident = Buff.readInt();
  Buff.readInt(); // Checksum #1
  if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402)
    Buff.readInt(); // Checksum #2

  Name = Buff.readString();
  if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404)
    Filename = Buff.readString();

  if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) {
    Buff.readArcTag();
    uint32_t Count = Buff.readInt() / 2;
    for (unsigned i = 0, e = Count; i != e; ++i) {
      Blocks[i]->addCount(Buff.readInt64());
    }
    return true;
  }

  LineNumber = Buff.readInt();

  // read blocks.
  bool BlockTagFound = Buff.readBlockTag();
  (void)BlockTagFound;
  assert(BlockTagFound && "Block Tag not found!");
  uint32_t BlockCount = Buff.readInt();
  for (int i = 0, e = BlockCount; i != e; ++i) {
    Buff.readInt(); // Block flags;
    Blocks.push_back(new GCOVBlock(i));
  }

  // read edges.
  while (Buff.readEdgeTag()) {
    uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
    uint32_t BlockNo = Buff.readInt();
    assert(BlockNo < BlockCount && "Unexpected Block number!");
    for (int i = 0, e = EdgeCount; i != e; ++i) {
      Blocks[BlockNo]->addEdge(Buff.readInt());
      Buff.readInt(); // Edge flag
    }
  }

  // read line table.
  while (Buff.readLineTag()) {
    uint32_t LineTableLength = Buff.readInt();
    uint32_t EndPos = Buff.getCursor() + LineTableLength*4;
    uint32_t BlockNo = Buff.readInt();
    assert(BlockNo < BlockCount && "Unexpected Block number!");
    GCOVBlock *Block = Blocks[BlockNo];
    Buff.readInt(); // flag
    while (Buff.getCursor() != (EndPos - 4)) {
      StringRef Filename = Buff.readString();
      if (Buff.getCursor() == (EndPos - 4)) break;
      while (uint32_t L = Buff.readInt())
        Block->addLine(Filename, L);
    }
    Buff.readInt(); // flag
  }
  return true;
}

/// dump - Dump GCOVFunction content on standard out for debugging purposes.
void GCOVFunction::dump() {
  outs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
  for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
         E = Blocks.end(); I != E; ++I)
    (*I)->dump();
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVFunction::collectLineCounts(FileInfo &FI) {
  for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
         E = Blocks.end(); I != E; ++I)
    (*I)->collectLineCounts(FI);
}

//===----------------------------------------------------------------------===//
// GCOVBlock implementation.

/// ~GCOVBlock - Delete GCOVBlock and its content.
GCOVBlock::~GCOVBlock() {
  Edges.clear();
  DeleteContainerSeconds(Lines);
}

void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
  GCOVLines *&LinesForFile = Lines[Filename];
  if (!LinesForFile)
    LinesForFile = new GCOVLines();
  LinesForFile->add(LineNo);
}

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVBlock::collectLineCounts(FileInfo &FI) {
  for (StringMap<GCOVLines *>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    I->second->collectLineCounts(FI, I->first(), Counter);
}

/// dump - Dump GCOVBlock content on standard out for debugging purposes.
void GCOVBlock::dump() {
  outs() << "Block : " << Number << " Counter : " << Counter << "\n";
  if (!Edges.empty()) {
    outs() << "\tEdges : ";
    for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end();
         I != E; ++I)
      outs() << (*I) << ",";
    outs() << "\n";
  }
  if (!Lines.empty()) {
    outs() << "\tLines : ";
    for (StringMap<GCOVLines *>::iterator LI = Lines.begin(),
           LE = Lines.end(); LI != LE; ++LI) {
      outs() << LI->first() << " -> ";
      LI->second->dump();
      outs() << "\n";
    }
  }
}

//===----------------------------------------------------------------------===//
// GCOVLines implementation.

/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename,
                                  uint64_t Count) {
  for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    FI.addLineCount(Filename, *I, Count);
}

/// dump - Dump GCOVLines content on standard out for debugging purposes.
void GCOVLines::dump() {
  for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(),
         E = Lines.end(); I != E; ++I)
    outs() << (*I) << ",";
}

//===----------------------------------------------------------------------===//
// FileInfo implementation.

/// addLineCount - Add line count for the given line number in a file.
void FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) {
  if (LineInfo.find(Filename) == LineInfo.end()) {
    OwningPtr<MemoryBuffer> Buff;
    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
      errs() << Filename << ": " << ec.message() << "\n";
      return;
    }
    StringRef AllLines = Buff.take()->getBuffer();
    LineCounts L(AllLines.count('\n'));
    L[Line-1] = Count;
    LineInfo[Filename] = L;
    return;
  }
  LineCounts &L = LineInfo[Filename];
  L[Line-1] = Count;
}

/// print -  Print source files with collected line count information.
void FileInfo::print(StringRef gcnoFile, StringRef gcdaFile) {
  for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end();
       I != E; ++I) {
    StringRef Filename = I->first();
    outs() << "        -:    0:Source:" << Filename << "\n";
    outs() << "        -:    0:Graph:" << gcnoFile << "\n";
    outs() << "        -:    0:Data:" << gcdaFile << "\n";
    LineCounts &L = LineInfo[Filename];
    OwningPtr<MemoryBuffer> Buff;
    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
      errs() << Filename << ": " << ec.message() << "\n";
      return;
    }
    StringRef AllLines = Buff.take()->getBuffer();
    for (unsigned i = 0, e = L.size(); i != e; ++i) {
      if (L[i])
        outs() << format("%9lu:", L[i]);
      else
        outs() << "        -:";
      std::pair<StringRef, StringRef> P = AllLines.split('\n');
      if (AllLines != P.first)
        outs() << format("%5u:", i+1) << P.first;
      outs() << "\n";
      AllLines = P.second;
    }
  }
}

<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2015 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include "AbstractSyncAsyncTest.cpp"
#include "joynr/tests/testJoynrMessagingConnector.h"
#include "joynr/IReplyCaller.h"
#include <string>
#include "utils/MockObjects.h"
#include "joynr/SubscriptionCallback.h"
#include "joynr/OnChangeSubscriptionQos.h"

using ::testing::A;
using ::testing::_;
using ::testing::Return;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::AllOf;
using ::testing::Property;
using ::testing::Invoke;
using ::testing::Unused;

using namespace joynr;

ACTION_P(ReleaseSemaphore,semaphore)
{
    semaphore->notify();
}

/**
 * @brief Fixutre.
 */
class TestJoynrMessagingConnectorTest : public AbstractSyncAsyncTest {
public:

    TestJoynrMessagingConnectorTest():
        mockSubscriptionManager(new MockSubscriptionManager()),
        gpsLocation(types::Localisation::GpsLocation(
                        9.0,
                        51.0,
                        508.0,
                        types::Localisation::GpsFixEnum::MODE2D,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        444,
                        444,
                        2)),
        floatValue(123.45),
        semaphore(0)
    {
    }

    ~TestJoynrMessagingConnectorTest()
    {
        delete mockSubscriptionManager;
    }

    // sets the expectations on the call expected on the MessageSender from the connector
    testing::internal::TypedExpectation<void(
            const std::string&, // sender participant ID
            const std::string&, // receiver participant ID
            const MessagingQos&, // messaging QoS
            const Request&, // request object to send
            std::shared_ptr<IReplyCaller> // reply caller to notify when reply is received
    )>& setExpectationsForSendRequestCall(std::string methodName) override {
        return EXPECT_CALL(
                    *mockJoynrMessageSender,
                    sendRequest(
                        Eq(proxyParticipantId), // sender participant ID
                        Eq(providerParticipantId), // receiver participant ID
                        _, // messaging QoS
                        Property(&Request::getMethodName, Eq(methodName)), // request object to send
                        Property(&std::shared_ptr<IReplyCaller>::get,NotNull()) // reply caller to notify when reply is received
                    )
        );
    }

    MockSubscriptionManager* mockSubscriptionManager;
    joynr::types::Localisation::GpsLocation gpsLocation;
    float floatValue;
    Semaphore semaphore;

    tests::testJoynrMessagingConnector* createConnector(bool cacheEnabled) {
        return new tests::testJoynrMessagingConnector(
                    mockJoynrMessageSender,
                    mockSubscriptionManager,
                    "myDomain",
                    proxyParticipantId,
                    providerParticipantId,
                    MessagingQos(),
                    &mockClientCache,
                    cacheEnabled);
    }

    tests::Itest* createFixture(bool cacheEnabled) override {
        return dynamic_cast<tests::Itest*>(createConnector(cacheEnabled));
    }

    void invokeSubscriptionCallback(const std::string& subscribeToName,
                                      std::shared_ptr<ISubscriptionCallback> callback,
                                      std::shared_ptr<SubscriptionQos> qos,
                                      SubscriptionRequest& subscriptionRequest) {
        std::ignore = subscribeToName;
        std::ignore = qos;
        std::ignore = subscriptionRequest;

        std::shared_ptr<SubscriptionCallback<joynr::types::Localisation::GpsLocation, float>> typedCallback =
                std::dynamic_pointer_cast<SubscriptionCallback<joynr::types::Localisation::GpsLocation, float>>(callback);

        typedCallback->onSuccess(gpsLocation, floatValue);
    }
};

typedef TestJoynrMessagingConnectorTest TestJoynrMessagingConnectorTestDeathTest;

/*
 * Tests
 */

TEST_F(TestJoynrMessagingConnectorTest, async_getAttributeNotCached) {
    testAsync_getAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setAttributeNotCached) {
    testSync_setAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getAttributeNotCached) {
    testSync_getAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getAttributeCached) {
    testAsync_getAttributeCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getAttributeCached) {
    testSync_getAttributeCached();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getterCallReturnsProviderRuntimeException) {
    testAsync_getterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getterCallReturnsProviderRuntimeException) {
    testSync_getterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getterCallReturnsMethodInvocationException) {
    testAsync_getterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getterCallReturnsMethodInvocationException) {
    testSync_getterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_setterCallReturnsProviderRuntimeException) {
    testAsync_setterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setterCallReturnsProviderRuntimeException) {
    testSync_setterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_setterCallReturnsMethodInvocationException) {
    testAsync_setterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setterCallReturnsMethodInvocationException) {
    testSync_setterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsProviderRuntimeException) {
    testAsync_methodCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsProviderRuntimeException) {
    testSync_methodCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsMethodInvocationException) {
    testAsync_methodCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsMethodInvocationException) {
    testSync_methodCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsErrorEnum) {
    testAsync_methodCallReturnsErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsErrorEnum) {
    testSync_methodCallReturnsErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsExtendedErrorEnum) {
    testAsync_methodCallReturnsExtendedErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsExtendedErrorEnum) {
    testSync_methodCallReturnsExtendedErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsInlineErrorEnum) {
    testAsync_methodCallReturnsInlineErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsInlineErrorEnum) {
    testSync_methodCallReturnsInlineErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_OperationWithNoArguments) {
    testAsync_OperationWithNoArguments();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_OperationWithNoArguments) {
    testSync_OperationWithNoArguments();
}

TEST_F(TestJoynrMessagingConnectorTest, subscribeToAttribute) {
    testSubscribeToAttribute();
}

TEST_F(TestJoynrMessagingConnectorTest, testBroadcastListenerWrapper) {
    tests::testJoynrMessagingConnector* connector = createConnector(false);

    auto mockListener = std::make_shared<MockGpsFloatSubscriptionListener>();

    EXPECT_CALL(
                        *mockSubscriptionManager,
                        registerSubscription(
                            Eq("locationUpdateWithSpeed"), //broadcastName
                            _,
                            _, // messaging QoS
                            _
                        )).WillOnce(testing::Invoke(this, &TestJoynrMessagingConnectorTest::invokeSubscriptionCallback));
    //   joynr::tests::LocationUpdateWithSpeedSelectiveBroadcastSubscriptionListenerWrapper

    // Use a semaphore to count and wait on calls to the mock listener
    EXPECT_CALL(*mockListener, onReceive(Eq(gpsLocation), Eq(floatValue)))
            .WillOnce(ReleaseSemaphore(&semaphore));

    auto qos = std::make_shared<OnChangeSubscriptionQos>();
    connector->subscribeToLocationUpdateWithSpeedBroadcast(mockListener, qos);

    // Wait for a subscription message to arrive
    ASSERT_TRUE(semaphore.waitFor(std::chrono::seconds(2)));
}
<commit_msg>[C++] fixed TestJoynrMessagingConnectorTest<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2015 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include "AbstractSyncAsyncTest.cpp"
#include "joynr/tests/testJoynrMessagingConnector.h"
#include "joynr/IReplyCaller.h"
#include <string>
#include "utils/MockObjects.h"
#include "joynr/SubscriptionCallback.h"
#include "joynr/OnChangeSubscriptionQos.h"

using ::testing::A;
using ::testing::_;
using ::testing::Return;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::AllOf;
using ::testing::Property;
using ::testing::Invoke;
using ::testing::Unused;

using namespace joynr;

ACTION_P(ReleaseSemaphore,semaphore)
{
    semaphore->notify();
}

/**
 * @brief Fixutre.
 */
class TestJoynrMessagingConnectorTest : public AbstractSyncAsyncTest {
public:

    TestJoynrMessagingConnectorTest():
        mockSubscriptionManager(new MockSubscriptionManager()),
        gpsLocation(types::Localisation::GpsLocation(
                        9.0,
                        51.0,
                        508.0,
                        types::Localisation::GpsFixEnum::MODE2D,
                        0.0,
                        0.0,
                        0.0,
                        0.0,
                        444,
                        444,
                        2)),
        floatValue(123.45),
        semaphore(0)
    {
    }

    ~TestJoynrMessagingConnectorTest()
    {
        delete mockSubscriptionManager;
    }

    // sets the expectations on the call expected on the MessageSender from the connector
    testing::internal::TypedExpectation<void(
            const std::string&, // sender participant ID
            const std::string&, // receiver participant ID
            const MessagingQos&, // messaging QoS
            const Request&, // request object to send
            std::shared_ptr<IReplyCaller> // reply caller to notify when reply is received
    )>& setExpectationsForSendRequestCall(std::string methodName) override {
        return EXPECT_CALL(
                    *mockJoynrMessageSender,
                    sendRequest(
                        Eq(proxyParticipantId), // sender participant ID
                        Eq(providerParticipantId), // receiver participant ID
                        _, // messaging QoS
                        Property(&Request::getMethodName, Eq(methodName)), // request object to send
                        Property(&std::shared_ptr<IReplyCaller>::get,NotNull()) // reply caller to notify when reply is received
                    )
        );
    }

    MockSubscriptionManager* mockSubscriptionManager;
    joynr::types::Localisation::GpsLocation gpsLocation;
    float floatValue;
    Semaphore semaphore;

    tests::testJoynrMessagingConnector* createConnector(bool cacheEnabled) {
        return new tests::testJoynrMessagingConnector(
                    mockJoynrMessageSender,
                    mockSubscriptionManager,
                    "myDomain",
                    proxyParticipantId,
                    providerParticipantId,
                    MessagingQos(),
                    &mockClientCache,
                    cacheEnabled);
    }

    tests::Itest* createFixture(bool cacheEnabled) override {
        return dynamic_cast<tests::Itest*>(createConnector(cacheEnabled));
    }

    void invokeSubscriptionCallback(const std::string& subscribeToName,
                                      std::shared_ptr<ISubscriptionCallback> callback,
                                      std::shared_ptr<SubscriptionQos> qos,
                                      SubscriptionRequest& subscriptionRequest) {
        std::ignore = subscribeToName;
        subscriptionRequest.setQos(qos);
        std::shared_ptr<SubscriptionCallback<joynr::types::Localisation::GpsLocation, float>> typedCallback =
                std::dynamic_pointer_cast<SubscriptionCallback<joynr::types::Localisation::GpsLocation, float>>(callback);

        typedCallback->onSuccess(gpsLocation, floatValue);
    }
};

typedef TestJoynrMessagingConnectorTest TestJoynrMessagingConnectorTestDeathTest;

/*
 * Tests
 */

TEST_F(TestJoynrMessagingConnectorTest, async_getAttributeNotCached) {
    testAsync_getAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setAttributeNotCached) {
    testSync_setAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getAttributeNotCached) {
    testSync_getAttributeNotCached();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getAttributeCached) {
    testAsync_getAttributeCached();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getAttributeCached) {
    testSync_getAttributeCached();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getterCallReturnsProviderRuntimeException) {
    testAsync_getterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getterCallReturnsProviderRuntimeException) {
    testSync_getterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_getterCallReturnsMethodInvocationException) {
    testAsync_getterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_getterCallReturnsMethodInvocationException) {
    testSync_getterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_setterCallReturnsProviderRuntimeException) {
    testAsync_setterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setterCallReturnsProviderRuntimeException) {
    testSync_setterCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_setterCallReturnsMethodInvocationException) {
    testAsync_setterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_setterCallReturnsMethodInvocationException) {
    testSync_setterCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsProviderRuntimeException) {
    testAsync_methodCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsProviderRuntimeException) {
    testSync_methodCallReturnsProviderRuntimeException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsMethodInvocationException) {
    testAsync_methodCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsMethodInvocationException) {
    testSync_methodCallReturnsMethodInvocationException();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsErrorEnum) {
    testAsync_methodCallReturnsErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsErrorEnum) {
    testSync_methodCallReturnsErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsExtendedErrorEnum) {
    testAsync_methodCallReturnsExtendedErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsExtendedErrorEnum) {
    testSync_methodCallReturnsExtendedErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_methodCallReturnsInlineErrorEnum) {
    testAsync_methodCallReturnsInlineErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_methodCallReturnsInlineErrorEnum) {
    testSync_methodCallReturnsInlineErrorEnum();
}

TEST_F(TestJoynrMessagingConnectorTest, async_OperationWithNoArguments) {
    testAsync_OperationWithNoArguments();
}

TEST_F(TestJoynrMessagingConnectorTest, sync_OperationWithNoArguments) {
    testSync_OperationWithNoArguments();
}

TEST_F(TestJoynrMessagingConnectorTest, subscribeToAttribute) {
    testSubscribeToAttribute();
}

TEST_F(TestJoynrMessagingConnectorTest, testBroadcastListenerWrapper) {
    tests::testJoynrMessagingConnector* connector = createConnector(false);

    auto mockListener = std::make_shared<MockGpsFloatSubscriptionListener>();

    EXPECT_CALL(
                        *mockSubscriptionManager,
                        registerSubscription(
                            Eq("locationUpdateWithSpeed"), //broadcastName
                            _,
                            _, // messaging QoS
                            _
                        )).WillOnce(testing::Invoke(this, &TestJoynrMessagingConnectorTest::invokeSubscriptionCallback));
    //   joynr::tests::LocationUpdateWithSpeedSelectiveBroadcastSubscriptionListenerWrapper

    // Use a semaphore to count and wait on calls to the mock listener
    EXPECT_CALL(*mockListener, onReceive(Eq(gpsLocation), Eq(floatValue)))
            .WillOnce(ReleaseSemaphore(&semaphore));

    auto qos = std::make_shared<OnChangeSubscriptionQos>();
    connector->subscribeToLocationUpdateWithSpeedBroadcast(mockListener, qos);

    // Wait for a subscription message to arrive
    ASSERT_TRUE(semaphore.waitFor(std::chrono::seconds(2)));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: transparencygroupaction.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2007-01-22 11:52:27 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX
#define _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX

#include <cppcanvas/canvas.hxx>
#include <cppcanvas/renderer.hxx>
#include <action.hxx>

#include <memory> // auto_ptr

namespace basegfx {
    class B2DPoint;
    class B2DVector;
}

class GDIMetaFile;
class Gradient;

/* Definition of internal::TransparencyGroupActionFactory class */

namespace cppcanvas
{
    namespace internal
    {
        struct OutDevState;

        typedef ::std::auto_ptr< GDIMetaFile >  MtfAutoPtr;
        typedef ::std::auto_ptr< Gradient >     GradientAutoPtr;

        /** Transparency group action.

            This action groups a bunch of other actions, to be
            rendered with the given transparency setting against the
            background.

            Creates encapsulated converters between GDIMetaFile and
            XCanvas. The Canvas argument is deliberately placed at the
            constructor, to force reconstruction of this object for a
            new canvas. This considerably eases internal state
            handling, since a lot of the internal state (e.g. fonts,
            text layout) is Canvas-dependent.
         */
        class TransparencyGroupActionFactory
        {
        public:
            /** Create new transparency group action.

                @param rGroupMtf
                Metafile that groups all actions to be rendered
                transparent

                @param rParms
                Render parameters

                @param rDstPoint
                Left, top edge of destination, in current state
                coordinate system

                @param rDstSize
                Size of the transparency group object, in current
                state coordinate system.

                @param nAlpha
                Alpha value, must be in the range [0,1]
             */
            static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr&                   rGroupMtf,
                                                                  const Renderer::Parameters&   rParms,
                                                                  const ::basegfx::B2DPoint&    rDstPoint,
                                                                  const ::basegfx::B2DVector&   rDstSize,
                                                                  double                        nAlpha,
                                                                  const CanvasSharedPtr&        rCanvas,
                                                                  const OutDevState&            rState );

            /** Create new transparency group action.

                @param rGroupMtf
                Metafile that groups all actions to be rendered
                transparent.

                @param rAlphaGradient
                VCL gradient, to be rendered into the action's alpha
                channel.

                @param rParms
                Render parameters

                @param rDstPoint
                Left, top edge of destination, in current state
                coordinate system

                @param rDstSize
                Size of the transparency group object, in current
                state coordinate system.
             */
            static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr&                   rGroupMtf,
                                                                  GradientAutoPtr&              rAlphaGradient,
                                                                  const Renderer::Parameters&   rParms,
                                                                  const ::basegfx::B2DPoint&    rDstPoint,
                                                                  const ::basegfx::B2DVector&   rDstSize,
                                                                  const CanvasSharedPtr&        rCanvas,
                                                                  const OutDevState&            rState );

        private:
            // static factory, disable big four
            TransparencyGroupActionFactory();
            ~TransparencyGroupActionFactory();
            TransparencyGroupActionFactory(const TransparencyGroupActionFactory&);
            TransparencyGroupActionFactory& operator=( const TransparencyGroupActionFactory& );
        };
    }
}

#endif /*_CPPCANVAS_TRANSPARENCYGROUPACTION_HXX */
<commit_msg>INTEGRATION: CWS changefileheader (1.6.26); FILE MERGED 2008/03/31 13:07:08 rt 1.6.26.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: transparencygroupaction.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX
#define _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX

#include <cppcanvas/canvas.hxx>
#include <cppcanvas/renderer.hxx>
#include <action.hxx>

#include <memory> // auto_ptr

namespace basegfx {
    class B2DPoint;
    class B2DVector;
}

class GDIMetaFile;
class Gradient;

/* Definition of internal::TransparencyGroupActionFactory class */

namespace cppcanvas
{
    namespace internal
    {
        struct OutDevState;

        typedef ::std::auto_ptr< GDIMetaFile >  MtfAutoPtr;
        typedef ::std::auto_ptr< Gradient >     GradientAutoPtr;

        /** Transparency group action.

            This action groups a bunch of other actions, to be
            rendered with the given transparency setting against the
            background.

            Creates encapsulated converters between GDIMetaFile and
            XCanvas. The Canvas argument is deliberately placed at the
            constructor, to force reconstruction of this object for a
            new canvas. This considerably eases internal state
            handling, since a lot of the internal state (e.g. fonts,
            text layout) is Canvas-dependent.
         */
        class TransparencyGroupActionFactory
        {
        public:
            /** Create new transparency group action.

                @param rGroupMtf
                Metafile that groups all actions to be rendered
                transparent

                @param rParms
                Render parameters

                @param rDstPoint
                Left, top edge of destination, in current state
                coordinate system

                @param rDstSize
                Size of the transparency group object, in current
                state coordinate system.

                @param nAlpha
                Alpha value, must be in the range [0,1]
             */
            static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr&                   rGroupMtf,
                                                                  const Renderer::Parameters&   rParms,
                                                                  const ::basegfx::B2DPoint&    rDstPoint,
                                                                  const ::basegfx::B2DVector&   rDstSize,
                                                                  double                        nAlpha,
                                                                  const CanvasSharedPtr&        rCanvas,
                                                                  const OutDevState&            rState );

            /** Create new transparency group action.

                @param rGroupMtf
                Metafile that groups all actions to be rendered
                transparent.

                @param rAlphaGradient
                VCL gradient, to be rendered into the action's alpha
                channel.

                @param rParms
                Render parameters

                @param rDstPoint
                Left, top edge of destination, in current state
                coordinate system

                @param rDstSize
                Size of the transparency group object, in current
                state coordinate system.
             */
            static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr&                   rGroupMtf,
                                                                  GradientAutoPtr&              rAlphaGradient,
                                                                  const Renderer::Parameters&   rParms,
                                                                  const ::basegfx::B2DPoint&    rDstPoint,
                                                                  const ::basegfx::B2DVector&   rDstSize,
                                                                  const CanvasSharedPtr&        rCanvas,
                                                                  const OutDevState&            rState );

        private:
            // static factory, disable big four
            TransparencyGroupActionFactory();
            ~TransparencyGroupActionFactory();
            TransparencyGroupActionFactory(const TransparencyGroupActionFactory&);
            TransparencyGroupActionFactory& operator=( const TransparencyGroupActionFactory& );
        };
    }
}

#endif /*_CPPCANVAS_TRANSPARENCYGROUPACTION_HXX */
<|endoftext|>


<commit_before>/** \brief Utility for augmenting MARC records with links to a local full-text database.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015-2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <stdexcept>
#include <vector>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <libgen.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <kchashdb.h>
#include "Downloader.h"
#include "ExecUtil.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcUtil.h"
#include "MarcWriter.h"
#include "RegexMatcher.h"
#include "Semaphore.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "TimeLimit.h"
#include "util.h"

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "Usage: " << ::progname
              << "[--max-record-count count] [--skip-count count] [--process-count-low-and-high-watermarks low:high] "
              << "marc_input marc_output full_text_db\n"
              << "       --process-count-low-and-high-watermarks sets the maximum and minimum number of spawned\n"
              << "       child processes.  When we hit the high water mark we wait for child processes to exit\n"
              << "       until we reach the low watermark.\n\n";

    std::exit(EXIT_FAILURE);
}

// Checks subfields "3" and "z" to see if they start w/ "Rezension".
bool IsProbablyAReview(const Subfields &subfields) {
    const auto &_3_begin_end(subfields.getIterators('3'));
    if (_3_begin_end.first != _3_begin_end.second) {
        if (StringUtil::StartsWith(_3_begin_end.first->value_, "Rezension"))
            return true;
    } else {
        const auto &z_begin_end(subfields.getIterators('z'));
        if (z_begin_end.first != z_begin_end.second
            and StringUtil::StartsWith(z_begin_end.first->value_, "Rezension"))
            return true;
    }

    return false;
}

bool FoundAtLeastOneNonReviewLink(const MarcRecord &record) {
    for (size_t _856_index(record.getFieldIndex("856")); record.getTag(_856_index) == "856"; ++_856_index) {
        const Subfields subfields(record.getSubfields(_856_index));
        if (subfields.getIndicator1() == '7' or not subfields.hasSubfield('u'))
            continue;

        if (not IsProbablyAReview(subfields))
            return true;
    }

    return false;
}

// Returns the number of child processes that returned a non-zero exit code.
unsigned CleanUpZombies(const unsigned zombies_to_collect) {
    unsigned child_reported_failure_count(0);
    for (unsigned zombie_no(0); zombie_no < zombies_to_collect; ++zombie_no) {
        int exit_code;
        ::wait(&exit_code);
        if (exit_code != 0)
            ++child_reported_failure_count;
    }

    return child_reported_failure_count;
}

void ProcessRecords(const unsigned max_record_count, const unsigned skip_count, MarcReader * const marc_reader,
                    MarcWriter * const marc_writer, const std::string &db_filename,
                    const unsigned process_count_low_watermark, const unsigned process_count_high_watermark)
{
    Semaphore semaphore("/full_text_cached_counter", Semaphore::CREATE);
    std::string err_msg;
    unsigned total_record_count(0), spawn_count(0), active_child_count(0), child_reported_failure_count(0);

    const std::string UPDATE_FULL_TEXT_DB_PATH("/usr/local/bin/update_full_text_db");

    std::cout << "Skip " << skip_count << " records\n";
    off_t record_start = marc_reader->tell();
    while (MarcRecord record = marc_reader->read()) {
        if (total_record_count == max_record_count)
            break;
        ++total_record_count;
        if (total_record_count <= skip_count) {
            record_start = marc_reader->tell();
            continue;
        }

        if (not FoundAtLeastOneNonReviewLink(record)) {
            MarcUtil::FileLockedComposeAndWriteRecord(marc_writer, &record);
            record_start = marc_reader->tell();
            continue;
        }

        ExecUtil::Spawn(UPDATE_FULL_TEXT_DB_PATH,
                        { std::to_string(record_start), marc_reader->getPath(), marc_writer->getFile().getPath(),
                          db_filename });
        ++active_child_count;
        ++spawn_count;

        if (active_child_count > process_count_high_watermark) {
            child_reported_failure_count += CleanUpZombies(active_child_count - process_count_low_watermark);
            active_child_count = process_count_low_watermark;
        }
        record_start = marc_reader->tell();
    }

    // Wait for stragglers:
    child_reported_failure_count += CleanUpZombies(active_child_count);

    if (not err_msg.empty())
        Error(err_msg);
    std::cerr << "Read " << total_record_count << " records.\n";
    std::cerr << "Spawned " << spawn_count << " subprocesses.\n";
    std::cerr << semaphore.getValue()
              << " documents were not downloaded because their cached values had not yet expired.\n";
    std::cerr << child_reported_failure_count << " children reported a failure!\n";
}

constexpr unsigned PROCESS_COUNT_DEFAULT_HIGH_WATERMARK(10);
constexpr unsigned PROCESS_COUNT_DEFAULT_LOW_WATERMARK(5);

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4 and argc != 6 and argc != 8 and argc != 10)
        Usage();
    ++argv; // skip program name

    // Process optional args:
    unsigned max_record_count(UINT_MAX), skip_count(0);
    unsigned process_count_low_watermark(PROCESS_COUNT_DEFAULT_LOW_WATERMARK),
             process_count_high_watermark(PROCESS_COUNT_DEFAULT_HIGH_WATERMARK);
    while (argc > 4) {
        std::cout << "Arg: " << *argv << "\n";
        if (std::strcmp(*argv, "--max-record-count") == 0) {
            ++argv;
            if (not StringUtil::ToNumber(*argv, &max_record_count) or max_record_count == 0)
                Error("bad value for --max-record-count!");
            ++argv;
            argc -= 2;
        } else if (std::strcmp(*argv, "--skip-count") == 0) {
            ++argv;
            if (not StringUtil::ToNumber(*argv, &skip_count))
                Error("bad value for --skip-count!");
            std::cout << "Should skip " << skip_count << " records\n";
            ++argv;
            argc -= 2;
        } else if (std::strcmp("--process-count-low-and-high-watermarks", *argv) == 0) {
            ++argv;
            char *arg_end(*argv + std::strlen(*argv));
            char * const colon(std::find(*argv, arg_end, ':'));
            if (colon == arg_end)
                Error("bad argument to --process-count-low-and-high-watermarks: colon is missing!");
            *colon = '\0';
            if (not StringUtil::ToNumber(*argv, &process_count_low_watermark)
                or not StringUtil::ToNumber(*argv, &process_count_high_watermark))
                Error("low or high watermark is not an unsigned number!");
            if (process_count_high_watermark > process_count_low_watermark)
                Error("the high watermark must be larger than the low watermark!");
            ++argv;
            argc -= 2;
        } else
            Error("unknown flag: " + std::string(*argv));
    }

    const std::string marc_input_filename(*argv++);
    const std::string marc_output_filename(*argv++);
    if (marc_input_filename == marc_output_filename)
        Error("input filename must not equal output filename!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    const std::string db_filename(*argv);
    kyotocabinet::HashDB db;
    if (not db.open(db_filename, kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE))
        Error("Failed to create the key/valuedatabase \"" + db_filename + "\" ("
              + std::string(db.error().message()) + ")!");
    db.close();

    const std::string UPDATE_DB_LOG_DIR_PATH(
        "/var/log/" + std::string(FileUtil::Exists("/var/log/krimdok") ? "krimdok" : "ixtheo")
        + "/update_full_text_db");
    if (not FileUtil::MakeDirectory(UPDATE_DB_LOG_DIR_PATH, /* recursive = */ true))
        Error("failed to create directory: " + UPDATE_DB_LOG_DIR_PATH);

    try {
        ProcessRecords(max_record_count, skip_count, marc_reader.get(), marc_writer.get(), db_filename,
                       process_count_low_watermark, process_count_high_watermark);
    } catch (const std::exception &e) {
        Error("Caught exception: " + std::string(e.what()));
    }
}
<commit_msg>We now also cache text for records that have no 856$u but have 520$a subfields.<commit_after>/** \brief Utility for augmenting MARC records with links to a local full-text database.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015-2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <stdexcept>
#include <vector>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <libgen.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <kchashdb.h>
#include "Downloader.h"
#include "ExecUtil.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcUtil.h"
#include "MarcWriter.h"
#include "RegexMatcher.h"
#include "Semaphore.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "TimeLimit.h"
#include "util.h"

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "Usage: " << ::progname
              << "[--max-record-count count] [--skip-count count] [--process-count-low-and-high-watermarks low:high] "
              << "marc_input marc_output full_text_db\n"
              << "       --process-count-low-and-high-watermarks sets the maximum and minimum number of spawned\n"
              << "       child processes.  When we hit the high water mark we wait for child processes to exit\n"
              << "       until we reach the low watermark.\n\n";

    std::exit(EXIT_FAILURE);
}

// Checks subfields "3" and "z" to see if they start w/ "Rezension".
bool IsProbablyAReview(const Subfields &subfields) {
    const auto &_3_begin_end(subfields.getIterators('3'));
    if (_3_begin_end.first != _3_begin_end.second) {
        if (StringUtil::StartsWith(_3_begin_end.first->value_, "Rezension"))
            return true;
    } else {
        const auto &z_begin_end(subfields.getIterators('z'));
        if (z_begin_end.first != z_begin_end.second
            and StringUtil::StartsWith(z_begin_end.first->value_, "Rezension"))
            return true;
    }

    return false;
}

bool FoundAtLeastOneNonReviewLink(const MarcRecord &record) {
    for (size_t _856_index(record.getFieldIndex("856")); record.getTag(_856_index) == "856"; ++_856_index) {
        const Subfields subfields(record.getSubfields(_856_index));
        if (subfields.getIndicator1() == '7' or not subfields.hasSubfield('u'))
            continue;

        if (not IsProbablyAReview(subfields))
            return true;
    }

    return false;
}

// Returns the number of child processes that returned a non-zero exit code.
unsigned CleanUpZombies(const unsigned zombies_to_collect) {
    unsigned child_reported_failure_count(0);
    for (unsigned zombie_no(0); zombie_no < zombies_to_collect; ++zombie_no) {
        int exit_code;
        ::wait(&exit_code);
        if (exit_code != 0)
            ++child_reported_failure_count;
    }

    return child_reported_failure_count;
}

void ProcessRecords(const unsigned max_record_count, const unsigned skip_count, MarcReader * const marc_reader,
                    MarcWriter * const marc_writer, const std::string &db_filename,
                    const unsigned process_count_low_watermark, const unsigned process_count_high_watermark)
{
    Semaphore semaphore("/full_text_cached_counter", Semaphore::CREATE);
    std::string err_msg;
    unsigned total_record_count(0), spawn_count(0), active_child_count(0), child_reported_failure_count(0);

    const std::string UPDATE_FULL_TEXT_DB_PATH("/usr/local/bin/update_full_text_db");

    std::cout << "Skip " << skip_count << " records\n";
    off_t record_start = marc_reader->tell();
    while (MarcRecord record = marc_reader->read()) {
        if (total_record_count == max_record_count)
            break;
        ++total_record_count;
        if (total_record_count <= skip_count) {
            record_start = marc_reader->tell();
            continue;
        }

        const bool insert_in_cache(FoundAtLeastOneNonReviewLink(record)
                                   or (not MarcUtil::HasTagAndSubfield(record, "856", 'u')
                                       and MarcUtil::HasTagAndSubfield(record, "520", 'a')));
        if (not insert_in_cache) {
            MarcUtil::FileLockedComposeAndWriteRecord(marc_writer, &record);
            record_start = marc_reader->tell();
            continue;
        }

        ExecUtil::Spawn(UPDATE_FULL_TEXT_DB_PATH,
                        { std::to_string(record_start), marc_reader->getPath(), marc_writer->getFile().getPath(),
                          db_filename });
        ++active_child_count;
        ++spawn_count;

        if (active_child_count > process_count_high_watermark) {
            child_reported_failure_count += CleanUpZombies(active_child_count - process_count_low_watermark);
            active_child_count = process_count_low_watermark;
        }
        record_start = marc_reader->tell();
    }

    // Wait for stragglers:
    child_reported_failure_count += CleanUpZombies(active_child_count);

    if (not err_msg.empty())
        Error(err_msg);
    std::cerr << "Read " << total_record_count << " records.\n";
    std::cerr << "Spawned " << spawn_count << " subprocesses.\n";
    std::cerr << semaphore.getValue()
              << " documents were not downloaded because their cached values had not yet expired.\n";
    std::cerr << child_reported_failure_count << " children reported a failure!\n";
}

constexpr unsigned PROCESS_COUNT_DEFAULT_HIGH_WATERMARK(10);
constexpr unsigned PROCESS_COUNT_DEFAULT_LOW_WATERMARK(5);

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4 and argc != 6 and argc != 8 and argc != 10)
        Usage();
    ++argv; // skip program name

    // Process optional args:
    unsigned max_record_count(UINT_MAX), skip_count(0);
    unsigned process_count_low_watermark(PROCESS_COUNT_DEFAULT_LOW_WATERMARK),
             process_count_high_watermark(PROCESS_COUNT_DEFAULT_HIGH_WATERMARK);
    while (argc > 4) {
        std::cout << "Arg: " << *argv << "\n";
        if (std::strcmp(*argv, "--max-record-count") == 0) {
            ++argv;
            if (not StringUtil::ToNumber(*argv, &max_record_count) or max_record_count == 0)
                Error("bad value for --max-record-count!");
            ++argv;
            argc -= 2;
        } else if (std::strcmp(*argv, "--skip-count") == 0) {
            ++argv;
            if (not StringUtil::ToNumber(*argv, &skip_count))
                Error("bad value for --skip-count!");
            std::cout << "Should skip " << skip_count << " records\n";
            ++argv;
            argc -= 2;
        } else if (std::strcmp("--process-count-low-and-high-watermarks", *argv) == 0) {
            ++argv;
            char *arg_end(*argv + std::strlen(*argv));
            char * const colon(std::find(*argv, arg_end, ':'));
            if (colon == arg_end)
                Error("bad argument to --process-count-low-and-high-watermarks: colon is missing!");
            *colon = '\0';
            if (not StringUtil::ToNumber(*argv, &process_count_low_watermark)
                or not StringUtil::ToNumber(*argv, &process_count_high_watermark))
                Error("low or high watermark is not an unsigned number!");
            if (process_count_high_watermark > process_count_low_watermark)
                Error("the high watermark must be larger than the low watermark!");
            ++argv;
            argc -= 2;
        } else
            Error("unknown flag: " + std::string(*argv));
    }

    const std::string marc_input_filename(*argv++);
    const std::string marc_output_filename(*argv++);
    if (marc_input_filename == marc_output_filename)
        Error("input filename must not equal output filename!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    const std::string db_filename(*argv);
    kyotocabinet::HashDB db;
    if (not db.open(db_filename, kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE))
        Error("Failed to create the key/valuedatabase \"" + db_filename + "\" ("
              + std::string(db.error().message()) + ")!");
    db.close();

    const std::string UPDATE_DB_LOG_DIR_PATH(
        "/var/log/" + std::string(FileUtil::Exists("/var/log/krimdok") ? "krimdok" : "ixtheo")
        + "/update_full_text_db");
    if (not FileUtil::MakeDirectory(UPDATE_DB_LOG_DIR_PATH, /* recursive = */ true))
        Error("failed to create directory: " + UPDATE_DB_LOG_DIR_PATH);

    try {
        ProcessRecords(max_record_count, skip_count, marc_reader.get(), marc_writer.get(), db_filename,
                       process_count_low_watermark, process_count_high_watermark);
    } catch (const std::exception &e) {
        Error("Caught exception: " + std::string(e.what()));
    }
}
<|endoftext|>