<commit_before>/*
# Copyright (c) 2015, FxArena DA <mail@fxarena.net>
# All rights reserved.
#
# OpenFX-Arena is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2. You should have received a copy of the GNU General Public License version 2 along with OpenFX-Arena. If not, see http://www.gnu.org/licenses/.
# OpenFX-Arena 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.
#
# Need custom licensing terms or conditions? Commercial license for proprietary software? Contact us.
*/

#include "Edges.h"
#include "ofxsMacros.h"
#include <Magick++.h>
#include <iostream>
#include <stdint.h>
#include <cmath>

#define kPluginName "EdgesOFX"
#define kPluginGrouping "Filter"
#define kPluginIdentifier "net.fxarena.openfx.Edges"
#define kPluginVersionMajor 0
#define kPluginVersionMinor 1
#define kPluginMagickVersion 26640

#define kParamWidth "width"
#define kParamWidthLabel "Width"
#define kParamWidthHint "Width of edges"
#define kParamWidthDefault 2

#define kParamBrightness "brightness"
#define kParamBrightnessLabel "Brightness"
#define kParamBrightnessHint "Adjust edge brightness"
#define kParamBrightnessDefault 5

#define kParamSmoothing "smoothing"
#define kParamSmoothingLabel "Smoothing"
#define kParamSmoothingHint "Adjust edge smoothing"
#define kParamSmoothingDefault 1

#define kSupportsTiles 0
#define kSupportsMultiResolution 0
#define kSupportsRenderScale 0 // TODO support renderscale
#define kRenderThreadSafety eRenderFullySafe
#define kHostFrameThreading false

using namespace OFX;

class EdgesPlugin : public OFX::ImageEffect
{
public:
    EdgesPlugin(OfxImageEffectHandle handle);
    virtual ~EdgesPlugin();
    virtual void render(const OFX::RenderArguments &args) OVERRIDE FINAL;
    virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL;
private:
    OFX::Clip *dstClip_;
    OFX::Clip *srcClip_;
    OFX::DoubleParam *brightness_;
    OFX::DoubleParam *smoothing_;
    OFX::IntParam *width_;
};

EdgesPlugin::EdgesPlugin(OfxImageEffectHandle handle)
: OFX::ImageEffect(handle)
, dstClip_(0)
, srcClip_(0)
{
    Magick::InitializeMagick(NULL);
    dstClip_ = fetchClip(kOfxImageEffectOutputClipName);
    assert(dstClip_ && dstClip_->getPixelComponents() == OFX::ePixelComponentRGB);
    srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName);
    assert(srcClip_ && srcClip_->getPixelComponents() == OFX::ePixelComponentRGB);

    brightness_ = fetchDoubleParam(kParamBrightness);
    smoothing_ = fetchDoubleParam(kParamSmoothing);
    width_ = fetchIntParam(kParamWidth);

    assert(brightness_ && smoothing_ && width_);
}

EdgesPlugin::~EdgesPlugin()
{
}

void EdgesPlugin::render(const OFX::RenderArguments &args)
{
    // render scale
    if (!kSupportsRenderScale && (args.renderScale.x != 1. || args.renderScale.y != 1.)) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }

    // get src clip
    if (!srcClip_) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    assert(srcClip_);
    std::auto_ptr<const OFX::Image> srcImg(srcClip_->fetchImage(args.time));
    OfxRectI srcRod,srcBounds;
    if (srcImg.get()) {
        srcRod = srcImg->getRegionOfDefinition();
        srcBounds = srcImg->getBounds();
        if (srcImg->getRenderScale().x != args.renderScale.x ||
            srcImg->getRenderScale().y != args.renderScale.y ||
            srcImg->getField() != args.fieldToRender) {
            setPersistentMessage(OFX::Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
            OFX::throwSuiteStatusException(kOfxStatFailed);
            return;
        }
    }

    // get dest clip
    if (!dstClip_) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    assert(dstClip_);
    std::auto_ptr<OFX::Image> dstImg(dstClip_->fetchImage(args.time));
    if (!dstImg.get()) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    if (dstImg->getRenderScale().x != args.renderScale.x ||
        dstImg->getRenderScale().y != args.renderScale.y ||
        dstImg->getField() != args.fieldToRender) {
        setPersistentMessage(OFX::Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }

    // get bit depth
    OFX::BitDepthEnum dstBitDepth = dstImg->getPixelDepth();
    if (dstBitDepth != OFX::eBitDepthFloat || (srcImg.get() && (dstBitDepth != srcImg->getPixelDepth()))) {
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
        return;
    }

    // get pixel component
    OFX::PixelComponentEnum dstComponents  = dstImg->getPixelComponents();
    if (dstComponents != OFX::ePixelComponentRGB || (srcImg.get() && (dstComponents != srcImg->getPixelComponents()))) {
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
        return;
    }

    // are we in the image bounds?
    OfxRectI dstBounds = dstImg->getBounds();
    if(args.renderWindow.x1 < dstBounds.x1 || args.renderWindow.x1 >= dstBounds.x2 || args.renderWindow.y1 < dstBounds.y1 || args.renderWindow.y1 >= dstBounds.y2 ||
       args.renderWindow.x2 <= dstBounds.x1 || args.renderWindow.x2 > dstBounds.x2 || args.renderWindow.y2 <= dstBounds.y1 || args.renderWindow.y2 > dstBounds.y2) {
        OFX::throwSuiteStatusException(kOfxStatErrValue);
        return;
    }

    // get params
    double brightness,smoothing;
    int edge;
    brightness_->getValueAtTime(args.time, brightness);
    smoothing_->getValueAtTime(args.time, smoothing);
    width_->getValueAtTime(args.time, edge);

    // setup
    int width = srcRod.x2-srcRod.x1;
    int height = srcRod.y2-srcRod.y1;

    // read image
    Magick::Image image(Magick::Geometry(width,height),Magick::Color("rgb(0,0,0)"));
    if (srcClip_ && srcClip_->isConnected())
        image.read(width,height,"RGB",Magick::FloatPixel,(float*)srcImg->getPixelData());

    #ifdef DEBUG
    image.debug(true);
    #endif

    // blur
    if (smoothing>0)
        image.blur(0,smoothing);
    // edge
    std::ostringstream edgeWidth;
    edgeWidth<<edge;
    image.morphology(Magick::EdgeMorphology,Magick::DiamondKernel,edgeWidth.str());
    // multiply
    if (brightness>0) {
        image.quantumOperator(Magick::RedChannel,Magick::MultiplyEvaluateOperator,brightness);
        image.quantumOperator(Magick::GreenChannel,Magick::MultiplyEvaluateOperator,brightness);
        image.quantumOperator(Magick::BlueChannel,Magick::MultiplyEvaluateOperator,brightness);
    }

    // return image
    if (dstClip_ && dstClip_->isConnected() && srcClip_ && srcClip_->isConnected())
        image.write(0,0,width,height,"RGB",Magick::FloatPixel,(float*)dstImg->getPixelData());
}

bool EdgesPlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod)
{
    if (!kSupportsRenderScale && (args.renderScale.x != 1. || args.renderScale.y != 1.)) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return false;
    }
    if (srcClip_ && srcClip_->isConnected()) {
        rod = srcClip_->getRegionOfDefinition(args.time);
    } else {
        rod.x1 = rod.y1 = kOfxFlagInfiniteMin;
        rod.x2 = rod.y2 = kOfxFlagInfiniteMax;
    }
    return true;
}

mDeclarePluginFactory(EdgesPluginFactory, {}, {});

/** @brief The basic describe function, passed a plugin descriptor */
void EdgesPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    // basic labels
    desc.setLabel(kPluginName);
    desc.setPluginGrouping(kPluginGrouping);
    size_t magickNumber;
    std::string magickString = MagickCore::GetMagickVersion(&magickNumber);
    if (magickNumber != kPluginMagickVersion)
        magickString.append("\n\nWarning! You are using an unsupported version of ImageMagick.");
    desc.setPluginDescription("Edge extraction filter.\n\nWritten by Ole-André Rodlie <olear@fxarena.net>\n\nPowered by "+magickString);

    // add the supported contexts
    desc.addSupportedContext(eContextGeneral);
    desc.addSupportedContext(eContextFilter);

    // add supported pixel depths
    desc.addSupportedBitDepth(eBitDepthFloat);

    desc.setSupportsTiles(kSupportsTiles);
    desc.setSupportsMultiResolution(kSupportsMultiResolution);
    desc.setRenderThreadSafety(kRenderThreadSafety);
    desc.setHostFrameThreading(kHostFrameThreading);
}

/** @brief The describe in context function, passed a plugin descriptor and a context */
void EdgesPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum /*context*/)
{
    // create the mandated source clip
    ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
    srcClip->addSupportedComponent(ePixelComponentRGB);
    srcClip->setTemporalClipAccess(false);
    srcClip->setSupportsTiles(kSupportsTiles);
    srcClip->setIsMask(false);

    // create the mandated output clip
    ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
    dstClip->addSupportedComponent(ePixelComponentRGB);
    dstClip->setSupportsTiles(kSupportsTiles);

    // make some pages
    PageParamDescriptor *page = desc.definePageParam(kPluginName);
    {
        IntParamDescriptor *param = desc.defineIntParam(kParamWidth);
        param->setLabel(kParamWidthLabel);
        param->setHint(kParamWidthHint);
        param->setRange(0, 100);
        param->setDisplayRange(0, 100);
        param->setDefault(kParamWidthDefault);
        page->addChild(*param);
    }
    {
        DoubleParamDescriptor *param = desc.defineDoubleParam(kParamBrightness);
        param->setLabel(kParamBrightnessLabel);
        param->setHint(kParamBrightnessHint);
        param->setRange(0, 100);
        param->setDisplayRange(0, 100);
        param->setDefault(kParamBrightnessDefault);
        page->addChild(*param);
    }
    {
        DoubleParamDescriptor *param = desc.defineDoubleParam(kParamSmoothing);
        param->setLabel(kParamSmoothingLabel);
        param->setHint(kParamSmoothingHint);
        param->setRange(0, 10);
        param->setDisplayRange(0, 10);
        param->setDefault(kParamSmoothingDefault);
        page->addChild(*param);
    }
}

