<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/base/processors/imagestackvolumesource.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/layer.h>
#include <inviwo/core/datastructures/image/layerram.h>
#include <inviwo/core/datastructures/image/imageram.h>
#include <inviwo/core/datastructures/volume/volume.h>
#include <inviwo/core/datastructures/volume/volumeram.h>
#include <inviwo/core/datastructures/volume/volumeramprecision.h>
#include <inviwo/core/io/datareaderfactory.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stdextensions.h>
#include <inviwo/core/util/vectoroperations.h>
#include <inviwo/core/io/datareaderexception.h>

namespace inviwo {

namespace {

template <typename Format>
struct FloatOrIntMax32
    : std::integral_constant<bool, Format::numtype == NumericType::Float || Format::compsize <= 4> {
};

}  // namespace

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo ImageStackVolumeSource::processorInfo_{
    "org.inviwo.ImageStackVolumeSource",  // Class identifier
    "Image Stack Volume Source",          // Display name
    "Data Input",                         // Category
    CodeState::Stable,                    // Code state
    "Layer, Image, Volume",               // Tags
};
const ProcessorInfo ImageStackVolumeSource::getProcessorInfo() const { return processorInfo_; }

ImageStackVolumeSource::ImageStackVolumeSource()
    : Processor()
    , outport_("volume")
    , filePattern_("filePattern", "File Pattern", "####.jpeg", "")
    , skipUnsupportedFiles_("skipUnsupportedFiles", "Skip Unsupported Files", false)
    // volume parameters
    , voxelSpacing_("voxelSpacing", "Voxel Spacing", vec3(1.0f), vec3(0.1f), vec3(10.0f),
                    vec3(0.1f))
    , basis_("Basis", "Basis and offset")
    , information_("Information", "Data information") {

    addPort(outport_);
    addProperty(filePattern_);
    addProperty(skipUnsupportedFiles_);
    addProperty(voxelSpacing_);
    addProperty(information_);
    addProperty(basis_);

    validExtensions_ =
        InviwoApplication::getPtr()->getDataReaderFactory()->getExtensionsForType<Layer>();
    filePattern_.onChange([this]() { load(); });
    voxelSpacing_.onChange([this]() {
        // update volume basis and offset
        updateVolumeBasis();
        invalidate(InvalidationLevel::InvalidOutput);
    });
    filePattern_.onChange([&]() { isReady_.update(); });
    isReady_.setUpdate([this]() { return !filePattern_.getFileList().empty(); });
}

void ImageStackVolumeSource::process() {
    if (isDeserializing_) return;

    if (dirty_) {
        load();
        dirty_ = false;
    }

    if (volume_) {
        basis_.updateEntity(*volume_);
        information_.updateVolume(*volume_);
    }
}

bool ImageStackVolumeSource::isValidImageFile(std::string fileName) {
    std::string fileExtension = toLower(filesystem::getFileExtension(fileName));
    return util::contains_if(validExtensions_,
                             [&](const FileExtension& e) { return e.extension_ == fileExtension; });
}

void ImageStackVolumeSource::load() { load(false); }

void ImageStackVolumeSource::load(bool deserialized) {
    if (isDeserializing_) return;

    std::vector<std::string> filesInDirectory = filePattern_.getFileList();
    if (filesInDirectory.empty()) return;

    std::vector<std::string> fileNames;
    for (size_t i = 0; i < filesInDirectory.size(); i++) {
        if (isValidImageFile(filesInDirectory[i])) {
            fileNames.push_back(filesInDirectory[i]);
        }
    }
    if (!fileNames.size()) {
        LogWarn("No images found in '" << filePattern_.getFilePatternPath() << "'");
        return;
    }

    using ReaderMap = std::map<std::string, std::unique_ptr<DataReaderType<Layer>>>;
    ReaderMap readerMap;

    size_t numSlices = 0;
    // determine number of slices and file readers for all images
    for (auto file : fileNames) {
        std::string fileExtension = toLower(filesystem::getFileExtension(file));
        if (readerMap.find(fileExtension) != readerMap.end()) {
            // reader already exists for this format
            ++numSlices;
            continue;
        }
        auto reader = InviwoApplication::getPtr()
                          ->getDataReaderFactory()
                          ->getReaderForTypeAndExtension<Layer>(fileExtension);
        if (!reader && skipUnsupportedFiles_.get()) {
            // ignore file entirely
            continue;
        }
        readerMap[fileExtension] = std::move(reader);

        ++numSlices;
    }

    if (readerMap.empty()) {
        // could not find any suitable data reader for the images
        LogWarn("Image formats not supported");
        return;
    }

    auto getReaderIt = [&readerMap](const std::string& filename) {
        return readerMap.find(toLower(filesystem::getFileExtension(filename)));
    };

    // use first image to determine the volume size
    size2_t layerDims{0u, 0u};
    //    const DataFormatBase* format = nullptr;
    try {
        size_t slice = 0;

        // skip slices with unsupported image formats
        while (getReaderIt(fileNames[slice]) == readerMap.end()) {
            ++slice;
        }

        auto imgLayer = getReaderIt(fileNames[slice])->second->readData(fileNames[slice]);
        // Call getRepresentation here to force read a ram representation.
        // Otherwise the default image size, i.e. 256x265, will be reported
        // until you do the conversion since the LayerDisk does not provide any metadata.
        auto layerRAM = imgLayer->getRepresentation<LayerRAM>();
        layerDims = imgLayer->getDimensions();

        if ((layerDims.x == 0) || (layerDims.y == 0)) {
            LogError("Could not extract valid image dimensions from '" << fileNames[slice] << "'");
            return;
        }

        volume_ = layerRAM->dispatch<std::shared_ptr<Volume>, FloatOrIntMax32>(
            [&](auto baselayerprecision) {
                using ValueType = util::PrecsionValueType<decltype(baselayerprecision)>;
                using PrimitiveType = typename DataFormat<ValueType>::primitive;

                const size3_t volSize(layerDims, numSlices);
                // create matching volume representation
                auto volumeRAM = std::make_shared<VolumeRAMPrecision<ValueType>>(volSize);

                auto volume = std::make_shared<Volume>(volumeRAM);
                volume->dataMap_.dataRange =
                    dvec2{DataFormat<PrimitiveType>::lowest(), DataFormat<PrimitiveType>::max()};
                volume->dataMap_.valueRange =
                    dvec2{DataFormat<PrimitiveType>::lowest(), DataFormat<PrimitiveType>::max()};

                auto volData = volumeRAM->getDataTyped();
                const size_t sliceOffset = glm::compMul(layerDims);
                // initalize volume slices before current one
                std::fill(volData, volData + slice * sliceOffset, ValueType{0});

                // copy first image layer into volume
                auto layerDataBase = baselayerprecision->getDataTyped();
                std::copy(layerDataBase, layerDataBase + sliceOffset,
                          volData + slice * sliceOffset);

                // load remaining slices
                ++slice;
                while (slice < numSlices) {
                    auto it = getReaderIt(fileNames[slice]);
                    if (it == readerMap.end()) {
                        // reader does not exist for this format
                        std::fill(volData + slice * sliceOffset,
                                  volData + (slice + 1) * sliceOffset, ValueType{0});
                        ++slice;
                        continue;
                    }

                    try {
                        auto layer = (*it).second->readData(fileNames[slice]);
                        if (layer->getDimensions() != layerDims) {
                            // rescale layer if necessary
                            layer->setDimensions(layerDims);
                        }
                        layer->getRepresentation<LayerRAM>()->dispatch<void, FloatOrIntMax32>(
                            [&](auto layerpr) {
                                using ValueTypeLayer = util::PrecsionValueType<decltype(layerpr)>;
                                if ((DataFormat<ValueType>::numtype != NumericType::Float) &&
                                    (DataFormat<ValueType>::compsize > 4)) {
                                    throw DataReaderException(
                                        std::string{"Unsupported integer bit depth ("} +
                                        std::to_string(DataFormat<ValueType>::precision()) + ")");
                                }

                                auto layerData = layerpr->getDataTyped();
                                std::transform(
                                    layerData, layerData + sliceOffset,
                                    volData + slice * sliceOffset, [](auto value) {
                                        return util::glm_convert_normalized<typename ValueType>(
                                            value);
                                    });
                            });

                    } catch (DataReaderException const& e) {
                        LogProcessorError("Could not load image: " << fileNames[slice] << ", "
                                                                   << e.getMessage());
                        std::fill(volData + slice * sliceOffset,
                                  volData + (slice + 1) * sliceOffset, ValueType{0});
                    }
                    ++slice;
                }
                return volume;
            });

    } catch (DataReaderException const& e) {
        LogProcessorError("Could not load image: " << fileNames.front() << ", " << e.getMessage());
        return;
    }
    /*
    if ((layerDims.x == 0) || (layerDims.y == 0) || !format) {
        LogError("Invalid layer dimensions/format for volume");
        return;
    }

    // create a volume GL representation
    auto volumeRAM = createVolumeRAM(volSize, format);
    volume_ = std::make_shared<Volume>(volumeRAM);
    volume_->dataMap_.dataRange = dvec2{format->getLowest(), format->getMax()};
    volume_->dataMap_.valueRange = dvec2{format->getLowest(), format->getMax()};

    // set physical size of volume
    updateVolumeBasis(deserialized);

    volumeRAM->dispatch<void, FloatOrIntMax32>([&](auto volumeprecision) {
        using ValueType = util::PrecsionValueType<decltype(volumeprecision)>;
        using PrimitiveType = typename DataFormat<ValueType>::primitive;

        auto volData = volumeprecision->getDataTyped();
        const size_t sliceOffset = glm::compMul(layerDims);

        size_t slice = 0;
        for (auto file : fileNames) {
            // load image into texture
            std::string fileExtension = toLower(filesystem::getFileExtension(file));

            auto it = readerMap.find(fileExtension);
            if (it == readerMap.end()) {
                // reader does not exist for this format
                std::fill(volData + slice * sliceOffset, volData + (slice + 1) * sliceOffset,
                          ValueType{0});
                ++slice;
                continue;
            }

            try {
                auto layer = (*it).second->readData(file);
                if (layer->getDimensions() != layerDims) {
                    // rescale layer if necessary
                    layer->setDimensions(layerDims);
                }
                layer->getRepresentation<LayerRAM>()->dispatch<void, FloatOrIntMax32>(
                    [&](auto layerpr) {
                        auto layerData = layerpr->getDataTyped();
                        std::transform(
                            layerData, layerData + sliceOffset, volData + slice * sliceOffset,
                            [](auto value) {
                                return util::glm_convert_normalized<typename ValueType>(value);
                            });
                    });

            } catch (DataReaderException const& e) {
                LogProcessorError("Could not load image: " << file << ", " << e.getMessage());
                std::fill(volData + slice * sliceOffset, volData + (slice + 1) * sliceOffset,
                          ValueType{0});
            }

            ++slice;
        }
    });
    */

    basis_.updateForNewEntity(*volume_, deserialized);
    information_.updateForNewVolume(*volume_, deserialized);

    outport_.setData(volume_);
}

void ImageStackVolumeSource::deserialize(Deserializer& d) {
    isDeserializing_ = true;
    Processor::deserialize(d);
    isDeserializing_ = false;
    dirty_ = true;
}

void ImageStackVolumeSource::updateVolumeBasis(bool deserialized) {
    if (!volume_) {
        return;
    }
    size3_t layerDims{volume_->getDimensions()};
    vec3 spacing{voxelSpacing_.get()};

    double aspectRatio = static_cast<double>(layerDims.x) / static_cast<double>(layerDims.y);
    // consider voxel spacing
    aspectRatio *= spacing.x / spacing.y;

    vec3 scale{2.0f};
    if (aspectRatio > 1.0) {
        scale.y /= static_cast<float>(aspectRatio);
        scale.z = scale.x / (layerDims.x * spacing.x) * (layerDims.z * spacing.z);
    } else {
        scale.x *= static_cast<float>(aspectRatio);
        scale.z = scale.y / (layerDims.y * spacing.y) * (layerDims.z * spacing.z);
    }

    mat3 basis(glm::scale(scale));
    vec3 offset(-scale);
    offset *= 0.5;
    volume_->setBasis(basis);
    volume_->setOffset(offset);

    basis_.updateForNewEntity(*volume_, deserialized);
}

}  // namespace inviwo
<commit_msg>Base: clang fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/base/processors/imagestackvolumesource.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/layer.h>
#include <inviwo/core/datastructures/image/layerram.h>
#include <inviwo/core/datastructures/image/layerramprecision.h>
#include <inviwo/core/datastructures/image/imageram.h>
#include <inviwo/core/datastructures/volume/volume.h>
#include <inviwo/core/datastructures/volume/volumeram.h>
#include <inviwo/core/datastructures/volume/volumeramprecision.h>
#include <inviwo/core/io/datareaderfactory.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stdextensions.h>
#include <inviwo/core/util/vectoroperations.h>
#include <inviwo/core/io/datareaderexception.h>

namespace inviwo {

namespace {

template <typename Format>
struct FloatOrIntMax32
    : std::integral_constant<bool, Format::numtype == NumericType::Float || Format::compsize <= 4> {
};

}  // namespace

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo ImageStackVolumeSource::processorInfo_{
    "org.inviwo.ImageStackVolumeSource",  // Class identifier
    "Image Stack Volume Source",          // Display name
    "Data Input",                         // Category
    CodeState::Stable,                    // Code state
    "Layer, Image, Volume",               // Tags
};
const ProcessorInfo ImageStackVolumeSource::getProcessorInfo() const { return processorInfo_; }

ImageStackVolumeSource::ImageStackVolumeSource()
    : Processor()
    , outport_("volume")
    , filePattern_("filePattern", "File Pattern", "####.jpeg", "")
    , skipUnsupportedFiles_("skipUnsupportedFiles", "Skip Unsupported Files", false)
    // volume parameters
    , voxelSpacing_("voxelSpacing", "Voxel Spacing", vec3(1.0f), vec3(0.1f), vec3(10.0f),
                    vec3(0.1f))
    , basis_("Basis", "Basis and offset")
    , information_("Information", "Data information") {

    addPort(outport_);
    addProperty(filePattern_);
    addProperty(skipUnsupportedFiles_);
    addProperty(voxelSpacing_);
    addProperty(information_);
    addProperty(basis_);

    validExtensions_ =
        InviwoApplication::getPtr()->getDataReaderFactory()->getExtensionsForType<Layer>();
    filePattern_.onChange([this]() { load(); });
    voxelSpacing_.onChange([this]() {
        // update volume basis and offset
        updateVolumeBasis();
        invalidate(InvalidationLevel::InvalidOutput);
    });
    filePattern_.onChange([&]() { isReady_.update(); });
    isReady_.setUpdate([this]() { return !filePattern_.getFileList().empty(); });
}

void ImageStackVolumeSource::process() {
    if (isDeserializing_) return;

    if (dirty_) {
        load();
        dirty_ = false;
    }

    if (volume_) {
        basis_.updateEntity(*volume_);
        information_.updateVolume(*volume_);
    }
}

bool ImageStackVolumeSource::isValidImageFile(std::string fileName) {
    std::string fileExtension = toLower(filesystem::getFileExtension(fileName));
    return util::contains_if(validExtensions_,
                             [&](const FileExtension& e) { return e.extension_ == fileExtension; });
}

void ImageStackVolumeSource::load() { load(false); }

void ImageStackVolumeSource::load(bool deserialized) {
    if (isDeserializing_) return;

    std::vector<std::string> filesInDirectory = filePattern_.getFileList();
    if (filesInDirectory.empty()) return;

    std::vector<std::string> fileNames;
    for (size_t i = 0; i < filesInDirectory.size(); i++) {
        if (isValidImageFile(filesInDirectory[i])) {
            fileNames.push_back(filesInDirectory[i]);
        }
    }
    if (!fileNames.size()) {
        LogWarn("No images found in '" << filePattern_.getFilePatternPath() << "'");
        return;
    }

    using ReaderMap = std::map<std::string, std::unique_ptr<DataReaderType<Layer>>>;
    ReaderMap readerMap;

    size_t numSlices = 0;
    // determine number of slices and file readers for all images
    for (auto file : fileNames) {
        std::string fileExtension = toLower(filesystem::getFileExtension(file));
        if (readerMap.find(fileExtension) != readerMap.end()) {
            // reader already exists for this format
            ++numSlices;
            continue;
        }
        auto reader = InviwoApplication::getPtr()
                          ->getDataReaderFactory()
                          ->getReaderForTypeAndExtension<Layer>(fileExtension);
        if (!reader && skipUnsupportedFiles_.get()) {
            // ignore file entirely
            continue;
        }
        readerMap[fileExtension] = std::move(reader);

        ++numSlices;
    }

    if (readerMap.empty()) {
        // could not find any suitable data reader for the images
        LogWarn("Image formats not supported");
        return;
    }

    auto getReaderIt = [&readerMap](const std::string& filename) {
        return readerMap.find(toLower(filesystem::getFileExtension(filename)));
    };

    // use first image to determine the volume size
    size2_t layerDims{0u, 0u};
    //    const DataFormatBase* format = nullptr;
    try {
        size_t slice = 0;

        // skip slices with unsupported image formats
        while (getReaderIt(fileNames[slice]) == readerMap.end()) {
            ++slice;
        }

        auto imgLayer = getReaderIt(fileNames[slice])->second->readData(fileNames[slice]);
        // Call getRepresentation here to force read a ram representation.
        // Otherwise the default image size, i.e. 256x265, will be reported
        // until you do the conversion since the LayerDisk does not provide any metadata.
        auto layerRAM = imgLayer->getRepresentation<LayerRAM>();
        layerDims = imgLayer->getDimensions();

        if ((layerDims.x == 0) || (layerDims.y == 0)) {
            LogError("Could not extract valid image dimensions from '" << fileNames[slice] << "'");
            return;
        }

        volume_ = layerRAM->dispatch<std::shared_ptr<Volume>, FloatOrIntMax32>(
            [&](auto baselayerprecision) {
                using ValueType = util::PrecsionValueType<decltype(baselayerprecision)>;
                using PrimitiveType = typename DataFormat<ValueType>::primitive;

                const size3_t volSize(layerDims, numSlices);
                // create matching volume representation
                auto volumeRAM = std::make_shared<VolumeRAMPrecision<ValueType>>(volSize);

                auto volume = std::make_shared<Volume>(volumeRAM);
                volume->dataMap_.dataRange =
                    dvec2{DataFormat<PrimitiveType>::lowest(), DataFormat<PrimitiveType>::max()};
                volume->dataMap_.valueRange =
                    dvec2{DataFormat<PrimitiveType>::lowest(), DataFormat<PrimitiveType>::max()};

                auto volData = volumeRAM->getDataTyped();
                const size_t sliceOffset = glm::compMul(layerDims);
                // initalize volume slices before current one
                std::fill(volData, volData + slice * sliceOffset, ValueType{0});

                // copy first image layer into volume
                auto layerDataBase = baselayerprecision->getDataTyped();
                std::copy(layerDataBase, layerDataBase + sliceOffset,
                          volData + slice * sliceOffset);

                // load remaining slices
                ++slice;
                while (slice < numSlices) {
                    auto it = getReaderIt(fileNames[slice]);
                    if (it == readerMap.end()) {
                        // reader does not exist for this format
                        std::fill(volData + slice * sliceOffset,
                                  volData + (slice + 1) * sliceOffset, ValueType{0});
                        ++slice;
                        continue;
                    }

                    try {
                        auto layer = (*it).second->readData(fileNames[slice]);
                        if (layer->getDimensions() != layerDims) {
                            // rescale layer if necessary
                            layer->setDimensions(layerDims);
                        }
                        layer->getRepresentation<LayerRAM>()->dispatch<void, FloatOrIntMax32>(
                            [&](auto layerpr) {
                                using ValueTypeLayer = util::PrecsionValueType<decltype(layerpr)>;
                                if ((DataFormat<ValueType>::numtype != NumericType::Float) &&
                                    (DataFormat<ValueType>::compsize > 4)) {
                                    throw DataReaderException(
                                        std::string{"Unsupported integer bit depth ("} +
                                        std::to_string(DataFormat<ValueType>::precision()) + ")");
                                }

                                auto layerData = layerpr->getDataTyped();
                                std::transform(
                                    layerData, layerData + sliceOffset,
                                    volData + slice * sliceOffset, [](auto value) {
                                        return util::glm_convert_normalized<ValueType>(value);
                                    });
                            });

                    } catch (DataReaderException const& e) {
                        LogProcessorError("Could not load image: " << fileNames[slice] << ", "
                                                                   << e.getMessage());
                        std::fill(volData + slice * sliceOffset,
                                  volData + (slice + 1) * sliceOffset, ValueType{0});
                    }
                    ++slice;
                }
                return volume;
            });

    } catch (DataReaderException const& e) {
        LogProcessorError("Could not load image: " << fileNames.front() << ", " << e.getMessage());
        return;
    }
    /*
    if ((layerDims.x == 0) || (layerDims.y == 0) || !format) {
        LogError("Invalid layer dimensions/format for volume");
        return;
    }

    // create a volume GL representation
    auto volumeRAM = createVolumeRAM(volSize, format);
    volume_ = std::make_shared<Volume>(volumeRAM);
    volume_->dataMap_.dataRange = dvec2{format->getLowest(), format->getMax()};
    volume_->dataMap_.valueRange = dvec2{format->getLowest(), format->getMax()};

    // set physical size of volume
    updateVolumeBasis(deserialized);

    volumeRAM->dispatch<void, FloatOrIntMax32>([&](auto volumeprecision) {
        using ValueType = util::PrecsionValueType<decltype(volumeprecision)>;
        using PrimitiveType = typename DataFormat<ValueType>::primitive;

        auto volData = volumeprecision->getDataTyped();
        const size_t sliceOffset = glm::compMul(layerDims);

        size_t slice = 0;
        for (auto file : fileNames) {
            // load image into texture
            std::string fileExtension = toLower(filesystem::getFileExtension(file));

            auto it = readerMap.find(fileExtension);
            if (it == readerMap.end()) {
                // reader does not exist for this format
                std::fill(volData + slice * sliceOffset, volData + (slice + 1) * sliceOffset,
                          ValueType{0});
                ++slice;
                continue;
            }

            try {
                auto layer = (*it).second->readData(file);
                if (layer->getDimensions() != layerDims) {
                    // rescale layer if necessary
                    layer->setDimensions(layerDims);
                }
                layer->getRepresentation<LayerRAM>()->dispatch<void, FloatOrIntMax32>(
                    [&](auto layerpr) {
                        auto layerData = layerpr->getDataTyped();
                        std::transform(
                            layerData, layerData + sliceOffset, volData + slice * sliceOffset,
                            [](auto value) {
                                return util::glm_convert_normalized<typename ValueType>(value);
                            });
                    });

            } catch (DataReaderException const& e) {
                LogProcessorError("Could not load image: " << file << ", " << e.getMessage());
                std::fill(volData + slice * sliceOffset, volData + (slice + 1) * sliceOffset,
                          ValueType{0});
            }

            ++slice;
        }
    });
    */

    basis_.updateForNewEntity(*volume_, deserialized);
    information_.updateForNewVolume(*volume_, deserialized);

    outport_.setData(volume_);
}

void ImageStackVolumeSource::deserialize(Deserializer& d) {
    isDeserializing_ = true;
    Processor::deserialize(d);
    isDeserializing_ = false;
    dirty_ = true;
}

void ImageStackVolumeSource::updateVolumeBasis(bool deserialized) {
    if (!volume_) {
        return;
    }
    size3_t layerDims{volume_->getDimensions()};
    vec3 spacing{voxelSpacing_.get()};

    double aspectRatio = static_cast<double>(layerDims.x) / static_cast<double>(layerDims.y);
    // consider voxel spacing
    aspectRatio *= spacing.x / spacing.y;

    vec3 scale{2.0f};
    if (aspectRatio > 1.0) {
        scale.y /= static_cast<float>(aspectRatio);
        scale.z = scale.x / (layerDims.x * spacing.x) * (layerDims.z * spacing.z);
    } else {
        scale.x *= static_cast<float>(aspectRatio);
        scale.z = scale.y / (layerDims.y * spacing.y) * (layerDims.z * spacing.z);
    }

    mat3 basis(glm::scale(scale));
    vec3 offset(-scale);
    offset *= 0.5;
    volume_->setBasis(basis);
    volume_->setOffset(offset);

    basis_.updateForNewEntity(*volume_, deserialized);
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include <assert.h>
#include <string.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
	#define SHUT_RDWR SD_BOTH
#else // WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#include <unordered_map>
#include <set>

#include "connection.h"

#include "utils.h"

class GlobalNetProcess {
public:
	std::mutex fd_map_mutex;
	std::unordered_map<int, Connection*> fd_map;
#ifndef WIN32
	int pipe_write;
#endif

	static void do_net_process(GlobalNetProcess* me) {
		fd_set fd_set_read, fd_set_write;
		struct timeval timeout;

#ifndef WIN32
		int pipefd[2];
		ALWAYS_ASSERT(!pipe(pipefd));
		fcntl(pipefd[1], F_SETFL, fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
		fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
		me->pipe_write = pipefd[1];
#endif

		while (true) {
#ifndef WIN32
			timeout.tv_sec = 86400;
			timeout.tv_usec = 20 * 1000;
#else
			timeout.tv_sec = 0;
			timeout.tv_usec = 1000;
#endif

			FD_ZERO(&fd_set_read); FD_ZERO(&fd_set_write);
#ifndef WIN32
			int max = pipefd[0];
			FD_SET(pipefd[0], &fd_set_read);
#else
			int max = 0;
#endif
			auto now = std::chrono::steady_clock::now();
			{
				std::lock_guard<std::mutex> lock(me->fd_map_mutex);
				for (const auto& e : me->fd_map) {
					ALWAYS_ASSERT(e.first < FD_SETSIZE);
					if (e.second->total_inbound_size < 65536)
						FD_SET(e.first, &fd_set_read);
					if (e.second->total_waiting_size > 0) {
						FD_SET(e.first, &fd_set_write);
						if (now < e.second->earliest_next_write) {
							timeout.tv_sec = 0;
							timeout.tv_usec = std::min((long unsigned)timeout.tv_usec, to_micros_lu(e.second->earliest_next_write - now));
						}
					}
					max = std::max(e.first, max);
				}
			}

			ALWAYS_ASSERT(select(max + 1, &fd_set_read, &fd_set_write, NULL, &timeout) >= 0);

			now = std::chrono::steady_clock::now();
			unsigned char buf[4096];
			{
				std::set<int> remove_set;
				std::lock_guard<std::mutex> lock(me->fd_map_mutex);
				for (const auto& e : me->fd_map) {
					Connection* conn = e.second;

					if (FD_ISSET(e.first, &fd_set_read)) {
						ssize_t count = recv(conn->sock, (char*)buf, 4096, 0);

						std::lock_guard<std::mutex> lock(conn->read_mutex);
						if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
							remove_set.insert(e.first);
							conn->sock_errno = errno;
						} else {
							conn->inbound_queue.emplace_back(new std::vector<unsigned char>(buf, buf + count));
							conn->total_inbound_size += count;
							conn->read_cv.notify_all();
						}
					}
					if (FD_ISSET(e.first, &fd_set_write)) {
						if (now < conn->earliest_next_write)
							continue;
						std::lock_guard<std::mutex> lock(conn->send_mutex);
						if (!conn->secondary_writepos && conn->outbound_primary_queue.size()) {
							auto& msg = conn->outbound_primary_queue.front();
							ssize_t count = send(conn->sock, (char*) &(*msg)[conn->primary_writepos], msg->size() - conn->primary_writepos, MSG_NOSIGNAL);
							if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
								remove_set.insert(e.first);
								conn->sock_errno = errno;
							} else {
								conn->primary_writepos += count;
								if (conn->primary_writepos == msg->size()) {
									conn->primary_writepos = 0;
									conn->total_waiting_size -= msg->size();
									conn->outbound_primary_queue.pop_front();
								}
							}
						} else {
							assert(conn->outbound_secondary_queue.size() && !conn->primary_writepos);
							auto& msg = conn->outbound_secondary_queue.front();
							ssize_t count = send(conn->sock, (char*) &(*msg)[conn->secondary_writepos], msg->size() - conn->secondary_writepos, MSG_NOSIGNAL);
							if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
								remove_set.insert(e.first);
								conn->sock_errno = errno;
							} else {
								conn->secondary_writepos += count;
								if (conn->secondary_writepos == msg->size()) {
									conn->secondary_writepos = 0;
									conn->total_waiting_size -= msg->size();
									conn->outbound_secondary_queue.pop_front();
								}
							}
						}
						if (!conn->total_waiting_size)
							conn->initial_outbound_throttle = false;
						else if (!conn->primary_writepos && !conn->secondary_writepos && conn->initial_outbound_throttle)
							conn->earliest_next_write = std::chrono::steady_clock::now() + std::chrono::milliseconds(20); // Limit outbound to avg 5Mbps worst-case
					}
				}

				for (const int fd : remove_set) {
					Connection* conn = me->fd_map[fd];
					std::lock_guard<std::mutex> lock(conn->read_mutex);
					conn->inbound_queue.emplace_back((std::nullptr_t)NULL);
					conn->read_cv.notify_all();
					conn->disconnectFlags |= DISCONNECT_GLOBAL_THREAD_DONE;
					me->fd_map.erase(fd);
				}
			}
#ifndef WIN32
			if (FD_ISSET(pipefd[0], &fd_set_read))
				while (read(pipefd[0], buf, 4096) > 0);
#endif
		}
	}