/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */
ImageEffect* EdgesPluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/)
{
    return new EdgesPlugin(handle);
}

void getEdgesPluginID(OFX::PluginFactoryArray &ids)
{
    static EdgesPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<commit_msg>Edges: misc fixes<commit_after>/*
# Copyright (c) 2015, FxArena DA <mail@fxarena.net>
# All rights reserved.
#
# OpenFX-Arena is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2. You should have received a copy of the GNU General Public License version 2 along with OpenFX-Arena. If not, see http://www.gnu.org/licenses/.
# OpenFX-Arena 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.
#
# Need custom licensing terms or conditions? Commercial license for proprietary software? Contact us.
*/

#include "Edges.h"
#include "ofxsMacros.h"
#include <Magick++.h>
#include <iostream>
#include <stdint.h>
#include <cmath>

#define kPluginName "EdgesOFX"
#define kPluginGrouping "Filter"
#define kPluginIdentifier "net.fxarena.openfx.Edges"
#define kPluginVersionMajor 1
#define kPluginVersionMinor 0
#define kPluginMagickVersion 26640

#define kParamWidth "width"
#define kParamWidthLabel "Width"
#define kParamWidthHint "Width of edges"
#define kParamWidthDefault 2

#define kParamBrightness "brightness"
#define kParamBrightnessLabel "Brightness"
#define kParamBrightnessHint "Adjust edge brightness"
#define kParamBrightnessDefault 5

#define kParamSmoothing "smoothing"
#define kParamSmoothingLabel "Smoothing"
#define kParamSmoothingHint "Adjust edge smoothing"
#define kParamSmoothingDefault 1

#define kParamGray "gray"
#define kParamGrayLabel "Grayscale"
#define kParamGrayHint "Conver to grayscale before effect"
#define kParamGrayDefault false

#define kSupportsTiles 0
#define kSupportsMultiResolution 0
#define kSupportsRenderScale 1
#define kRenderThreadSafety eRenderFullySafe
#define kHostFrameThreading false

using namespace OFX;

class EdgesPlugin : public OFX::ImageEffect
{
public:
    EdgesPlugin(OfxImageEffectHandle handle);
    virtual ~EdgesPlugin();
    virtual void render(const OFX::RenderArguments &args) OVERRIDE FINAL;
    virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL;
private:
    OFX::Clip *dstClip_;
    OFX::Clip *srcClip_;
    OFX::DoubleParam *brightness_;
    OFX::DoubleParam *smoothing_;
    OFX::IntParam *width_;
    OFX::BooleanParam *gray_;
};

EdgesPlugin::EdgesPlugin(OfxImageEffectHandle handle)
: OFX::ImageEffect(handle)
, dstClip_(0)
, srcClip_(0)
{
    Magick::InitializeMagick(NULL);
    dstClip_ = fetchClip(kOfxImageEffectOutputClipName);
    assert(dstClip_ && dstClip_->getPixelComponents() == OFX::ePixelComponentRGB);
    srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName);
    assert(srcClip_ && srcClip_->getPixelComponents() == OFX::ePixelComponentRGB);

    brightness_ = fetchDoubleParam(kParamBrightness);
    smoothing_ = fetchDoubleParam(kParamSmoothing);
    width_ = fetchIntParam(kParamWidth);
    gray_ = fetchBooleanParam(kParamGray);

    assert(brightness_ && smoothing_ && width_ && gray_);
}

EdgesPlugin::~EdgesPlugin()
{
}

void EdgesPlugin::render(const OFX::RenderArguments &args)
{
    // render scale
    if (!kSupportsRenderScale && (args.renderScale.x != 1. || args.renderScale.y != 1.)) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }

    // get src clip
    if (!srcClip_) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    assert(srcClip_);
    std::auto_ptr<const OFX::Image> srcImg(srcClip_->fetchImage(args.time));
    OfxRectI srcRod,srcBounds;
    if (srcImg.get()) {
        srcRod = srcImg->getRegionOfDefinition();
        srcBounds = srcImg->getBounds();
        if (srcImg->getRenderScale().x != args.renderScale.x ||
            srcImg->getRenderScale().y != args.renderScale.y ||
            srcImg->getField() != args.fieldToRender) {
            setPersistentMessage(OFX::Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
            OFX::throwSuiteStatusException(kOfxStatFailed);
            return;
        }
    }

    // get dest clip
    if (!dstClip_) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    assert(dstClip_);
    std::auto_ptr<OFX::Image> dstImg(dstClip_->fetchImage(args.time));
    if (!dstImg.get()) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }
    if (dstImg->getRenderScale().x != args.renderScale.x ||
        dstImg->getRenderScale().y != args.renderScale.y ||
        dstImg->getField() != args.fieldToRender) {
        setPersistentMessage(OFX::Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return;
    }

    // get bit depth
    OFX::BitDepthEnum dstBitDepth = dstImg->getPixelDepth();
    if (dstBitDepth != OFX::eBitDepthFloat || (srcImg.get() && (dstBitDepth != srcImg->getPixelDepth()))) {
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
        return;
    }

    // get pixel component
    OFX::PixelComponentEnum dstComponents  = dstImg->getPixelComponents();
    if (dstComponents != OFX::ePixelComponentRGB || (srcImg.get() && (dstComponents != srcImg->getPixelComponents()))) {
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
        return;
    }

    // are we in the image bounds?
    OfxRectI dstBounds = dstImg->getBounds();
    if(args.renderWindow.x1 < dstBounds.x1 || args.renderWindow.x1 >= dstBounds.x2 || args.renderWindow.y1 < dstBounds.y1 || args.renderWindow.y1 >= dstBounds.y2 ||
       args.renderWindow.x2 <= dstBounds.x1 || args.renderWindow.x2 > dstBounds.x2 || args.renderWindow.y2 <= dstBounds.y1 || args.renderWindow.y2 > dstBounds.y2) {
        OFX::throwSuiteStatusException(kOfxStatErrValue);
        return;
    }

    // get params
    double brightness,smoothing;
    int edge;
    bool gray = false;
    brightness_->getValueAtTime(args.time, brightness);
    smoothing_->getValueAtTime(args.time, smoothing);
    width_->getValueAtTime(args.time, edge);
    gray_->getValueAtTime(args.time, gray);

    // setup
    int width = srcRod.x2-srcRod.x1;
    int height = srcRod.y2-srcRod.y1;

    // read image
    Magick::Image image(Magick::Geometry(width,height),Magick::Color("rgb(0,0,0)"));
    if (srcClip_ && srcClip_->isConnected())
        image.read(width,height,"RGB",Magick::FloatPixel,(float*)srcImg->getPixelData());

    #ifdef DEBUG
    image.debug(true);
    #endif

    // grayscale
    if (gray) {
        image.quantizeColorSpace(Magick::GRAYColorspace);
        image.quantize();
    }
    // blur
    if (smoothing>0)
        image.blur(0,std::floor(smoothing * args.renderScale.x));
    // edge
    std::ostringstream edgeWidth;
    edgeWidth<<std::floor((edge/2) * args.renderScale.x);
    image.morphology(Magick::EdgeMorphology,Magick::DiamondKernel,edgeWidth.str());
    // multiply
    if (brightness>0) {
        image.quantumOperator(Magick::RedChannel,Magick::MultiplyEvaluateOperator,std::floor(brightness * args.renderScale.x+0.5));
        image.quantumOperator(Magick::GreenChannel,Magick::MultiplyEvaluateOperator,std::floor(brightness * args.renderScale.x+0.5));
        image.quantumOperator(Magick::BlueChannel,Magick::MultiplyEvaluateOperator,std::floor(brightness * args.renderScale.x+0.5));
    }

    // return image
    if (dstClip_ && dstClip_->isConnected() && srcClip_ && srcClip_->isConnected())
        image.write(0,0,width,height,"RGB",Magick::FloatPixel,(float*)dstImg->getPixelData());
}

bool EdgesPlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod)
{
    if (!kSupportsRenderScale && (args.renderScale.x != 1. || args.renderScale.y != 1.)) {
        OFX::throwSuiteStatusException(kOfxStatFailed);
        return false;
    }
    if (srcClip_ && srcClip_->isConnected()) {
        rod = srcClip_->getRegionOfDefinition(args.time);
    } else {
        rod.x1 = rod.y1 = kOfxFlagInfiniteMin;
        rod.x2 = rod.y2 = kOfxFlagInfiniteMax;
    }
    return true;
}

mDeclarePluginFactory(EdgesPluginFactory, {}, {});

/** @brief The basic describe function, passed a plugin descriptor */
void EdgesPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    // basic labels
    desc.setLabel(kPluginName);
    desc.setPluginGrouping(kPluginGrouping);
    size_t magickNumber;
    std::string magickString = MagickCore::GetMagickVersion(&magickNumber);
    if (magickNumber != kPluginMagickVersion)
        magickString.append("\n\nWarning! You are using an unsupported version of ImageMagick.");
    desc.setPluginDescription("Edge extraction filter.\n\nWritten by Ole-André Rodlie <olear@fxarena.net>\n\nPowered by "+magickString);

    // add the supported contexts
    desc.addSupportedContext(eContextGeneral);
    desc.addSupportedContext(eContextFilter);

    // add supported pixel depths
    desc.addSupportedBitDepth(eBitDepthFloat);

    desc.setSupportsTiles(kSupportsTiles);
    desc.setSupportsMultiResolution(kSupportsMultiResolution);
    desc.setRenderThreadSafety(kRenderThreadSafety);
    desc.setHostFrameThreading(kHostFrameThreading);
}