	GlobalNetProcess() {
		std::thread(do_net_process, this).detach();
	}
};
static GlobalNetProcess processor;

Connection::~Connection() {
	assert(disconnectFlags & DISCONNECT_COMPLETE);
	user_thread->join();
	close(sock);
	delete user_thread;
}

void Connection::do_send_bytes(const std::shared_ptr<std::vector<unsigned char> >& bytes, int send_mutex_token) {
	if (!send_mutex_token)
		send_mutex.lock();
	else
		ALWAYS_ASSERT(send_mutex_token == outside_send_mutex_token);

	if (initial_outbound_throttle && send_mutex_token)
		initial_outbound_bytes += bytes->size();

	if (total_waiting_size - (initial_outbound_throttle ? initial_outbound_bytes : 0) > 4000000) {
		if (!send_mutex_token)
			send_mutex.unlock();
		return disconnect_from_outside("total_waiting_size blew up :(");
	}

	outbound_primary_queue.push_back(bytes);
	total_waiting_size += bytes->size();
#ifndef WIN32
	if (total_waiting_size > (ssize_t)bytes->size())
		write(processor.pipe_write, "1", 1);
#endif

	if (!send_mutex_token)
		send_mutex.unlock();
}

void Connection::maybe_send_bytes(const std::shared_ptr<std::vector<unsigned char> >& bytes, int send_mutex_token) {
	if (!send_mutex_token) {
		if (!send_mutex.try_lock())
			return;
	} else
		ALWAYS_ASSERT(send_mutex_token == outside_send_mutex_token);

	if (total_waiting_size - (initial_outbound_throttle ? initial_outbound_bytes : 0) > 4000000) {
		if (!send_mutex_token)
			send_mutex.unlock();
		return disconnect_from_outside("total_waiting_size blew up :(");
	}

	outbound_secondary_queue.push_back(bytes);
	total_waiting_size += bytes->size();
#ifndef WIN32
	if (total_waiting_size > (ssize_t)bytes->size())
		write(processor.pipe_write, "1", 1);
#endif

	if (!send_mutex_token)
		send_mutex.unlock();
}

void Connection::disconnect_from_outside(const char* reason) {
	if (disconnectFlags.fetch_or(DISCONNECT_PRINT_AND_CLOSE) & DISCONNECT_PRINT_AND_CLOSE)
		return;

	printf("%s Disconnect: %s (%s)\n", host.c_str(), reason, strerror(errno));
	shutdown(sock, SHUT_RDWR);
}

void Connection::disconnect(const char* reason) {
	if (disconnectFlags.fetch_or(DISCONNECT_STARTED) & DISCONNECT_STARTED)
		return;

	if (!(disconnectFlags.fetch_or(DISCONNECT_PRINT_AND_CLOSE) & DISCONNECT_PRINT_AND_CLOSE)) {
		printf("%s Disconnect: %s (%s)\n", host.c_str(), reason, strerror(sock_errno));
		shutdown(sock, SHUT_RDWR);
	}

	assert(std::this_thread::get_id() == user_thread->get_id());

	std::unique_lock<std::mutex> lock(read_mutex);
	while (!(disconnectFlags & DISCONNECT_GLOBAL_THREAD_DONE))
		read_cv.wait(lock);

	outbound_secondary_queue.clear();
	outbound_primary_queue.clear();
	inbound_queue.clear();

	disconnectFlags |= DISCONNECT_COMPLETE;

	if (on_disconnect)
		std::thread(on_disconnect).detach();
}

void Connection::do_setup_and_read(Connection* me) {
	#ifdef WIN32
		unsigned long nonblocking = 1;
		ioctlsocket(me->sock, FIONBIO, &nonblocking);
	#else
		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) | O_NONBLOCK);
	#endif

	#ifdef X86_BSD
		int nosigpipe = 1;
		setsockopt(me->sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
	#endif

	int nodelay = 1;
	setsockopt(me->sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

	if (errno) {
		me->disconnectFlags |= DISCONNECT_GLOBAL_THREAD_DONE;
		return me->disconnect("error during connect");
	}

	{
		std::lock_guard<std::mutex> lock(processor.fd_map_mutex);
		processor.fd_map[me->sock] = me;
#ifndef WIN32
		write(processor.pipe_write, "1", 1);
#endif
	}

	me->net_process([&](const char* reason) { me->disconnect(reason); });
}

ssize_t Connection::read_all(char *buf, size_t nbyte) {
	size_t total = 0;
	while (total < nbyte) {
		std::unique_lock<std::mutex> lock(read_mutex);
		while (!inbound_queue.size())
			read_cv.wait(lock);

		if (!inbound_queue.front())
			return -1;

		size_t readamt = std::min(nbyte - total, inbound_queue.front()->size() - readpos);
		memcpy(buf + total, &(*inbound_queue.front())[readpos], readamt);
		if (readpos + readamt == inbound_queue.front()->size()) {
#ifndef WIN32
			int32_t old_size = total_inbound_size;
#endif
			total_inbound_size -= inbound_queue.front()->size();
#ifndef WIN32
			// If the old size is >= 64k, we may need to wakeup the select thread to get it to read more
			if (old_size >= 65536)
				write(processor.pipe_write, "1", 1);
#endif

			readpos = 0;
			inbound_queue.pop_front();
		} else
			readpos += readamt;
		total += readamt;
	}
	assert(total == nbyte);
	return nbyte;
}

void OutboundPersistentConnection::reconnect(std::string disconnectReason) {
	OutboundConnection* old = (OutboundConnection*) connection.fetch_and(0);
	if (old)
		old->disconnect_from_outside(disconnectReason.c_str());

	on_disconnect();

	std::this_thread::sleep_for(std::chrono::seconds(1));
	while (old && !(old->getDisconnectFlags() & DISCONNECT_COMPLETE)) {
		printf("Disconnect of outbound connection still not complete (status is %d)\n", old->getDisconnectFlags());
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}

	std::thread(do_connect, this).detach();
	delete old;
}

void OutboundPersistentConnection::do_connect(OutboundPersistentConnection* me) {
	int sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock <= 0)
		return me->reconnect("unable to create socket");

	sockaddr_in6 addr;
	if (!lookup_address(me->serverHost.c_str(), &addr)) {
		close(sock);
		return me->reconnect("unable to lookup host");
	}

	int v6only = 0;
	setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

	addr.sin6_port = htons(me->serverPort);
	if (connect(sock, (struct sockaddr*)&addr, sizeof(addr))) {
		close(sock);
		return me->reconnect("failed to connect()");
	}

	OutboundConnection* new_conn = new OutboundConnection(sock, me);
#ifndef NDEBUG
	unsigned long old_val =
#endif
		me->connection.exchange((unsigned long)new_conn);
	assert(old_val == 0);
	new_conn->construction_done();
}
<commit_msg>Fix CPU usage bug on initial_outbound_throttle<commit_after>#include <assert.h>
#include <string.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
	#define SHUT_RDWR SD_BOTH
#else // WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#include <unordered_map>
#include <set>

#include "connection.h"

#include "utils.h"

class GlobalNetProcess {
public:
	std::mutex fd_map_mutex;
	std::unordered_map<int, Connection*> fd_map;
#ifndef WIN32
	int pipe_write;
#endif