/** @brief The describe in context function, passed a plugin descriptor and a context */
void EdgesPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum /*context*/)
{
    // create the mandated source clip
    ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
    srcClip->addSupportedComponent(ePixelComponentRGB);
    srcClip->setTemporalClipAccess(false);
    srcClip->setSupportsTiles(kSupportsTiles);
    srcClip->setIsMask(false);

    // create the mandated output clip
    ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
    dstClip->addSupportedComponent(ePixelComponentRGB);
    dstClip->setSupportsTiles(kSupportsTiles);

    // make some pages
    PageParamDescriptor *page = desc.definePageParam(kPluginName);
    {
        IntParamDescriptor *param = desc.defineIntParam(kParamWidth);
        param->setLabel(kParamWidthLabel);
        param->setHint(kParamWidthHint);
        param->setRange(0, 100);
        param->setDisplayRange(0, 100);
        param->setDefault(kParamWidthDefault);
        page->addChild(*param);
    }
    {
        DoubleParamDescriptor *param = desc.defineDoubleParam(kParamBrightness);
        param->setLabel(kParamBrightnessLabel);
        param->setHint(kParamBrightnessHint);
        param->setRange(0, 100);
        param->setDisplayRange(0, 100);
        param->setDefault(kParamBrightnessDefault);
        page->addChild(*param);
    }
    {
        DoubleParamDescriptor *param = desc.defineDoubleParam(kParamSmoothing);
        param->setLabel(kParamSmoothingLabel);
        param->setHint(kParamSmoothingHint);
        param->setRange(0, 10);
        param->setDisplayRange(0, 10);
        param->setDefault(kParamSmoothingDefault);
        page->addChild(*param);
    }
    {
        BooleanParamDescriptor *param = desc.defineBooleanParam(kParamGray);
        param->setLabel(kParamGrayLabel);
        param->setHint(kParamGrayHint);
        param->setDefault(kParamGrayDefault);
        page->addChild(*param);
    }
}

/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */
ImageEffect* EdgesPluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/)
{
    return new EdgesPlugin(handle);
}