	static void do_net_process(GlobalNetProcess* me) {
		fd_set fd_set_read, fd_set_write;
		struct timeval timeout;

#ifndef WIN32
		int pipefd[2];
		ALWAYS_ASSERT(!pipe(pipefd));
		fcntl(pipefd[1], F_SETFL, fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
		fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
		me->pipe_write = pipefd[1];
#endif

		while (true) {
#ifndef WIN32
			timeout.tv_sec = 86400;
			timeout.tv_usec = 20 * 1000;
#else
			timeout.tv_sec = 0;
			timeout.tv_usec = 1000;
#endif

			FD_ZERO(&fd_set_read); FD_ZERO(&fd_set_write);
#ifndef WIN32
			int max = pipefd[0];
			FD_SET(pipefd[0], &fd_set_read);
#else
			int max = 0;
#endif
			auto now = std::chrono::steady_clock::now();
			{
				std::lock_guard<std::mutex> lock(me->fd_map_mutex);
				for (const auto& e : me->fd_map) {
					ALWAYS_ASSERT(e.first < FD_SETSIZE);
					if (e.second->total_inbound_size < 65536)
						FD_SET(e.first, &fd_set_read);
					if (e.second->total_waiting_size > 0) {
						if (now < e.second->earliest_next_write) {
							timeout.tv_sec = 0;
							timeout.tv_usec = std::min((long unsigned)timeout.tv_usec, to_micros_lu(e.second->earliest_next_write - now));
						} else
							FD_SET(e.first, &fd_set_write);
					}
					max = std::max(e.first, max);
				}
			}

			ALWAYS_ASSERT(select(max + 1, &fd_set_read, &fd_set_write, NULL, &timeout) >= 0);

			now = std::chrono::steady_clock::now();
			unsigned char buf[4096];
			{
				std::set<int> remove_set;
				std::lock_guard<std::mutex> lock(me->fd_map_mutex);
				for (const auto& e : me->fd_map) {
					Connection* conn = e.second;

					if (FD_ISSET(e.first, &fd_set_read)) {
						ssize_t count = recv(conn->sock, (char*)buf, 4096, 0);

						std::lock_guard<std::mutex> lock(conn->read_mutex);
						if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
							remove_set.insert(e.first);
							conn->sock_errno = errno;
						} else {
							conn->inbound_queue.emplace_back(new std::vector<unsigned char>(buf, buf + count));
							conn->total_inbound_size += count;
							conn->read_cv.notify_all();
						}
					}
					if (FD_ISSET(e.first, &fd_set_write)) {
						if (now < conn->earliest_next_write)
							continue;
						std::lock_guard<std::mutex> lock(conn->send_mutex);
						if (!conn->secondary_writepos && conn->outbound_primary_queue.size()) {
							auto& msg = conn->outbound_primary_queue.front();
							ssize_t count = send(conn->sock, (char*) &(*msg)[conn->primary_writepos], msg->size() - conn->primary_writepos, MSG_NOSIGNAL);
							if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
								remove_set.insert(e.first);
								conn->sock_errno = errno;
							} else {
								conn->primary_writepos += count;
								if (conn->primary_writepos == msg->size()) {
									conn->primary_writepos = 0;
									conn->total_waiting_size -= msg->size();
									conn->outbound_primary_queue.pop_front();
								}
							}
						} else {
							assert(conn->outbound_secondary_queue.size() && !conn->primary_writepos);
							auto& msg = conn->outbound_secondary_queue.front();
							ssize_t count = send(conn->sock, (char*) &(*msg)[conn->secondary_writepos], msg->size() - conn->secondary_writepos, MSG_NOSIGNAL);
							if (count <= 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
								remove_set.insert(e.first);
								conn->sock_errno = errno;
							} else {
								conn->secondary_writepos += count;
								if (conn->secondary_writepos == msg->size()) {
									conn->secondary_writepos = 0;
									conn->total_waiting_size -= msg->size();
									conn->outbound_secondary_queue.pop_front();
								}
							}
						}
						if (!conn->total_waiting_size)
							conn->initial_outbound_throttle = false;
						else if (!conn->primary_writepos && !conn->secondary_writepos && conn->initial_outbound_throttle)
							conn->earliest_next_write = std::chrono::steady_clock::now() + std::chrono::milliseconds(20); // Limit outbound to avg 5Mbps worst-case
					}
				}

				for (const int fd : remove_set) {
					Connection* conn = me->fd_map[fd];
					std::lock_guard<std::mutex> lock(conn->read_mutex);
					conn->inbound_queue.emplace_back((std::nullptr_t)NULL);
					conn->read_cv.notify_all();
					conn->disconnectFlags |= DISCONNECT_GLOBAL_THREAD_DONE;
					me->fd_map.erase(fd);
				}
			}
#ifndef WIN32
			if (FD_ISSET(pipefd[0], &fd_set_read))
				while (read(pipefd[0], buf, 4096) > 0);
#endif
		}
	}

	GlobalNetProcess() {
		std::thread(do_net_process, this).detach();
	}
};
static GlobalNetProcess processor;

Connection::~Connection() {
	assert(disconnectFlags & DISCONNECT_COMPLETE);
	user_thread->join();
	close(sock);
	delete user_thread;
}

void Connection::do_send_bytes(const std::shared_ptr<std::vector<unsigned char> >& bytes, int send_mutex_token) {
	if (!send_mutex_token)
		send_mutex.lock();
	else
		ALWAYS_ASSERT(send_mutex_token == outside_send_mutex_token);

	if (initial_outbound_throttle && send_mutex_token)
		initial_outbound_bytes += bytes->size();

	if (total_waiting_size - (initial_outbound_throttle ? initial_outbound_bytes : 0) > 4000000) {
		if (!send_mutex_token)
			send_mutex.unlock();
		return disconnect_from_outside("total_waiting_size blew up :(");
	}

	outbound_primary_queue.push_back(bytes);
	total_waiting_size += bytes->size();
#ifndef WIN32
	if (total_waiting_size > (ssize_t)bytes->size())
		write(processor.pipe_write, "1", 1);
#endif

	if (!send_mutex_token)
		send_mutex.unlock();
}

void Connection::maybe_send_bytes(const std::shared_ptr<std::vector<unsigned char> >& bytes, int send_mutex_token) {
	if (!send_mutex_token) {
		if (!send_mutex.try_lock())
			return;
	} else
		ALWAYS_ASSERT(send_mutex_token == outside_send_mutex_token);

	if (total_waiting_size - (initial_outbound_throttle ? initial_outbound_bytes : 0) > 4000000) {
		if (!send_mutex_token)
			send_mutex.unlock();
		return disconnect_from_outside("total_waiting_size blew up :(");
	}

	outbound_secondary_queue.push_back(bytes);
	total_waiting_size += bytes->size();
#ifndef WIN32
	if (total_waiting_size > (ssize_t)bytes->size())
		write(processor.pipe_write, "1", 1);
#endif

	if (!send_mutex_token)
		send_mutex.unlock();
}

void Connection::disconnect_from_outside(const char* reason) {
	if (disconnectFlags.fetch_or(DISCONNECT_PRINT_AND_CLOSE) & DISCONNECT_PRINT_AND_CLOSE)
		return;

	printf("%s Disconnect: %s (%s)\n", host.c_str(), reason, strerror(errno));
	shutdown(sock, SHUT_RDWR);
}

void Connection::disconnect(const char* reason) {
	if (disconnectFlags.fetch_or(DISCONNECT_STARTED) & DISCONNECT_STARTED)
		return;

	if (!(disconnectFlags.fetch_or(DISCONNECT_PRINT_AND_CLOSE) & DISCONNECT_PRINT_AND_CLOSE)) {
		printf("%s Disconnect: %s (%s)\n", host.c_str(), reason, strerror(sock_errno));
		shutdown(sock, SHUT_RDWR);
	}

	assert(std::this_thread::get_id() == user_thread->get_id());

	std::unique_lock<std::mutex> lock(read_mutex);
	while (!(disconnectFlags & DISCONNECT_GLOBAL_THREAD_DONE))
		read_cv.wait(lock);

	outbound_secondary_queue.clear();
	outbound_primary_queue.clear();
	inbound_queue.clear();

	disconnectFlags |= DISCONNECT_COMPLETE;

	if (on_disconnect)
		std::thread(on_disconnect).detach();
}

void Connection::do_setup_and_read(Connection* me) {
	#ifdef WIN32
		unsigned long nonblocking = 1;
		ioctlsocket(me->sock, FIONBIO, &nonblocking);
	#else
		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) | O_NONBLOCK);
	#endif

	#ifdef X86_BSD
		int nosigpipe = 1;
		setsockopt(me->sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
	#endif

	int nodelay = 1;
	setsockopt(me->sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

	if (errno) {
		me->disconnectFlags |= DISCONNECT_GLOBAL_THREAD_DONE;
		return me->disconnect("error during connect");
	}

	{
		std::lock_guard<std::mutex> lock(processor.fd_map_mutex);
		processor.fd_map[me->sock] = me;
#ifndef WIN32
		write(processor.pipe_write, "1", 1);
#endif
	}

	me->net_process([&](const char* reason) { me->disconnect(reason); });
}

ssize_t Connection::read_all(char *buf, size_t nbyte) {
	size_t total = 0;
	while (total < nbyte) {
		std::unique_lock<std::mutex> lock(read_mutex);
		while (!inbound_queue.size())
			read_cv.wait(lock);

		if (!inbound_queue.front())
			return -1;

		size_t readamt = std::min(nbyte - total, inbound_queue.front()->size() - readpos);
		memcpy(buf + total, &(*inbound_queue.front())[readpos], readamt);
		if (readpos + readamt == inbound_queue.front()->size()) {
#ifndef WIN32
			int32_t old_size = total_inbound_size;
#endif
			total_inbound_size -= inbound_queue.front()->size();
#ifndef WIN32
			// If the old size is >= 64k, we may need to wakeup the select thread to get it to read more
			if (old_size >= 65536)
				write(processor.pipe_write, "1", 1);
#endif

			readpos = 0;
			inbound_queue.pop_front();
		} else
			readpos += readamt;
		total += readamt;
	}
	assert(total == nbyte);
	return nbyte;
}

void OutboundPersistentConnection::reconnect(std::string disconnectReason) {
	OutboundConnection* old = (OutboundConnection*) connection.fetch_and(0);
	if (old)
		old->disconnect_from_outside(disconnectReason.c_str());

	on_disconnect();

	std::this_thread::sleep_for(std::chrono::seconds(1));
	while (old && !(old->getDisconnectFlags() & DISCONNECT_COMPLETE)) {
		printf("Disconnect of outbound connection still not complete (status is %d)\n", old->getDisconnectFlags());
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}

	std::thread(do_connect, this).detach();
	delete old;
}

void OutboundPersistentConnection::do_connect(OutboundPersistentConnection* me) {
	int sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock <= 0)
		return me->reconnect("unable to create socket");

	sockaddr_in6 addr;
	if (!lookup_address(me->serverHost.c_str(), &addr)) {
		close(sock);
		return me->reconnect("unable to lookup host");
	}

	int v6only = 0;
	setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

	addr.sin6_port = htons(me->serverPort);
	if (connect(sock, (struct sockaddr*)&addr, sizeof(addr))) {
		close(sock);
		return me->reconnect("failed to connect()");
	}

	OutboundConnection* new_conn = new OutboundConnection(sock, me);
#ifndef NDEBUG
	unsigned long old_val =
#endif
		me->connection.exchange((unsigned long)new_conn);
	assert(old_val == 0);
	new_conn->construction_done();
}
<|endoftext|>


<commit_before>#include <common.h>

#define TITLE	Quest(
#define DESC	,
#define REWARD	,(struct item_t){
#define x		,
#define END		}),

const Quest QuestList[TOTAL_QUESTS]={
//	Quest("Test","A test quest",(struct item_t){1,TEST_ITEM}),

// Get quest list
#include "../config/quest_list.txt"

};