void getEdgesPluginID(OFX::PluginFactoryArray &ids)
{
    static EdgesPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<|endoftext|>


<commit_before>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGPropeller.cpp
 Author:       Jon S. Berndt
 Date started: 08/24/00
 Purpose:      Encapsulates the propeller object

 ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 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 General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------
08/24/00  JSB  Created

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGPropeller.h"
#include "FGFCS.h"

static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.50 2001/12/23 21:49:01 jberndt Exp $";
static const char *IdHdr = ID_PROPELLER;

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

// This class currently makes certain assumptions when calculating torque and
// p-factor. That is, that the axis of rotation is the X axis of the aircraft -
// not just the X-axis of the engine/propeller. This may or may not work for a
// helicopter.

FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(exec)
{
  string token;
  int rows, cols;

  MaxPitch = MinPitch = P_Factor = Sense = Pitch = 0.0;

  Name = Prop_cfg->GetValue("NAME");
  Prop_cfg->GetNextConfigLine();
  while (Prop_cfg->GetValue() != string("/FG_PROPELLER")) {
    *Prop_cfg >> token;
    if (token == "IXX") {
      *Prop_cfg >> Ixx;
    } else if (token == "DIAMETER") {
      *Prop_cfg >> Diameter;
      Diameter /= 12.0;
    } else if (token == "NUMBLADES") {
      *Prop_cfg >> numBlades;
    } else if (token == "MINPITCH") {
      *Prop_cfg >> MinPitch;
    } else if (token == "MAXPITCH") {
      *Prop_cfg >> MaxPitch;
    } else if (token == "MINRPM") {
      *Prop_cfg >> MinRPM;
    } else if (token == "MAXRPM") {
      *Prop_cfg >> MaxRPM;
    } else if (token == "C_THRUST") {
      *Prop_cfg >> rows >> cols;
      if (cols == 1) cThrust = new FGTable(rows);
      else           cThrust = new FGTable(rows, cols);
      *cThrust << *Prop_cfg;
    } else if (token == "C_POWER") {
      *Prop_cfg >> rows >> cols;
      if (cols == 1) cPower = new FGTable(rows);
      else           cPower = new FGTable(rows, cols);
      *cPower << *Prop_cfg;
    } else if (token == "EOF") {
      cerr << "      End of file reached" <<  endl;
      break;
    } else {
      cerr << "Unhandled token in Propeller config file: " << token << endl;
    }
  }

  Type = ttPropeller;
  RPM = 0;
  vTorque.InitMatrix();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGPropeller::~FGPropeller()
{
  if (cThrust)    delete cThrust;
  if (cPower)     delete cPower;
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
// We need the velocity with respect to the wind.
//
// Note that PowerAvailable is the excess power available after the drag of the
// propeller has been subtracted. At equilibrium, PowerAvailable will be zero -
// indicating that the propeller will not accelerate or decelerate.
// Remembering that Torque * omega = Power, we can derive the torque on the
// propeller and its acceleration to give a new RPM. The current RPM will be
// used to calculate thrust.
//
// Because RPM could be zero, we need to be creative about what RPM is stated as.

double FGPropeller::Calculate(double PowerAvailable)
{
  double J, C_Thrust, omega;
  double Vel = fdmex->GetTranslation()->GetvAeroUVW(eU);
  double rho = fdmex->GetAtmosphere()->GetDensity();
  double RPS = RPM/60.0;
  double alpha, beta;

  if (RPM > 0.10) {
    J = Vel / (Diameter * RPS);
  } else {
    J = 0.0;
  }

  if (MaxPitch == MinPitch) { // Fixed pitch prop
    C_Thrust = cThrust->GetValue(J);
  } else {                    // Variable pitch prop
    C_Thrust = cThrust->GetValue(J, Pitch);
  }

  if (P_Factor > 0.0001) {
    alpha = fdmex->GetTranslation()->Getalpha();
    beta  = fdmex->GetTranslation()->Getbeta();
    SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
    SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
  } else if (P_Factor < 0.000) {
    cerr << "P-Factor value in config file must be greater than zero" << endl;
  }

  Thrust = C_Thrust*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho;
  vFn(1) = Thrust;
  omega = RPS*2.0*M_PI;

  // The Ixx value and rotation speed given below are for rotation about the
  // natural axis of the engine. The transform takes place in the base class
  // FGForce::GetBodyForces() function.

  vH(eX) = Ixx*omega*Sense;
  vH(eY) = 0.0;
  vH(eZ) = 0.0;

  if (omega <= 5) omega = 1.0;

  ExcessTorque = PowerAvailable / omega;
  RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;

  vMn = fdmex->GetRotation()->GetPQR()*vH + vTorque*Sense;

  return Thrust; // return thrust in pounds
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

double FGPropeller::GetPowerRequired(void)
{
  if (RPM <= 0.10) return 0.0; // If the prop ain't turnin', the fuel ain't burnin'.

  double cPReq, RPS = RPM / 60.0;

  double J = fdmex->GetTranslation()->GetvAeroUVW(eU) / (Diameter * RPS);
  double rho = fdmex->GetAtmosphere()->GetDensity();

  if (MaxPitch == MinPitch) { // Fixed pitch prop
    cPReq = cPower->GetValue(J);
  } else {                    // Variable pitch prop
    double advance = fdmex->GetFCS()->GetPropAdvance(ThrusterNumber);

    if (MaxRPM != MinRPM) {   // fixed-speed prop
      double rpmReq = MinRPM + (MaxRPM - MinRPM) * advance;
      double dRPM = rpmReq - RPM;

      Pitch -= dRPM / 10;

      if (Pitch < MinPitch)       Pitch = MinPitch;
      else if (Pitch > MaxPitch)  Pitch = MaxPitch;

    } else {
      Pitch = MaxPitch - (MaxPitch - MinPitch) * advance;
    }
    cPReq = cPower->GetValue(J, Pitch);
  }

  PowerRequired = cPReq*RPS*RPS*RPS*Diameter*Diameter*Diameter*Diameter
                                                       *Diameter*rho;
  vTorque(eX) = -Sense*PowerRequired / (RPS*2.0*M_PI);

  return PowerRequired;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGColumnVector3 FGPropeller::GetPFactor()
{
  double px=0.0, py, pz;

  py = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
  pz = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;

  return FGColumnVector3(px, py, pz);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGPropeller::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      cout << "\n    Propeller Name: " << Name << endl;
      cout << "      IXX = " << Ixx << endl;
      cout << "      Diameter = " << Diameter << " ft." << endl;
      cout << "      Number of Blades  = " << numBlades << endl;
      cout << "      Minimum Pitch  = " << MinPitch << endl;
      cout << "      Maximum Pitch  = " << MaxPitch << endl;
      cout << "      Thrust Coefficient: " <<  endl;
      cThrust->Print();
      cout << "      Power Coefficient: " <<  endl;
      cPower->Print();
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGPropeller" << endl;
    if (from == 1) cout << "Destroyed:    FGPropeller" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}

<commit_msg>Added preliminary support for windmilling, based on formula from Jon.<commit_after>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGPropeller.cpp
 Author:       Jon S. Berndt
 Date started: 08/24/00
 Purpose:      Encapsulates the propeller object

 ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 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 General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------
08/24/00  JSB  Created

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGPropeller.h"
#include "FGFCS.h"

static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.51 2001/12/24 22:58:40 dmegginson Exp $";
static const char *IdHdr = ID_PROPELLER;

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

// This class currently makes certain assumptions when calculating torque and
// p-factor. That is, that the axis of rotation is the X axis of the aircraft -
// not just the X-axis of the engine/propeller. This may or may not work for a
// helicopter.

FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(exec)
{
  string token;
  int rows, cols;

  MaxPitch = MinPitch = P_Factor = Sense = Pitch = 0.0;

  Name = Prop_cfg->GetValue("NAME");
  Prop_cfg->GetNextConfigLine();
  while (Prop_cfg->GetValue() != string("/FG_PROPELLER")) {
    *Prop_cfg >> token;
    if (token == "IXX") {
      *Prop_cfg >> Ixx;
    } else if (token == "DIAMETER") {
      *Prop_cfg >> Diameter;
      Diameter /= 12.0;
    } else if (token == "NUMBLADES") {
      *Prop_cfg >> numBlades;
    } else if (token == "MINPITCH") {
      *Prop_cfg >> MinPitch;
    } else if (token == "MAXPITCH") {
      *Prop_cfg >> MaxPitch;
    } else if (token == "MINRPM") {
      *Prop_cfg >> MinRPM;
    } else if (token == "MAXRPM") {
      *Prop_cfg >> MaxRPM;
    } else if (token == "C_THRUST") {
      *Prop_cfg >> rows >> cols;
      if (cols == 1) cThrust = new FGTable(rows);
      else           cThrust = new FGTable(rows, cols);
      *cThrust << *Prop_cfg;
    } else if (token == "C_POWER") {
      *Prop_cfg >> rows >> cols;
      if (cols == 1) cPower = new FGTable(rows);
      else           cPower = new FGTable(rows, cols);
      *cPower << *Prop_cfg;
    } else if (token == "EOF") {
      cerr << "      End of file reached" <<  endl;
      break;
    } else {
      cerr << "Unhandled token in Propeller config file: " << token << endl;
    }
  }

  Type = ttPropeller;
  RPM = 0;
  vTorque.InitMatrix();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGPropeller::~FGPropeller()
{
  if (cThrust)    delete cThrust;
  if (cPower)     delete cPower;
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
// We need the velocity with respect to the wind.
//
// Note that PowerAvailable is the excess power available after the drag of the
// propeller has been subtracted. At equilibrium, PowerAvailable will be zero -
// indicating that the propeller will not accelerate or decelerate.
// Remembering that Torque * omega = Power, we can derive the torque on the
// propeller and its acceleration to give a new RPM. The current RPM will be
// used to calculate thrust.
//
// Because RPM could be zero, we need to be creative about what RPM is stated as.

double FGPropeller::Calculate(double PowerAvailable)
{
  double J, C_Thrust, omega;
  double Vel = fdmex->GetTranslation()->GetvAeroUVW(eU);
  double rho = fdmex->GetAtmosphere()->GetDensity();
  double RPS = RPM/60.0;
  double alpha, beta;

  if (RPM > 0.10) {
    J = Vel / (Diameter * RPS);
  } else {
    J = 0.0;
  }

  if (MaxPitch == MinPitch) { // Fixed pitch prop
    C_Thrust = cThrust->GetValue(J);
  } else {                    // Variable pitch prop
    C_Thrust = cThrust->GetValue(J, Pitch);
  }

  if (P_Factor > 0.0001) {
    alpha = fdmex->GetTranslation()->Getalpha();
    beta  = fdmex->GetTranslation()->Getbeta();
    SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
    SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
  } else if (P_Factor < 0.000) {
    cerr << "P-Factor value in config file must be greater than zero" << endl;
  }

  Thrust = C_Thrust*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho;
  omega = RPS*2.0*M_PI;

  // Check for windmilling.
  double radius = Diameter * 0.375; // 75% of radius
  double windmill_cutoff = tan(Pitch * 1.745329E-2) * omega * radius;
  if (Vel > windmill_cutoff) {
    cout << "Windmilling: " << Vel << " > " << windmill_cutoff << endl;
    Thrust = -Thrust;
  }

  vFn(1) = Thrust;

  // The Ixx value and rotation speed given below are for rotation about the
  // natural axis of the engine. The transform takes place in the base class
  // FGForce::GetBodyForces() function.

  vH(eX) = Ixx*omega*Sense;
  vH(eY) = 0.0;
  vH(eZ) = 0.0;

  if (omega <= 5) omega = 1.0;

  ExcessTorque = PowerAvailable / omega;
  RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;

  vMn = fdmex->GetRotation()->GetPQR()*vH + vTorque*Sense;

  return Thrust; // return thrust in pounds
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

double FGPropeller::GetPowerRequired(void)
{
  if (RPM <= 0.10) return 0.0; // If the prop ain't turnin', the fuel ain't burnin'.

  double cPReq, RPS = RPM / 60.0;

  double J = fdmex->GetTranslation()->GetvAeroUVW(eU) / (Diameter * RPS);
  double rho = fdmex->GetAtmosphere()->GetDensity();

  if (MaxPitch == MinPitch) { // Fixed pitch prop
    Pitch = MinPitch;
    cPReq = cPower->GetValue(J);
  } else {                    // Variable pitch prop
    double advance = fdmex->GetFCS()->GetPropAdvance(ThrusterNumber);

    if (MaxRPM != MinRPM) {   // fixed-speed prop
      double rpmReq = MinRPM + (MaxRPM - MinRPM) * advance;
      double dRPM = rpmReq - RPM;

      Pitch -= dRPM / 10;

      if (Pitch < MinPitch)       Pitch = MinPitch;
      else if (Pitch > MaxPitch)  Pitch = MaxPitch;

    } else {
      Pitch = MaxPitch - (MaxPitch - MinPitch) * advance;
    }
    cPReq = cPower->GetValue(J, Pitch);
  }

  PowerRequired = cPReq*RPS*RPS*RPS*Diameter*Diameter*Diameter*Diameter
                                                       *Diameter*rho;
  vTorque(eX) = -Sense*PowerRequired / (RPS*2.0*M_PI);

  return PowerRequired;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGColumnVector3 FGPropeller::GetPFactor()
{
  double px=0.0, py, pz;

  py = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
  pz = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;

  return FGColumnVector3(px, py, pz);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGPropeller::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      cout << "\n    Propeller Name: " << Name << endl;
      cout << "      IXX = " << Ixx << endl;
      cout << "      Diameter = " << Diameter << " ft." << endl;
      cout << "      Number of Blades  = " << numBlades << endl;
      cout << "      Minimum Pitch  = " << MinPitch << endl;
      cout << "      Maximum Pitch  = " << MaxPitch << endl;
      cout << "      Thrust Coefficient: " <<  endl;
      cThrust->Print();
      cout << "      Power Coefficient: " <<  endl;
      cPower->Print();
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGPropeller" << endl;
    if (from == 1) cout << "Destroyed:    FGPropeller" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}

<|endoftext|>


<commit_before>#include "GraphReader.h"

#include "Graph.h"

#include <stdio.h>
#include <fstream>
#include <iostream>

using namespace ADS;
using namespace std;

namespace ADS
{
    int parseLine (const string &line, Graph<unsigned int> *pGraph, bool &bFoundEndOfFile)
    {
        unsigned int uiSrc, uiDst, uiCost;
        char str[1];
        if (line.length() <= 0 || pGraph == NULL) {
            return -1;
        }
        if (sscanf (line.c_str(), "%d %d %d", &uiSrc, &uiDst, &uiCost) == 3) {
            /* srcVertex dstVertex edgeCost */
            if (!pGraph->addEdge (uiSrc, uiDst, uiCost))
                return -2;
        }
        else if (line.length() == 1 && sscanf (line.c_str(), "%s", str) > 0 && (strcmp (str, "*") == 0)) {
            /* end of input */
            bFoundEndOfFile = true;
            return 0;
        }
        else {
            printf ("Invalid: %s\n", line.c_str());
            return -3;
        }
        return 0;
    }

    int readStream (istream &stream, Graph<unsigned int> *pGraph, bool &bFoundEndOfFile)
    {
        for (std::string line; std::getline (stream, line);)
            if (parseLine (line, pGraph, bFoundEndOfFile) < 0)
                return -1;
        return 0;
    }
}

GraphReader::GraphReader (const char *pszFileName)
    : _fileName (pszFileName)
{
}

GraphReader::~GraphReader (void)
{
}

bool GraphReader::read (Graph<unsigned int> *pGraph)
{
    if (pGraph == NULL)
        return false;

    bool bFoundEndOfFile = false;
    if (_fileName.length() <= 0) {
        readStream (std::cin, pGraph, bFoundEndOfFile);
    }
    else {
        std::ifstream graphFile (_fileName, std::ifstream::in);
        readStream (graphFile, pGraph, bFoundEndOfFile);
        graphFile.close();
    }

    return bFoundEndOfFile;
}

<commit_msg>Added missing include.<commit_after>#include "GraphReader.h"

#include "Graph.h"

#include <stdio.h>
#include <fstream>
#include <iostream>
#include <string.h>

using namespace ADS;
using namespace std;

namespace ADS
{
    int parseLine (const string &line, Graph<unsigned int> *pGraph, bool &bFoundEndOfFile)
    {
        unsigned int uiSrc, uiDst, uiCost;
        if (line.length() <= 0 || pGraph == NULL) {
            return -1;
        }
        if (sscanf (line.c_str(), "%d %d %d", &uiSrc, &uiDst, &uiCost) == 3) {
            /* srcVertex dstVertex edgeCost */
            if (!pGraph->addEdge (uiSrc, uiDst, uiCost))
                return -2;
        }
        else if (line.length() == 1 && (strcmp (line.c_str(), "*") == 0)) {
            /* end of input */
            bFoundEndOfFile = true;
            return 0;
        }
        else {
            printf ("Invalid: %s\n", line.c_str());
            return -3;
        }
        return 0;
    }

    int readStream (istream &stream, Graph<unsigned int> *pGraph, bool &bFoundEndOfFile)
    {
        for (std::string line; std::getline (stream, line);)
            if (parseLine (line, pGraph, bFoundEndOfFile) < 0)
                return -1;
        return 0;
    }
}

GraphReader::GraphReader (const char *pszFileName)
    : _fileName (pszFileName)
{
}

GraphReader::~GraphReader (void)
{
}

bool GraphReader::read (Graph<unsigned int> *pGraph)
{
    if (pGraph == NULL)
        return false;

    bool bFoundEndOfFile = false;
    if (_fileName.length() <= 0) {
        readStream (std::cin, pGraph, bFoundEndOfFile);
    }
    else {
        std::ifstream graphFile (_fileName, std::ifstream::in);
        readStream (graphFile, pGraph, bFoundEndOfFile);
        graphFile.close();
    }

    return bFoundEndOfFile;
}

<|endoftext|>


<commit_before>#include "Includes.h"
#include "MainWindow.h"
#include "WeatherInfo.h"
#include "WeatherLoad.h"

// Переменные и функции для главного окна приложения
static HDC hdc; // хэндл контекста устройства

// Меню окна и подменю "Файл", "Вид"
HMENU hMainMenu, hFileMenu, hViewMenu;

// Высота строки меню в пикселях - для перестроения окна
static INT32 nMenuHeight;

// Элемент ListView
HWND hLstWeather;

// Вектор данных для обработки - вектор объектов класса Student
WeatherLoad weather;

// Стандартный диалог открытия файла
OPENFILENAME ofn;

LOGFONT lf;
COLORREF colfont;
CHOOSEFONT cfont;
HFONT font;
HANDLE hOldFont;

CHOOSECOLOR ccol;
COLORREF clf;
COLORREF clfusers[16];

// Оконная функция - обработка сообщений, получаемых окном
// hwnd - дескриптор окна
// msg - числовой код сообщения
// wParam - первая часть параметров сообщения
// lParam - вторая часть параметров сообщения
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
		HANDLE_MSG(hwnd, WM_CREATE, OnCreate);  // создание окна
		HANDLE_MSG(hwnd, WM_SIZE, OnSize);      // Изменение размера экрана
		HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
		HANDLE_MSG(hwnd, WM_CLOSE, OnClose);
		HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);
		HANDLE_MSG(hwnd, WM_GETMINMAXINFO, OnGetMinMaxInfo);
		HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
		HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, OnCtlColorStatic);

		// Обработка сообщений для которых не предусмотрена обработка в нашем окне
		default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	} // switch

	return 0;
} // WndProc

// Обработчик сообщения WM_CREATE - обработчик события "При создании"
// нашего окна
BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
	RECT rect;
	GetClientRect(hwnd, &rect);

	#pragma region Ñîçäàíèå ìåíþ
	hMainMenu = CreateMenu();
	hFileMenu = CreatePopupMenu();
	hViewMenu = CreatePopupMenu();

	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFileMenu, _T("&Файл"));
	AppendMenu(hFileMenu, MF_STRING, IDC_OPEN, _T("&Открыть..."));
	AppendMenu(hFileMenu, MF_SEPARATOR, NULL, _T(""));
	AppendMenu(hFileMenu, MF_STRING, IDC_QUIT, _T("Вы&ход"));

	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT_PTR)hViewMenu, _T("&Вид"));
	AppendMenu(hViewMenu, MF_STRING, IDC_FONT, _T("&Шрифт текста"));
	AppendMenu(hViewMenu, MF_STRING, IDC_COLOR, _T("Ц&вет фона..."));
	SetMenu(hwnd, hMainMenu);

	// Получить высоту строки меню в пикселах
	nMenuHeight = GetSystemMetrics(SM_CYMENU);
	#pragma endregion

	#pragma region Создание элемента ListView
	hLstWeather = CreateWindowEx(0, WC_LISTVIEW, NULL,
		WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | LVS_ALIGNLEFT,
		rect.left + 10, rect.top + 10, rect.right - 20, rect.bottom - nMenuHeight,
		hwnd, (HMENU)IDC_LISTVIEW, lpCreateStruct->hInstance, NULL);
	// SendMessage(hLstStudents, WM_SETFONT, WPARAM(hFontList), NULL);

	// Добавление столбцов
	LV_COLUMN lvCol;
	ZeroMemory(&lvCol, sizeof(LV_COLUMN));

	// Добавление 0-го столбца - Фамилия и инициалы
	lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvCol.fmt  = LVCFMT_LEFT;
	lvCol.cx   = (rect.right - rect.left - 20) / 5;

	lvCol.iSubItem = 0;
	lvCol.pszText  = _T("Город");
	ListView_InsertColumn(hLstWeather, 0, &lvCol);

	// Теперь добавляем подэлементы
	lvCol.iSubItem = 1;
	lvCol.pszText  = _T("Направление ветра");
	ListView_InsertColumn(hLstWeather, 1, &lvCol);

	lvCol.iSubItem = 2;
	lvCol.pszText  = _T("Скорость ветра, м/с");
	ListView_InsertColumn(hLstWeather, 2, &lvCol);

	lvCol.iSubItem = 3;
	lvCol.pszText  = _T("Макс. днев. темпер.");
	ListView_InsertColumn(hLstWeather, 3, &lvCol);

	lvCol.iSubItem = 4;
	lvCol.pszText  = _T("Мин. ноч. темпер.");
	ListView_InsertColumn(hLstWeather, 4, &lvCol);

	ListView_SetExtendedListViewStyle(hLstWeather,
		ListView_GetExtendedListViewStyle(hLstWeather) | LVS_EX_FULLROWSELECT);
	#pragma endregion

	// Загрузка данных из файла
	weather = WeatherLoad(_T("Метеоданные.txt"));
	weather.LoadFromFile();

	// Вывод вектора студентов в элемент ListView
	weather.ListView(hLstWeather);

	#pragma region Создание диалога открытия файла
	static TCHAR fileName[256];
	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = hwnd;
	ofn.lpstrFile = fileName;
	ofn.nMaxFile = sizeof(fileName);
	ofn.lpstrFilter = _T("Текстовые файлы (*.txt)\0*.txt\0CSV-файлы (*.csv)\0*.csv\0Все файлы (*.*)\0*.*\0");
	ofn.nFilterIndex = 1;
	ofn.lpstrInitialDir = _T(".");  // текущий каталог/текущая папка
	ofn.lpstrDefExt = _T("txt");
	#pragma endregion

	#pragma region Создание диалога выбора шрифта
	colfont = RGB(0, 0, 0);
	lf.lfHeight = 13;
	lf.lfWidth = 13;
	lf.lfEscapement = 0;
	lf.lfOrientation = 0;
	lf.lfItalic = 0;
	lf.lfUnderline = 0;
	lf.lfStrikeOut = 0;
	lf.lfWeight = FW_NORMAL;
	lf.lfCharSet = RUSSIAN_CHARSET;
	_tcscpy(lf.lfFaceName, _T("Calibri"));
	cfont.lStructSize = sizeof(CHOOSEFONT);
	cfont.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
	#pragma endregion

	#pragma region Создание диалога выбора цвета
	ccol.lStructSize = sizeof(CHOOSECOLOR);
	ccol.Flags = CC_RGBINIT;
	ccol.lpCustColors = clfusers;
	clf = RGB(255, 255, 255);
	#pragma endregion

	return TRUE;
} // OnCreate

// Обработчик сообщения WM_SIZE - обработчик события "При изменении размера"
// нашего окна
void OnSize(HWND hwnd, UINT state, int cx, int cy)
{
	RECT rect; // Прямоугольник - для хранения координат рабочей области окна
	INT32 nWidth; // Ширина столбца элемента ListView

	GetClientRect(hwnd, &rect);         // Задать область окна для перерисовки

	// Новый размер ListView
	MoveWindow(hLstWeather, 10, 10, rect.right - 20, rect.bottom - nMenuHeight - 10, TRUE);

	// Послать сообщения ListView для установки ширины столбцов
	nWidth = (rect.right - 20) / 5;
	for (size_t i = 0; i < 5; i++)
		ListView_SetColumnWidth(hLstWeather, i, nWidth);

	InvalidateRect(hwnd, &rect, TRUE);   // Объявить область недействительной => формируется WM_PAINT
} // OnSize

// Обработчик сообщения WM_PAINT - обработчик события "При отрисовке"
void OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps; // Параметры контекста устройства
	RECT rect; // Прямоугольник - для хранения координат рабочей области окна

	hdc = BeginPaint(hwnd, &ps); // Получить хэндл контекста устройства

	font = CreateFontIndirect(&lf);
	hOldFont = SelectObject(hdc, font);
	SetTextColor(hdc, colfont);
	TextOut(hdc, 20, 20, lf.lfFaceName, _tcslen(lf.lfFaceName));
	SelectObject(hdc, hOldFont);
	DeleteObject(font);

	GetClientRect(hwnd, &rect); // Получить координаты области для рисования

	EndPaint(hwnd, &ps); // Освободить контекст для корректной работы системыû
} // OnPaint