Quest::Quest(const char *t,const char *d,struct item_t r){
	strcpy((title=(char *)malloc(strlen(t))),t);
	strcpy((desc =(char *)malloc(strlen(d))),d);
	memcpy(&reward,&r,sizeof(struct item_t));
}

Quest::~Quest(){
	free(title);
	free(desc);
	memset(&reward,0,sizeof(struct item_t));
}

int QuestHandler::assign(const char *t){
	unsigned char i;
	for(i=0;i<current.size();i++){				// Make sure we don't already have this quest
		if(!strcmp(current[i]->title,t)){
#ifdef DEBUG
			DEBUG_printf("The QuestHandler already has this quest: %s\n",t);
#endif // DEBUG
			return -2;
		}
	}
	for(i=0;i<TOTAL_QUESTS;i++){				// Add the quest (if it really exists)
		if(!strcmp(QuestList[i].title,t)){
			current.push_back(&QuestList[i]);
#ifdef DEBUG
			DEBUG_printf("Added quest %s, now have %u active quests.\n",t,current.size());
#endif // DEBUG
			return current.size();
		}
#ifdef DEBUG
		DEBUG_printf("Finding quest: %s != %s\n",t,QuestList[i].title);
#endif // DEBUG
	}
#ifdef DEBUG
	DEBUG_printf("Quest %s does not exist.\n",t);
#endif // DEBUG
	return -1;
}

int QuestHandler::drop(const char *t){
	unsigned char i;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
			current.erase(current.begin()+i);
			return current.size();
		}
	}
	return -1;
}

int QuestHandler::finish(const char *t,void *completer){
	unsigned char i;
	unsigned int r;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
#ifdef DEBUG
			DEBUG_printf("Completing quest %s.\n",t);
#endif // DEBUG
			((Entity *)completer)->inv->addItem(current[i]->reward.id,current[i]->reward.count);
			current.erase(current.begin()+i);
#ifdef DEBUG
			DEBUG_printf("QuestHandler now has %u active quests.\n",current.size());
#endif // DEBUG
			return 0;
		}
	}
#ifdef DEBUG
	DEBUG_printf("QuestHandler never had quest %s.\n",t);
#endif // DEBUG
	return -1;
}

bool QuestHandler::hasQuest(const char *t){
	unsigned int i;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
			return true;
		}
	}
	return false;
}
<commit_msg>fixed malloc crash<commit_after>#include <common.h>

#define TITLE	Quest(
#define DESC	,
#define REWARD	,(struct item_t){
#define x		,
#define END		}),

const Quest QuestList[TOTAL_QUESTS]={
//	Quest("Test","A test quest",(struct item_t){1,TEST_ITEM}),

// Get quest list
#include "../config/quest_list.txt"

};

// Trust nobody
#define STRLEN_MIN 16

unsigned int safe_strlen(const char *s){
	unsigned int size=0;
	while(s[size])size++;
	if(size<STRLEN_MIN)return STRLEN_MIN;
	else return size;
}

Quest::Quest(const char *t,const char *d,struct item_t r){
	title=(char *)calloc(safe_strlen(t),sizeof(char));
	desc=(char *)calloc(safe_strlen(d),sizeof(char));
	strcpy(title,t);
	strcpy(desc,d);
	memcpy(&reward,&r,sizeof(struct item_t));
}

Quest::~Quest(){
	free(title);
	free(desc);
	memset(&reward,0,sizeof(struct item_t));
}

int QuestHandler::assign(const char *t){
	unsigned char i;
	for(i=0;i<current.size();i++){				// Make sure we don't already have this quest
		if(!strcmp(current[i]->title,t)){
#ifdef DEBUG
			DEBUG_printf("The QuestHandler already has this quest: %s\n",t);
#endif // DEBUG
			return -2;
		}
	}
	for(i=0;i<TOTAL_QUESTS;i++){				// Add the quest (if it really exists)
		if(!strcmp(QuestList[i].title,t)){
			current.push_back(&QuestList[i]);
#ifdef DEBUG
			DEBUG_printf("Added quest %s, now have %u active quests.\n",t,current.size());
#endif // DEBUG
			return current.size();
		}
#ifdef DEBUG
		DEBUG_printf("Finding quest: %s != %s\n",t,QuestList[i].title);
#endif // DEBUG
	}
#ifdef DEBUG
	DEBUG_printf("Quest %s does not exist.\n",t);
#endif // DEBUG
	return -1;
}

int QuestHandler::drop(const char *t){
	unsigned char i;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
			current.erase(current.begin()+i);
			return current.size();
		}
	}
	return -1;
}

int QuestHandler::finish(const char *t,void *completer){
	unsigned char i;
	unsigned int r;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
#ifdef DEBUG
			DEBUG_printf("Completing quest %s.\n",t);
#endif // DEBUG
			((Entity *)completer)->inv->addItem(current[i]->reward.id,current[i]->reward.count);
			current.erase(current.begin()+i);
#ifdef DEBUG
			DEBUG_printf("QuestHandler now has %u active quests.\n",current.size());
#endif // DEBUG
			return 0;
		}
	}
#ifdef DEBUG
	DEBUG_printf("QuestHandler never had quest %s.\n",t);
#endif // DEBUG
	return -1;
}

bool QuestHandler::hasQuest(const char *t){
	unsigned int i;
	for(i=0;i<current.size();i++){
		if(!strcmp(current[i]->title,t)){
			return true;
		}
	}
	return false;
}
<|endoftext|>


<commit_before>#ifndef SPEED_CONTROL_H
#define SPEED_CONTROL_H

#include <Arduino.h>

class Servo;
class SerialMessageHandler;

class SpeedControl
{
	/**
	 * external state transitions (initiated by the user)
	 * - STOPPED -> DRIVING or REVERSING
	 * - DRIVING -> STOPPING
	 * - REVERSING -> DRIVING or STOPPING
	 * - REVERSE_WAIT -> DRIVING or STOPPING
	 *
	 * internal transitions
	 * - STOPPING -> REVERSE_WAIT -> REVERSING
	 * - STOPPING -> STOPPED
	 *
	 */

	enum State
	{
		DISABLED,
		STOPPED,
		BRAKING,
		DRIVING,
		REVERSING,
		REVERSE_WAIT,
		STOPPING_REVERSE
	};

	static const unsigned long minimum_tick_micros = 50;
	static const unsigned int tick_array_size = 4; // tick array size must be a power of 2
	static const unsigned int tick_array_mask = tick_array_size -1;

	SerialMessageHandler *message_handler;
	Servo *throttle_servo;

	SpeedControl::State state = DISABLED;

	unsigned long last_update_millis;
	unsigned long last_update_ticks;
	unsigned long reverse_wait_start_millis;

	unsigned long tick_array[tick_array_size];
	unsigned int tick_index;
	unsigned long last_tick_micros;
	unsigned long tick_counter;
	int target_speed;

public:
	int ticks_per_metre = 30;
	int brake_throttle = 40;
	int throttle_offset = 0;

	void set_throttle(int throttle);
	int get_throttle();
	float current_speed();
	void set_speed(int requested_speed);

	void set_throttle_offset(int amount) {throttle_offset = constrain(amount, -40, 40);}
	void set_brake_force(int amount) {brake_throttle = constrain(amount, 0, 90);}
	void set_ticks_per_metre(int amount) {ticks_per_metre = constrain(amount, 0, 1000);}

	void init(SerialMessageHandler *message_handler, Servo *throttle_servo);
	void poll();
	void disable();
	void interrupt();
};

#endif /* SPEED_CONTROL_H */

<commit_msg>Make interrupt-modified variables volatile.<commit_after>#ifndef SPEED_CONTROL_H
#define SPEED_CONTROL_H

#include <Arduino.h>

class Servo;
class SerialMessageHandler;

class SpeedControl
{
	/**
	 * external state transitions (initiated by the user)
	 * - STOPPED -> DRIVING or REVERSING
	 * - DRIVING -> STOPPING
	 * - REVERSING -> DRIVING or STOPPING
	 * - REVERSE_WAIT -> DRIVING or STOPPING
	 *
	 * internal transitions
	 * - STOPPING -> REVERSE_WAIT -> REVERSING
	 * - STOPPING -> STOPPED
	 *
	 */

	enum State
	{
		DISABLED,
		STOPPED,
		BRAKING,
		DRIVING,
		REVERSING,
		REVERSE_WAIT,
		STOPPING_REVERSE
	};

	static const unsigned long minimum_tick_micros = 50;
	static const unsigned int tick_array_size = 4; // tick array size must be a power of 2
	static const unsigned int tick_array_mask = tick_array_size -1;

	SerialMessageHandler *message_handler;
	Servo *throttle_servo;

	SpeedControl::State state = DISABLED;

	unsigned long last_update_millis;
	unsigned long last_update_ticks;
	unsigned long reverse_wait_start_millis;

	volatile unsigned long tick_array[tick_array_size];
	volatile unsigned long tick_counter;
	volatile unsigned long last_tick_micros;

	int target_speed;

public:
	int ticks_per_metre = 30;
	int brake_throttle = 40;
	int throttle_offset = 0;

	void set_throttle(int throttle);
	int get_throttle();
	float current_speed();
	void set_speed(int requested_speed);

	void set_throttle_offset(int amount) {throttle_offset = constrain(amount, -40, 40);}
	void set_brake_force(int amount) {brake_throttle = constrain(amount, 0, 90);}
	void set_ticks_per_metre(int amount) {ticks_per_metre = constrain(amount, 0, 1000);}

	void init(SerialMessageHandler *message_handler, Servo *throttle_servo);
	void poll();
	void disable();
	void interrupt();
};

#endif /* SPEED_CONTROL_H */

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: e3ditem.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 18:27:16 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _COM_SUN_STAR_DRAWING_DIRECTION3D_HPP_
#include <com/sun/star/drawing/Direction3D.hpp>
#endif
#ifndef _STREAM_HXX
#include <tools/stream.hxx>
#endif

#include <svx/e3ditem.hxx>

using namespace ::rtl;
using namespace ::com::sun::star;

// STATIC DATA -----------------------------------------------------------

DBG_NAMEEX(SvxB3DVectorItem)
DBG_NAME(SvxB3DVectorItem)

// -----------------------------------------------------------------------

TYPEINIT1_FACTORY(SvxB3DVectorItem, SfxPoolItem, new SvxB3DVectorItem);

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem()
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

SvxB3DVectorItem::~SvxB3DVectorItem()
{
    DBG_DTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( USHORT _nWhich, const basegfx::B3DVector& rVal ) :
    SfxPoolItem( _nWhich ),
    aVal( rVal )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( USHORT _nWhich, SvStream& rStream ) :
    SfxPoolItem( _nWhich )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
    double fValue;
    rStream >> fValue; aVal.setX(fValue);
    rStream >> fValue; aVal.setY(fValue);
    rStream >> fValue; aVal.setZ(fValue);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( const SvxB3DVectorItem& rItem ) :
    SfxPoolItem( rItem ),
    aVal( rItem.aVal )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

int SvxB3DVectorItem::operator==( const SfxPoolItem &rItem ) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );
    return ((SvxB3DVectorItem&)rItem).aVal == aVal;
}

// -----------------------------------------------------------------------

SfxPoolItem* SvxB3DVectorItem::Clone( SfxItemPool* /*pPool*/ ) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    return new SvxB3DVectorItem( *this );
}

// -----------------------------------------------------------------------

SfxPoolItem* SvxB3DVectorItem::Create(SvStream &rStream, USHORT /*nVersion*/) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    basegfx::B3DVector aStr;
    double fValue;
    rStream >> fValue; aStr.setX(fValue);
    rStream >> fValue; aStr.setY(fValue);
    rStream >> fValue; aStr.setZ(fValue);
    return new SvxB3DVectorItem(Which(), aStr);
}

// -----------------------------------------------------------------------

SvStream& SvxB3DVectorItem::Store(SvStream &rStream, USHORT /*nItemVersion*/) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);

    // ## if (nItemVersion)
    double fValue;
    fValue = aVal.getX(); rStream << fValue;
    fValue = aVal.getY(); rStream << fValue;
    fValue = aVal.getZ(); rStream << fValue;

    return rStream;
}

// -----------------------------------------------------------------------

sal_Bool SvxB3DVectorItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const
{
    drawing::Direction3D aDirection;

    // Werte eintragen
    aDirection.DirectionX = aVal.getX();
    aDirection.DirectionY = aVal.getY();
    aDirection.DirectionZ = aVal.getZ();

    rVal <<= aDirection;
    return( sal_True );
}

// -----------------------------------------------------------------------

sal_Bool SvxB3DVectorItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ )
{
    drawing::Direction3D aDirection;
    if(!(rVal >>= aDirection))
        return sal_False;

    aVal.setX(aDirection.DirectionX);
    aVal.setY(aDirection.DirectionY);
    aVal.setZ(aDirection.DirectionZ);
    return sal_True;
}

// -----------------------------------------------------------------------

USHORT SvxB3DVectorItem::GetVersion (USHORT nFileFormatVersion) const
{
    return (nFileFormatVersion == SOFFICE_FILEFORMAT_31) ? USHRT_MAX : 0;
}

// eof
<commit_msg>INTEGRATION: CWS changefileheader (1.10.368); FILE MERGED 2008/04/01 15:51:16 thb 1.10.368.3: #i85898# Stripping all external header guards 2008/04/01 12:49:13 thb 1.10.368.2: #i85898# Stripping all external header guards 2008/03/31 14:22:34 rt 1.10.368.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: e3ditem.cxx,v $
 * $Revision: 1.11 $
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include <com/sun/star/drawing/Direction3D.hpp>
#include <tools/stream.hxx>

#include <svx/e3ditem.hxx>

using namespace ::rtl;
using namespace ::com::sun::star;

// STATIC DATA -----------------------------------------------------------

DBG_NAMEEX(SvxB3DVectorItem)
DBG_NAME(SvxB3DVectorItem)

// -----------------------------------------------------------------------

TYPEINIT1_FACTORY(SvxB3DVectorItem, SfxPoolItem, new SvxB3DVectorItem);

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem()
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

SvxB3DVectorItem::~SvxB3DVectorItem()
{
    DBG_DTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( USHORT _nWhich, const basegfx::B3DVector& rVal ) :
    SfxPoolItem( _nWhich ),
    aVal( rVal )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( USHORT _nWhich, SvStream& rStream ) :
    SfxPoolItem( _nWhich )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
    double fValue;
    rStream >> fValue; aVal.setX(fValue);
    rStream >> fValue; aVal.setY(fValue);
    rStream >> fValue; aVal.setZ(fValue);
}

// -----------------------------------------------------------------------

SvxB3DVectorItem::SvxB3DVectorItem( const SvxB3DVectorItem& rItem ) :
    SfxPoolItem( rItem ),
    aVal( rItem.aVal )
{
    DBG_CTOR(SvxB3DVectorItem, 0);
}

// -----------------------------------------------------------------------

int SvxB3DVectorItem::operator==( const SfxPoolItem &rItem ) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );
    return ((SvxB3DVectorItem&)rItem).aVal == aVal;
}

// -----------------------------------------------------------------------

SfxPoolItem* SvxB3DVectorItem::Clone( SfxItemPool* /*pPool*/ ) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    return new SvxB3DVectorItem( *this );
}

// -----------------------------------------------------------------------

SfxPoolItem* SvxB3DVectorItem::Create(SvStream &rStream, USHORT /*nVersion*/) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);
    basegfx::B3DVector aStr;
    double fValue;
    rStream >> fValue; aStr.setX(fValue);
    rStream >> fValue; aStr.setY(fValue);
    rStream >> fValue; aStr.setZ(fValue);
    return new SvxB3DVectorItem(Which(), aStr);
}

// -----------------------------------------------------------------------

SvStream& SvxB3DVectorItem::Store(SvStream &rStream, USHORT /*nItemVersion*/) const
{
    DBG_CHKTHIS(SvxB3DVectorItem, 0);

    // ## if (nItemVersion)
    double fValue;
    fValue = aVal.getX(); rStream << fValue;
    fValue = aVal.getY(); rStream << fValue;
    fValue = aVal.getZ(); rStream << fValue;

    return rStream;
}

// -----------------------------------------------------------------------

sal_Bool SvxB3DVectorItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const
{
    drawing::Direction3D aDirection;

    // Werte eintragen
    aDirection.DirectionX = aVal.getX();
    aDirection.DirectionY = aVal.getY();
    aDirection.DirectionZ = aVal.getZ();

    rVal <<= aDirection;
    return( sal_True );
}

// -----------------------------------------------------------------------

sal_Bool SvxB3DVectorItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ )
{
    drawing::Direction3D aDirection;
    if(!(rVal >>= aDirection))
        return sal_False;

    aVal.setX(aDirection.DirectionX);
    aVal.setY(aDirection.DirectionY);
    aVal.setZ(aDirection.DirectionZ);
    return sal_True;
}

// -----------------------------------------------------------------------

USHORT SvxB3DVectorItem::GetVersion (USHORT nFileFormatVersion) const
{
    return (nFileFormatVersion == SOFFICE_FILEFORMAT_31) ? USHRT_MAX : 0;
}

// eof
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: grfitem.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 18:28:01 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#ifndef _SVX_GRFCROP_HXX
#include <svx/grfcrop.hxx>
#endif
#ifndef _SVX_ITEMTYPE_HXX //autogen
#include <svx/itemtype.hxx>
#endif
#ifndef _COM_SUN_STAR_TEXT_GRAPHICCROP_HPP_
#include <com/sun/star/text/GraphicCrop.hpp>
#endif

using namespace ::com::sun::star;

#define TWIP_TO_MM100(TWIP)     ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L))
#define MM100_TO_TWIP(MM100)    ((MM100) >= 0 ? (((MM100)*72L+63L)/127L) : (((MM100)*72L-63L)/127L))
//TYPEINIT1_FACTORY( SvxGrfCrop, SfxPoolItem , new  SvxGrfCrop(0))

/******************************************************************************
 *  Implementierung     class SwCropGrf
 ******************************************************************************/

SvxGrfCrop::SvxGrfCrop( USHORT nItemId )
    : SfxPoolItem( nItemId ),
    nLeft( 0 ), nRight( 0 ), nTop( 0 ), nBottom( 0 )
{}

SvxGrfCrop::SvxGrfCrop( sal_Int32 nL, sal_Int32 nR,
                        sal_Int32 nT, sal_Int32 nB, USHORT nItemId )
    : SfxPoolItem( nItemId ),
    nLeft( nL ), nRight( nR ), nTop( nT ), nBottom( nB )
{}

SvxGrfCrop::~SvxGrfCrop()
{
}

int SvxGrfCrop::operator==( const SfxPoolItem& rAttr ) const
{
    DBG_ASSERT( SfxPoolItem::operator==( rAttr ), "not equal attributes" );
    return nLeft    == ((const SvxGrfCrop&)rAttr).GetLeft() &&
           nRight   == ((const SvxGrfCrop&)rAttr).GetRight() &&
           nTop     == ((const SvxGrfCrop&)rAttr).GetTop() &&
           nBottom  == ((const SvxGrfCrop&)rAttr).GetBottom();
}

/*
SfxPoolItem* SvxGrfCrop::Clone( SfxItemPool* ) const
{
    return new SvxGrfCrop( *this );
}
*/

/*
USHORT SvxGrfCrop::GetVersion( USHORT nFFVer ) const
{
    DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer ||
                SOFFICE_FILEFORMAT_40==nFFVer ||
                SOFFICE_FILEFORMAT_NOW==nFFVer,
                "SvxGrfCrop: exist a new fileformat?" );
    return GRFCROP_VERSION_SWDEFAULT;
}
*/