// Обработчик сообщения WM_CLOSE - обработчик события "При закрытии окна"
void OnClose(HWND hwnd)
{
	DestroyWindow(hwnd);
} // OnClose

// Обработчик сообщения WM_DESTROY - обработчик события "При уничтожении окна"
void OnDestroy(HWND hwnd)
{
	PostQuitMessage(0);
} // OnDestroy

// Ограничение минимального размера главного окна приложения
// !! Работает вместе с OnSize !!
void OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo)
{
	lpMinMaxInfo->ptMinTrackSize = { 480, 240 };
} // OnGetMinMaxInfo

// Обработка сообщений WM_COMMAND - они посылаются от элементов управления
// в частности - от кнопок
void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	BOOL bResult;

	switch (id) {
		// Выбор файла данных при помощи стандартного диалога и
		// вывод данных из этого файла
	case IDC_OPEN:
		ofn.Flags = OFN_EXPLORER;
		bResult = GetOpenFileName(&ofn);
		if (!bResult) break;

		weather.SetFileName(wstring(ofn.lpstrFile));
		weather.LoadFromFile();
		weather.ListView(hLstWeather);
		break;

		// Выбор шрифта для вывода текста в ListView и установка шрифта
	case IDC_FONT:
		cfont.lpLogFont = &lf;
		cfont.rgbColors = colfont;
		if (ChooseFont(&cfont)) {
			lf = *cfont.lpLogFont;
			colfont = cfont.rgbColors;
			ListView_SetTextColor(hLstWeather, colfont);
			SendMessage(hLstWeather, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), TRUE);
		} // if
		break;

		// Выбор цвета для вывода текста в ListtView и установка цвета
	case IDC_COLOR:
		ccol.rgbResult = clf;
		if (ChooseColor(&ccol)) {
			clf = ccol.rgbResult;
			ListView_SetTextBkColor(hLstWeather, clf);
			RECT rt;
			GetClientRect(hLstWeather, &rt);
			InvalidateRect(hLstWeather, &rt, TRUE);
		} // if
		break;

	case IDC_QUIT:
		PostQuitMessage(0);
		break;
	} // switch
} // OnCommand

// Отрисовка фона статического управляющего элемента
// Фон - совпадает с фоном рабочей области окна
HBRUSH OnCtlColorStatic(HWND, HDC hdc, HWND, int)
{
	SetBkMode(hdc, TRANSPARENT);
	return CreateSolidBrush(BACKGROUND);
} // OnCtlColorStatic
<commit_msg>Convert encoding Windows-1251 to UTF-8<commit_after>#include "Includes.h"
#include "MainWindow.h"
#include "WeatherInfo.h"
#include "WeatherLoad.h"

// Переменные и функции для главного окна приложения
static HDC hdc; // хэндл контекста устройства

// Меню окна и подменю "Файл", "Вид"
HMENU hMainMenu, hFileMenu, hViewMenu;

// Высота строки меню в пикселях - для перестроения окна
static INT32 nMenuHeight;

// Элемент ListView
HWND hLstWeather;

// Вектор данных для обработки - вектор объектов класса Student
WeatherLoad weather;

// Стандартный диалог открытия файла
OPENFILENAME ofn;

LOGFONT lf;
COLORREF colfont;
CHOOSEFONT cfont;
HFONT font;
HANDLE hOldFont;

CHOOSECOLOR ccol;
COLORREF clf;
COLORREF clfusers[16];

// Оконная функция - обработка сообщений, получаемых окном
// hwnd - дескриптор окна
// msg - числовой код сообщения
// wParam - первая часть параметров сообщения
// lParam - вторая часть параметров сообщения
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
		HANDLE_MSG(hwnd, WM_CREATE, OnCreate);  // создание окна
		HANDLE_MSG(hwnd, WM_SIZE, OnSize);      // Изменение размера экрана
		HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
		HANDLE_MSG(hwnd, WM_CLOSE, OnClose);
		HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);
		HANDLE_MSG(hwnd, WM_GETMINMAXINFO, OnGetMinMaxInfo);
		HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
		HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, OnCtlColorStatic);

		// Обработка сообщений для которых не предусмотрена обработка в нашем окне
		default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	} // switch

	return 0;
} // WndProc

// Обработчик сообщения WM_CREATE - обработчик события "При создании"
// нашего окна
BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
	RECT rect;
	GetClientRect(hwnd, &rect);

	#pragma region Создание меню
	hMainMenu = CreateMenu();
	hFileMenu = CreatePopupMenu();
	hViewMenu = CreatePopupMenu();

	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFileMenu, _T("&Файл"));
	AppendMenu(hFileMenu, MF_STRING, IDC_OPEN, _T("&Открыть..."));
	AppendMenu(hFileMenu, MF_SEPARATOR, NULL, _T(""));
	AppendMenu(hFileMenu, MF_STRING, IDC_QUIT, _T("Вы&ход"));

	AppendMenu(hMainMenu, MF_STRING | MF_POPUP, (UINT_PTR)hViewMenu, _T("&Вид"));
	AppendMenu(hViewMenu, MF_STRING, IDC_FONT, _T("&Шрифт текста"));
	AppendMenu(hViewMenu, MF_STRING, IDC_COLOR, _T("Ц&вет фона..."));
	SetMenu(hwnd, hMainMenu);

	// Получить высоту строки меню в пикселах
	nMenuHeight = GetSystemMetrics(SM_CYMENU);
	#pragma endregion

	#pragma region Создание элемента ListView
	hLstWeather = CreateWindowEx(0, WC_LISTVIEW, NULL,
		WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | LVS_ALIGNLEFT,
		rect.left + 10, rect.top + 10, rect.right - 20, rect.bottom - nMenuHeight,
		hwnd, (HMENU)IDC_LISTVIEW, lpCreateStruct->hInstance, NULL);
	// SendMessage(hLstStudents, WM_SETFONT, WPARAM(hFontList), NULL);

	// Добавление столбцов
	LV_COLUMN lvCol;
	ZeroMemory(&lvCol, sizeof(LV_COLUMN));

	// Добавление 0-го столбца - Фамилия и инициалы
	lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvCol.fmt  = LVCFMT_LEFT;
	lvCol.cx   = (rect.right - rect.left - 20) / 5;

	lvCol.iSubItem = 0;
	lvCol.pszText  = _T("Город");
	ListView_InsertColumn(hLstWeather, 0, &lvCol);

	// Теперь добавляем подэлементы
	lvCol.iSubItem = 1;
	lvCol.pszText  = _T("Направление ветра");
	ListView_InsertColumn(hLstWeather, 1, &lvCol);

	lvCol.iSubItem = 2;
	lvCol.pszText  = _T("Скорость ветра, м/с");
	ListView_InsertColumn(hLstWeather, 2, &lvCol);

	lvCol.iSubItem = 3;
	lvCol.pszText  = _T("Макс. днев. темпер.");
	ListView_InsertColumn(hLstWeather, 3, &lvCol);

	lvCol.iSubItem = 4;
	lvCol.pszText  = _T("Мин. ноч. темпер.");
	ListView_InsertColumn(hLstWeather, 4, &lvCol);

	ListView_SetExtendedListViewStyle(hLstWeather,
		ListView_GetExtendedListViewStyle(hLstWeather) | LVS_EX_FULLROWSELECT);
	#pragma endregion

	// Загрузка данных из файла
	weather = WeatherLoad(_T("Метеоданные.txt"));
	weather.LoadFromFile();

	// Вывод вектора студентов в элемент ListView
	weather.ListView(hLstWeather);

	#pragma region Создание диалога открытия файла
	static TCHAR fileName[256];
	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = hwnd;
	ofn.lpstrFile = fileName;
	ofn.nMaxFile = sizeof(fileName);
	ofn.lpstrFilter = _T("Текстовые файлы (*.txt)\0*.txt\0CSV-файлы (*.csv)\0*.csv\0Все файлы (*.*)\0*.*\0");
	ofn.nFilterIndex = 1;
	ofn.lpstrInitialDir = _T(".");  // текущий каталог/текущая папка
	ofn.lpstrDefExt = _T("txt");
	#pragma endregion

	#pragma region Создание диалога выбора шрифта
	colfont = RGB(0, 0, 0);
	lf.lfHeight = 13;
	lf.lfWidth = 13;
	lf.lfEscapement = 0;
	lf.lfOrientation = 0;
	lf.lfItalic = 0;
	lf.lfUnderline = 0;
	lf.lfStrikeOut = 0;
	lf.lfWeight = FW_NORMAL;
	lf.lfCharSet = RUSSIAN_CHARSET;
	_tcscpy(lf.lfFaceName, _T("Calibri"));
	cfont.lStructSize = sizeof(CHOOSEFONT);
	cfont.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
	#pragma endregion

	#pragma region Создание диалога выбора цвета
	ccol.lStructSize = sizeof(CHOOSECOLOR);
	ccol.Flags = CC_RGBINIT;
	ccol.lpCustColors = clfusers;
	clf = RGB(255, 255, 255);
	#pragma endregion

	return TRUE;
} // OnCreate

// Обработчик сообщения WM_SIZE - обработчик события "При изменении размера"
// нашего окна
void OnSize(HWND hwnd, UINT state, int cx, int cy)
{
	RECT rect; // Прямоугольник - для хранения координат рабочей области окна
	INT32 nWidth; // Ширина столбца элемента ListView

	GetClientRect(hwnd, &rect);         // Задать область окна для перерисовки

	// Новый размер ListView
	MoveWindow(hLstWeather, 10, 10, rect.right - 20, rect.bottom - nMenuHeight - 10, TRUE);

	// Послать сообщения ListView для установки ширины столбцов
	nWidth = (rect.right - 20) / 5;
	for (size_t i = 0; i < 5; i++)
		ListView_SetColumnWidth(hLstWeather, i, nWidth);

	InvalidateRect(hwnd, &rect, TRUE);   // Объявить область недействительной => формируется WM_PAINT
} // OnSize

// Обработчик сообщения WM_PAINT - обработчик события "При отрисовке"
void OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps; // Параметры контекста устройства
	RECT rect; // Прямоугольник - для хранения координат рабочей области окна

	hdc = BeginPaint(hwnd, &ps); // Получить хэндл контекста устройства

	font = CreateFontIndirect(&lf);
	hOldFont = SelectObject(hdc, font);
	SetTextColor(hdc, colfont);
	TextOut(hdc, 20, 20, lf.lfFaceName, _tcslen(lf.lfFaceName));
	SelectObject(hdc, hOldFont);
	DeleteObject(font);

	GetClientRect(hwnd, &rect); // Получить координаты области для рисования

	EndPaint(hwnd, &ps); // Освободить контекст для корректной работы системыû
} // OnPaint