SfxPoolItem* SvxGrfCrop::Create( SvStream& rStrm, USHORT nVersion ) const
{
    INT32 top, left, right, bottom;
    rStrm >> top >> left >> right >> bottom;

    if( GRFCROP_VERSION_SWDEFAULT == nVersion )
        top = -top, bottom = -bottom, left = -left, right = -right;

    SvxGrfCrop* pNew = (SvxGrfCrop*)Clone();
    pNew->SetLeft( left );
    pNew->SetRight( right );
    pNew->SetTop( top );
    pNew->SetBottom( bottom );
    return pNew;
}

SvStream& SvxGrfCrop::Store( SvStream& rStrm, USHORT nVersion ) const
{
    INT32 left = GetLeft(), right = GetRight(),
            top = GetTop(), bottom = GetBottom();
    if( GRFCROP_VERSION_SWDEFAULT == nVersion )
        top = -top, bottom = -bottom, left = -left, right = -right;

    rStrm << top << left << right << bottom;

    return rStrm;
}

BOOL SvxGrfCrop::QueryValue( uno::Any& rVal, BYTE nMemberId ) const
{
    sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
    nMemberId &= ~CONVERT_TWIPS;
    text::GraphicCrop aRet;
    aRet.Left   = nLeft;
    aRet.Right  = nRight;
    aRet.Top    = nTop;
    aRet.Bottom = nBottom;

    if( bConvert )
    {
       aRet.Right   = TWIP_TO_MM100(aRet.Right );
       aRet.Top     = TWIP_TO_MM100(aRet.Top );
       aRet.Left    = TWIP_TO_MM100(aRet.Left   );
       aRet.Bottom  = TWIP_TO_MM100(aRet.Bottom);
    }

    rVal <<= aRet;
    return   sal_True;
}

BOOL SvxGrfCrop::PutValue( const uno::Any& rVal, BYTE nMemberId )
{
    sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
    nMemberId &= ~CONVERT_TWIPS;
    text::GraphicCrop aVal;

    if(!(rVal >>= aVal))
        return sal_False;
    if( bConvert )
    {
       aVal.Right   = MM100_TO_TWIP(aVal.Right );
       aVal.Top     = MM100_TO_TWIP(aVal.Top );
       aVal.Left    = MM100_TO_TWIP(aVal.Left   );
       aVal.Bottom  = MM100_TO_TWIP(aVal.Bottom);
    }

    nLeft   = aVal.Left  ;
    nRight  = aVal.Right ;
    nTop    = aVal.Top   ;
    nBottom = aVal.Bottom;
    return  sal_True;
}

SfxItemPresentation SvxGrfCrop::GetPresentation(
    SfxItemPresentation ePres, SfxMapUnit eCoreUnit, SfxMapUnit /*ePresUnit*/,
    String &rText, const IntlWrapper* pIntl ) const
{
    rText.Erase();
    switch( ePres )
    {
    case SFX_ITEM_PRESENTATION_NAMELESS:
    case SFX_ITEM_PRESENTATION_COMPLETE:
        if( SFX_ITEM_PRESENTATION_COMPLETE == ePres )
        {
            ( rText.AssignAscii( "L: " )) += ::GetMetricText( GetLeft(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " R: " )) += ::GetMetricText( GetRight(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " T: " )) += ::GetMetricText( GetTop(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " B: " )) += ::GetMetricText( GetBottom(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
        }
        break;

    default:
        ePres = SFX_ITEM_PRESENTATION_NONE;
        break;
    }
    return ePres;
}

<commit_msg>INTEGRATION: CWS changefileheader (1.11.368); FILE MERGED 2008/04/01 15:51:17 thb 1.11.368.3: #i85898# Stripping all external header guards 2008/04/01 12:49:14 thb 1.11.368.2: #i85898# Stripping all external header guards 2008/03/31 14:22:34 rt 1.11.368.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: grfitem.cxx,v $
 * $Revision: 1.12 $
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#include <tools/stream.hxx>
#include <svx/grfcrop.hxx>
#include <svx/itemtype.hxx>
#include <com/sun/star/text/GraphicCrop.hpp>

using namespace ::com::sun::star;

#define TWIP_TO_MM100(TWIP)     ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L))
#define MM100_TO_TWIP(MM100)    ((MM100) >= 0 ? (((MM100)*72L+63L)/127L) : (((MM100)*72L-63L)/127L))
//TYPEINIT1_FACTORY( SvxGrfCrop, SfxPoolItem , new  SvxGrfCrop(0))

/******************************************************************************
 *  Implementierung     class SwCropGrf
 ******************************************************************************/

SvxGrfCrop::SvxGrfCrop( USHORT nItemId )
    : SfxPoolItem( nItemId ),
    nLeft( 0 ), nRight( 0 ), nTop( 0 ), nBottom( 0 )
{}

SvxGrfCrop::SvxGrfCrop( sal_Int32 nL, sal_Int32 nR,
                        sal_Int32 nT, sal_Int32 nB, USHORT nItemId )
    : SfxPoolItem( nItemId ),
    nLeft( nL ), nRight( nR ), nTop( nT ), nBottom( nB )
{}

SvxGrfCrop::~SvxGrfCrop()
{
}

int SvxGrfCrop::operator==( const SfxPoolItem& rAttr ) const
{
    DBG_ASSERT( SfxPoolItem::operator==( rAttr ), "not equal attributes" );
    return nLeft    == ((const SvxGrfCrop&)rAttr).GetLeft() &&
           nRight   == ((const SvxGrfCrop&)rAttr).GetRight() &&
           nTop     == ((const SvxGrfCrop&)rAttr).GetTop() &&
           nBottom  == ((const SvxGrfCrop&)rAttr).GetBottom();
}

/*
SfxPoolItem* SvxGrfCrop::Clone( SfxItemPool* ) const
{
    return new SvxGrfCrop( *this );
}
*/

/*
USHORT SvxGrfCrop::GetVersion( USHORT nFFVer ) const
{
    DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer ||
                SOFFICE_FILEFORMAT_40==nFFVer ||
                SOFFICE_FILEFORMAT_NOW==nFFVer,
                "SvxGrfCrop: exist a new fileformat?" );
    return GRFCROP_VERSION_SWDEFAULT;
}
*/

SfxPoolItem* SvxGrfCrop::Create( SvStream& rStrm, USHORT nVersion ) const
{
    INT32 top, left, right, bottom;
    rStrm >> top >> left >> right >> bottom;

    if( GRFCROP_VERSION_SWDEFAULT == nVersion )
        top = -top, bottom = -bottom, left = -left, right = -right;

    SvxGrfCrop* pNew = (SvxGrfCrop*)Clone();
    pNew->SetLeft( left );
    pNew->SetRight( right );
    pNew->SetTop( top );
    pNew->SetBottom( bottom );
    return pNew;
}

SvStream& SvxGrfCrop::Store( SvStream& rStrm, USHORT nVersion ) const
{
    INT32 left = GetLeft(), right = GetRight(),
            top = GetTop(), bottom = GetBottom();
    if( GRFCROP_VERSION_SWDEFAULT == nVersion )
        top = -top, bottom = -bottom, left = -left, right = -right;

    rStrm << top << left << right << bottom;

    return rStrm;
}

BOOL SvxGrfCrop::QueryValue( uno::Any& rVal, BYTE nMemberId ) const
{
    sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
    nMemberId &= ~CONVERT_TWIPS;
    text::GraphicCrop aRet;
    aRet.Left   = nLeft;
    aRet.Right  = nRight;
    aRet.Top    = nTop;
    aRet.Bottom = nBottom;

    if( bConvert )
    {
       aRet.Right   = TWIP_TO_MM100(aRet.Right );
       aRet.Top     = TWIP_TO_MM100(aRet.Top );
       aRet.Left    = TWIP_TO_MM100(aRet.Left   );
       aRet.Bottom  = TWIP_TO_MM100(aRet.Bottom);
    }

    rVal <<= aRet;
    return   sal_True;
}

BOOL SvxGrfCrop::PutValue( const uno::Any& rVal, BYTE nMemberId )
{
    sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
    nMemberId &= ~CONVERT_TWIPS;
    text::GraphicCrop aVal;

    if(!(rVal >>= aVal))
        return sal_False;
    if( bConvert )
    {
       aVal.Right   = MM100_TO_TWIP(aVal.Right );
       aVal.Top     = MM100_TO_TWIP(aVal.Top );
       aVal.Left    = MM100_TO_TWIP(aVal.Left   );
       aVal.Bottom  = MM100_TO_TWIP(aVal.Bottom);
    }

    nLeft   = aVal.Left  ;
    nRight  = aVal.Right ;
    nTop    = aVal.Top   ;
    nBottom = aVal.Bottom;
    return  sal_True;
}

SfxItemPresentation SvxGrfCrop::GetPresentation(
    SfxItemPresentation ePres, SfxMapUnit eCoreUnit, SfxMapUnit /*ePresUnit*/,
    String &rText, const IntlWrapper* pIntl ) const
{
    rText.Erase();
    switch( ePres )
    {
    case SFX_ITEM_PRESENTATION_NAMELESS:
    case SFX_ITEM_PRESENTATION_COMPLETE:
        if( SFX_ITEM_PRESENTATION_COMPLETE == ePres )
        {
            ( rText.AssignAscii( "L: " )) += ::GetMetricText( GetLeft(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " R: " )) += ::GetMetricText( GetRight(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " T: " )) += ::GetMetricText( GetTop(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
            ( rText.AppendAscii( " B: " )) += ::GetMetricText( GetBottom(),
                                            eCoreUnit, SFX_MAPUNIT_MM, pIntl );
        }
        break;

    default:
        ePres = SFX_ITEM_PRESENTATION_NONE;
        break;
    }
    return ePres;
}

<|endoftext|>