// Обработчик сообщения WM_CLOSE - обработчик события "При закрытии окна"
void OnClose(HWND hwnd)
{
	DestroyWindow(hwnd);
} // OnClose

// Обработчик сообщения WM_DESTROY - обработчик события "При уничтожении окна"
void OnDestroy(HWND hwnd)
{
	PostQuitMessage(0);
} // OnDestroy

// Ограничение минимального размера главного окна приложения
// !! Работает вместе с OnSize !!
void OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo)
{
	lpMinMaxInfo->ptMinTrackSize = { 480, 240 };
} // OnGetMinMaxInfo

// Обработка сообщений WM_COMMAND - они посылаются от элементов управления
// в частности - от кнопок
void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	BOOL bResult;

	switch (id) {
		// Выбор файла данных при помощи стандартного диалога и
		// вывод данных из этого файла
	case IDC_OPEN:
		ofn.Flags = OFN_EXPLORER;
		bResult = GetOpenFileName(&ofn);
		if (!bResult) break;

		weather.SetFileName(wstring(ofn.lpstrFile));
		weather.LoadFromFile();
		weather.ListView(hLstWeather);
		break;

		// Выбор шрифта для вывода текста в ListView и установка шрифта
	case IDC_FONT:
		cfont.lpLogFont = &lf;
		cfont.rgbColors = colfont;
		if (ChooseFont(&cfont)) {
			lf = *cfont.lpLogFont;
			colfont = cfont.rgbColors;
			ListView_SetTextColor(hLstWeather, colfont);
			SendMessage(hLstWeather, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), TRUE);
		} // if
		break;

		// Выбор цвета для вывода текста в ListtView и установка цвета
	case IDC_COLOR:
		ccol.rgbResult = clf;
		if (ChooseColor(&ccol)) {
			clf = ccol.rgbResult;
			ListView_SetTextBkColor(hLstWeather, clf);
			RECT rt;
			GetClientRect(hLstWeather, &rt);
			InvalidateRect(hLstWeather, &rt, TRUE);
		} // if
		break;

	case IDC_QUIT:
		PostQuitMessage(0);
		break;
	} // switch
} // OnCommand

// Отрисовка фона статического управляющего элемента
// Фон - совпадает с фоном рабочей области окна
HBRUSH OnCtlColorStatic(HWND, HDC hdc, HWND, int)
{
	SetBkMode(hdc, TRANSPARENT);
	return CreateSolidBrush(BACKGROUND);
} // OnCtlColorStatic
<|endoftext|>


<commit_before>/*
* Copyright (C) 2012 David Edmundson <kde@davidedmundson.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "contact.h"

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactCapabilities>
#include <TelepathyQt/AvatarData>
#include <TelepathyQt/Utils>

#include <QBitmap>
#include <QPixmap>
#include <QPixmapCache>

#include <KIconLoader>
#include <KConfigGroup>
#include <KConfig>

#include "capabilities-hack-private.h"

KTp::Contact::Contact(Tp::ContactManager *manager, const Tp::ReferencedHandles &handle, const Tp::Features &requestedFeatures, const QVariantMap &attributes)
    : Tp::Contact(manager, handle, requestedFeatures, attributes)
{
    connect(manager->connection().data(), SIGNAL(destroyed()), SIGNAL(invalidated()));
    connect(manager->connection().data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));
    connect(this, SIGNAL(avatarTokenChanged(QString)), SLOT(invalidateAvatarCache()));
    connect(this, SIGNAL(avatarDataChanged(Tp::AvatarData)), SLOT(invalidateAvatarCache()));
}

KTp::Presence KTp::Contact::presence() const
{
    return KTp::Presence(Tp::Contact::presence());
}

bool KTp::Contact::audioCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamAudio && selfCanStreamAudio;
    }
    return false;
}

bool KTp::Contact::videoCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamVideo && selfCanStreamVideo;
    }

    return false;
}

bool KTp::Contact::fileTransferCapability()  const
{
    if (! manager()->connection()) {
        return false;
    }
    if (manager()->connection()) {
        bool contactCanHandleFiles = capabilities().fileTransfers();
        bool selfCanHandleFiles = manager()->connection()->selfContact()->capabilities().fileTransfers();
        return contactCanHandleFiles && selfCanHandleFiles;
    }

    return false;
}

QStringList KTp::Contact::clientTypes() const
{
    /* Temporary workaround for upstream bug https://bugs.freedesktop.org/show_bug.cgi?id=55883)
     * Close https://bugs.kde.org/show_bug.cgi?id=308217 when fixed upstream */
    if (Tp::Contact::presence().type() == Tp::ConnectionPresenceTypeOffline) {
        return QStringList();
    }

    return Tp::Contact::clientTypes();
}

QPixmap KTp::Contact::avatarPixmap()
{
    QPixmap avatar;

    //check pixmap cache for the avatar, if not present, load the avatar
    if (!QPixmapCache::find(keyCache(), avatar)){
        QString file = avatarData().fileName;

        //if contact does not provide path, let's see if we have avatar for the stored token
        if (file.isEmpty()) {
            KConfig config(QLatin1String("ktelepathy-avatarsrc"));
            KConfigGroup avatarTokenGroup = config.group(id());
            QString avatarToken = avatarTokenGroup.readEntry(QLatin1String("avatarToken"));
            //only bother loading the pixmap if the token is not empty
            if (!avatarToken.isEmpty()) {
                avatar.load(buildAvatarPath(avatarToken));
            }
        } else {
            avatar.load(file);
        }

        //if neither above succeeded, we need to load the icon
        if (avatar.isNull()) {
            avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
        }

        //if the contact is offline, gray it out
        if (presence().type() == Tp::ConnectionPresenceTypeOffline) {
            avatarToGray(avatar);
        }

        //insert the contact into pixmap cache for faster lookup
        QPixmapCache::insert(keyCache(), avatar);
    }

    return avatar;
}

void KTp::Contact::avatarToGray(QPixmap &avatar)
{
    QImage image = avatar.toImage();
    QPixmap alpha= avatar.alphaChannel();
    for (int i = 0; i < image.width(); ++i) {
        for (int j = 0; j < image.height(); ++j) {
            int colour = qGray(image.pixel(i, j));
            image.setPixel(i, j, qRgb(colour, colour, colour));
        }
    }
    avatar = avatar.fromImage(image);
    avatar.setAlphaChannel(alpha);
}

QString KTp::Contact::keyCache() const
{
    return id() + (presence().type() == Tp::ConnectionPresenceTypeOffline ? QLatin1String("-offline") : QLatin1String("-online"));
}

QString KTp::Contact::buildAvatarPath(const QString &avatarToken)
{
    QString cacheDir = QString::fromLatin1(qgetenv("XDG_CACHE_HOME"));
    if (cacheDir.isEmpty()) {
        cacheDir = QString::fromLatin1("%1/.cache").arg(QLatin1String(qgetenv("HOME")));
    }

    if (manager().isNull()) {
        return QString();
    }

    if (manager()->connection().isNull()) {
        return QString();
    }

    Tp::ConnectionPtr conn = manager()->connection();
    QString path = QString::fromLatin1("%1/telepathy/avatars/%2/%3").
        arg(cacheDir).arg(conn->cmName()).arg(conn->protocolName());

    QString avatarFileName = QString::fromLatin1("%1/%2").arg(path).arg(Tp::escapeAsIdentifier(avatarToken));

    return avatarFileName;
}

void KTp::Contact::invalidateAvatarCache()
{
    QPixmapCache::remove(id() + QLatin1String("-offline"));
    QPixmapCache::remove(id() + QLatin1String("-online"));
}
<commit_msg>Supress warnings about invalid ClientTypes<commit_after>/*
* Copyright (C) 2012 David Edmundson <kde@davidedmundson.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "contact.h"

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactCapabilities>
#include <TelepathyQt/AvatarData>
#include <TelepathyQt/Utils>

#include <QBitmap>
#include <QPixmap>
#include <QPixmapCache>

#include <KIconLoader>
#include <KConfigGroup>
#include <KConfig>

#include "capabilities-hack-private.h"

KTp::Contact::Contact(Tp::ContactManager *manager, const Tp::ReferencedHandles &handle, const Tp::Features &requestedFeatures, const QVariantMap &attributes)
    : Tp::Contact(manager, handle, requestedFeatures, attributes)
{
    connect(manager->connection().data(), SIGNAL(destroyed()), SIGNAL(invalidated()));
    connect(manager->connection().data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));
    connect(this, SIGNAL(avatarTokenChanged(QString)), SLOT(invalidateAvatarCache()));
    connect(this, SIGNAL(avatarDataChanged(Tp::AvatarData)), SLOT(invalidateAvatarCache()));
}

KTp::Presence KTp::Contact::presence() const
{
    return KTp::Presence(Tp::Contact::presence());
}

bool KTp::Contact::audioCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamAudio && selfCanStreamAudio;
    }
    return false;
}

bool KTp::Contact::videoCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamVideo && selfCanStreamVideo;
    }

    return false;
}

bool KTp::Contact::fileTransferCapability()  const
{
    if (! manager()->connection()) {
        return false;
    }
    if (manager()->connection()) {
        bool contactCanHandleFiles = capabilities().fileTransfers();
        bool selfCanHandleFiles = manager()->connection()->selfContact()->capabilities().fileTransfers();
        return contactCanHandleFiles && selfCanHandleFiles;
    }

    return false;
}

QStringList KTp::Contact::clientTypes() const
{
    /* Temporary workaround for upstream bug https://bugs.freedesktop.org/show_bug.cgi?id=55883)
     * Close https://bugs.kde.org/show_bug.cgi?id=308217 when fixed upstream */
    if (Tp::Contact::presence().type() == Tp::ConnectionPresenceTypeOffline) {
        return QStringList();
    }

    //supress any errors trying to access ClientTypes when we don't have them
    if (! actualFeatures().contains(Tp::Contact::FeatureClientTypes)) {
        return QStringList();
    }

    return Tp::Contact::clientTypes();
}

QPixmap KTp::Contact::avatarPixmap()
{
    QPixmap avatar;

    //check pixmap cache for the avatar, if not present, load the avatar
    if (!QPixmapCache::find(keyCache(), avatar)){
        QString file = avatarData().fileName;

        //if contact does not provide path, let's see if we have avatar for the stored token
        if (file.isEmpty()) {
            KConfig config(QLatin1String("ktelepathy-avatarsrc"));
            KConfigGroup avatarTokenGroup = config.group(id());
            QString avatarToken = avatarTokenGroup.readEntry(QLatin1String("avatarToken"));
            //only bother loading the pixmap if the token is not empty
            if (!avatarToken.isEmpty()) {
                avatar.load(buildAvatarPath(avatarToken));
            }
        } else {
            avatar.load(file);
        }

        //if neither above succeeded, we need to load the icon
        if (avatar.isNull()) {
            avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
        }

        //if the contact is offline, gray it out
        if (presence().type() == Tp::ConnectionPresenceTypeOffline) {
            avatarToGray(avatar);
        }

        //insert the contact into pixmap cache for faster lookup
        QPixmapCache::insert(keyCache(), avatar);
    }

    return avatar;
}

void KTp::Contact::avatarToGray(QPixmap &avatar)
{
    QImage image = avatar.toImage();
    QPixmap alpha= avatar.alphaChannel();
    for (int i = 0; i < image.width(); ++i) {
        for (int j = 0; j < image.height(); ++j) {
            int colour = qGray(image.pixel(i, j));
            image.setPixel(i, j, qRgb(colour, colour, colour));
        }
    }
    avatar = avatar.fromImage(image);
    avatar.setAlphaChannel(alpha);
}

QString KTp::Contact::keyCache() const
{
    return id() + (presence().type() == Tp::ConnectionPresenceTypeOffline ? QLatin1String("-offline") : QLatin1String("-online"));
}

QString KTp::Contact::buildAvatarPath(const QString &avatarToken)
{
    QString cacheDir = QString::fromLatin1(qgetenv("XDG_CACHE_HOME"));
    if (cacheDir.isEmpty()) {
        cacheDir = QString::fromLatin1("%1/.cache").arg(QLatin1String(qgetenv("HOME")));
    }

    if (manager().isNull()) {
        return QString();
    }

    if (manager()->connection().isNull()) {
        return QString();
    }

    Tp::ConnectionPtr conn = manager()->connection();
    QString path = QString::fromLatin1("%1/telepathy/avatars/%2/%3").
        arg(cacheDir).arg(conn->cmName()).arg(conn->protocolName());

    QString avatarFileName = QString::fromLatin1("%1/%2").arg(path).arg(Tp::escapeAsIdentifier(avatarToken));

    return avatarFileName;
}

void KTp::Contact::invalidateAvatarCache()
{
    QPixmapCache::remove(id() + QLatin1String("-offline"));
    QPixmapCache::remove(id() + QLatin1String("-online"));
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2012  Lasath Fernando <kde@lasath.org>

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "message.h"
#include <KDebug>

Message::Message(const Tp::Message &original)
    : m_originalMessage(original)
{
    setMainMessagePart(original.text());
}

QString Message::mainMessagePart() const
{
    return m_mainPart;
}

void Message::setMainMessagePart(const QString& message)
{
    m_mainPart = message.trimmed();
}

void Message::appendMessagePart(const QString& part)
{
    m_parts << part;
}

QString Message::finalizedMessage() const
{
    QString msg = m_mainPart + QLatin1String("\n") +
        m_parts.join(QLatin1String("\n"));

//     kDebug() << msg;
    return msg;
}

QVariant Message::property(const char *name) const
{
    return m_properties[QLatin1String(name)];
}

void Message::setProperty(const char *name, const QVariant& value)
{
    m_properties[QLatin1String(name)] = value;
}

QDateTime Message::time() const
{
    return m_originalMessage.sent();
}

QString Message::token() const
{
    return m_originalMessage.messageToken();
}

Tp::ChannelTextMessageType Message::type() const
{
    return m_originalMessage.messageType();
}
<commit_msg>Trim only the messages in the filter, not /all/ the messages<commit_after>/*
    Copyright (C) 2012  Lasath Fernando <kde@lasath.org>

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "message.h"
#include <KDebug>

Message::Message(const Tp::Message &original)
    : m_originalMessage(original)
{
    setMainMessagePart(original.text());
}

QString Message::mainMessagePart() const
{
    return m_mainPart;
}

void Message::setMainMessagePart(const QString& message)
{
    m_mainPart = message;
}

void Message::appendMessagePart(const QString& part)
{
    m_parts << part;
}

QString Message::finalizedMessage() const
{
    QString msg = m_mainPart + QLatin1String("\n") +
        m_parts.join(QLatin1String("\n"));

//     kDebug() << msg;
    return msg;
}

QVariant Message::property(const char *name) const
{
    return m_properties[QLatin1String(name)];
}

void Message::setProperty(const char *name, const QVariant& value)
{
    m_properties[QLatin1String(name)] = value;
}

QDateTime Message::time() const
{
    return m_originalMessage.sent();
}

QString Message::token() const
{
    return m_originalMessage.messageToken();
}

Tp::ChannelTextMessageType Message::type() const
{
    return m_originalMessage.messageType();
}
<|endoftext|>


<commit_before>/*=========================================================================

  Library:   qCTK

  Copyright (c) Kitware Inc.
  All rights reserved.
  Distributed under a BSD License. See LICENSE.txt file.

  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the above copyright notice for more information.

=========================================================================*/

// Qt includes
#include <QApplication>
#include <QSharedPointer>
#include <QTimer>

// CTK includes
#include "ctkTransferFunction.h"
#include "ctkTransferFunctionWidget.h"
#include "ctkVTKColorTransferFunction.h"

// VTK includes
#include <vtkColorTransferFunction.h>
#include <vtkSmartPointer.h>

// STD includes
#include <iostream>

//-----------------------------------------------------------------------------
int ctkTransferFunctionWidgetTest1(int argc, char * argv [] )
{
  QApplication app(argc, argv);

  vtkSmartPointer<vtkColorTransferFunction> ctf =
    vtkSmartPointer<vtkColorTransferFunction>::New();
  //
  ctf->AddRGBPoint(0., 1.,0.,0., 0.5, 0.);
  //ctf->AddRGBPoint(0.5, 0.,0.,1.);
  ctf->AddRGBPoint(1., 0.,1.,0.);
  //ctf->AddHSVPoint(0., 0.,1.,1.);
  //ctf->AddHSVPoint(1., 0.66666,1.,1.);

  QSharedPointer<ctkTransferFunction> transferFunction =
    QSharedPointer<ctkTransferFunction>(new ctkVTKColorTransferFunction(ctf));
  ctkTransferFunctionWidget transferFunctionWidget(transferFunction.data(), 0);
  // the widget is not really shown here, only when app.exec() is called
  transferFunctionWidget.show();

  //ctf->AddRGBPoint(0.7, 0.0,0.0,0.0);
  //ctkTransferFunctionWidget* toto = new ctkTransferFunctionWidget();
  QTimer autoExit;
  QObject::connect(&autoExit, SIGNAL(timeout()), &app, SLOT(quit()));
  //autoExit.start(1000);
  return app.exec();
}
<commit_msg>COMP: Restore the timer associated to the test ctkTransferFunctionWidgetTest1<commit_after>/*=========================================================================

  Library:   qCTK

  Copyright (c) Kitware Inc.
  All rights reserved.
  Distributed under a BSD License. See LICENSE.txt file.

  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the above copyright notice for more information.

=========================================================================*/

// Qt includes
#include <QApplication>
#include <QSharedPointer>
#include <QTimer>

// CTK includes
#include "ctkTransferFunction.h"
#include "ctkTransferFunctionWidget.h"
#include "ctkVTKColorTransferFunction.h"

// VTK includes
#include <vtkColorTransferFunction.h>
#include <vtkSmartPointer.h>

// STD includes
#include <iostream>

//-----------------------------------------------------------------------------
int ctkTransferFunctionWidgetTest1(int argc, char * argv [] )
{
  QApplication app(argc, argv);

  vtkSmartPointer<vtkColorTransferFunction> ctf =
    vtkSmartPointer<vtkColorTransferFunction>::New();
  //
  ctf->AddRGBPoint(0., 1.,0.,0., 0.5, 0.);
  //ctf->AddRGBPoint(0.5, 0.,0.,1.);
  ctf->AddRGBPoint(1., 0.,1.,0.);
  //ctf->AddHSVPoint(0., 0.,1.,1.);
  //ctf->AddHSVPoint(1., 0.66666,1.,1.);

  QSharedPointer<ctkTransferFunction> transferFunction =
    QSharedPointer<ctkTransferFunction>(new ctkVTKColorTransferFunction(ctf));
  ctkTransferFunctionWidget transferFunctionWidget(transferFunction.data(), 0);
  // the widget is not really shown here, only when app.exec() is called
  transferFunctionWidget.show();

  //ctf->AddRGBPoint(0.7, 0.0,0.0,0.0);
  //ctkTransferFunctionWidget* toto = new ctkTransferFunctionWidget();
  QTimer autoExit;
  QObject::connect(&autoExit, SIGNAL(timeout()), &app, SLOT(quit()));
  autoExit.start(1000);
  return app.exec();
}
<|endoftext|>