<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkBitmap.h"
#include "SkShader.h"
#include "SkXfermode.h"
#include "SkPM4f.h"

enum SrcType {
    //! A WxH image with a rectangle in the lower right.
    kRectangleImage_SrcType               = 0x01,
    //! kRectangleImage_SrcType with an alpha of 34.5%.
    kRectangleImageWithAlpha_SrcType      = 0x02,
    //! kRectnagleImageWithAlpha_SrcType scaled down by half.
    kSmallRectangleImageWithAlpha_SrcType = 0x04,
    //! kRectangleImage_SrcType drawn directly instead in an image.
    kRectangle_SrcType                    = 0x08,
    //! Two rectangles, first on the right half, second on the bottom half.
    kQuarterClear_SrcType                 = 0x10,
    //! kQuarterClear_SrcType in a layer.
    kQuarterClearInLayer_SrcType          = 0x20,
    //! A W/2xH/2 transparent image.
    kSmallTransparentImage_SrcType        = 0x40,
    //! kRectangleImage_SrcType drawn directly with a mask.
    kRectangleWithMask_SrcType            = 0x80,

    kAll_SrcType                          = 0xFF, //!< All the source types.
    kBasic_SrcType                        = 0x03, //!< Just basic source types.
};

const struct {
    SkXfermode::Mode  fMode;
    const char*       fLabel;
    int               fSourceTypeMask;  // The source types to use this
    // mode with. See draw_mode for
    // an explanation of each type.
    // PDF has to play some tricks
    // to support the base modes,
    // test those more extensively.
} gModes[] = {
    { SkXfermode::kClear_Mode,        "Clear",        kAll_SrcType   },
    { SkXfermode::kSrc_Mode,          "Src",          kAll_SrcType   },
    { SkXfermode::kDst_Mode,          "Dst",          kAll_SrcType   },
    { SkXfermode::kSrcOver_Mode,      "SrcOver",      kAll_SrcType   },
    { SkXfermode::kDstOver_Mode,      "DstOver",      kAll_SrcType   },
    { SkXfermode::kSrcIn_Mode,        "SrcIn",        kAll_SrcType   },
    { SkXfermode::kDstIn_Mode,        "DstIn",        kAll_SrcType   },
    { SkXfermode::kSrcOut_Mode,       "SrcOut",       kAll_SrcType   },
    { SkXfermode::kDstOut_Mode,       "DstOut",       kAll_SrcType   },
    { SkXfermode::kSrcATop_Mode,      "SrcATop",      kAll_SrcType   },
    { SkXfermode::kDstATop_Mode,      "DstATop",      kAll_SrcType   },

    { SkXfermode::kXor_Mode,          "Xor",          kBasic_SrcType },
    { SkXfermode::kPlus_Mode,         "Plus",         kBasic_SrcType },
    { SkXfermode::kModulate_Mode,     "Modulate",     kAll_SrcType   },
    { SkXfermode::kScreen_Mode,       "Screen",       kBasic_SrcType },
    { SkXfermode::kOverlay_Mode,      "Overlay",      kBasic_SrcType },
    { SkXfermode::kDarken_Mode,       "Darken",       kBasic_SrcType },
    { SkXfermode::kLighten_Mode,      "Lighten",      kBasic_SrcType },
    { SkXfermode::kColorDodge_Mode,   "ColorDodge",   kBasic_SrcType },
    { SkXfermode::kColorBurn_Mode,    "ColorBurn",    kBasic_SrcType },
    { SkXfermode::kHardLight_Mode,    "HardLight",    kBasic_SrcType },
    { SkXfermode::kSoftLight_Mode,    "SoftLight",    kBasic_SrcType },
    { SkXfermode::kDifference_Mode,   "Difference",   kBasic_SrcType },
    { SkXfermode::kExclusion_Mode,    "Exclusion",    kBasic_SrcType },
    { SkXfermode::kMultiply_Mode,     "Multiply",     kAll_SrcType   },
    { SkXfermode::kHue_Mode,          "Hue",          kBasic_SrcType },
    { SkXfermode::kSaturation_Mode,   "Saturation",   kBasic_SrcType },
    { SkXfermode::kColor_Mode,        "Color",        kBasic_SrcType },
    { SkXfermode::kLuminosity_Mode,   "Luminosity",   kBasic_SrcType },
};

static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
                         SkBitmap* transparent) {
    src->allocN32Pixels(w, h);
    src->eraseColor(SK_ColorTRANSPARENT);

    SkPaint p;
    p.setAntiAlias(true);

    SkRect r;
    SkScalar ww = SkIntToScalar(w);
    SkScalar hh = SkIntToScalar(h);

    {
        SkCanvas c(*src);
        p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44));
        r.set(0, 0, ww*3/4, hh*3/4);
        c.drawOval(r, p);
    }

    dst->allocN32Pixels(w, h);
    dst->eraseColor(SK_ColorTRANSPARENT);

    {
        SkCanvas c(*dst);
        p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
        r.set(ww/3, hh/3, ww*19/20, hh*19/20);
        c.drawRect(r, p);
    }

    transparent->allocN32Pixels(w, h);
    transparent->eraseColor(SK_ColorTRANSPARENT);
}

static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };

class XfermodesGM : public skiagm::GM {
    SkBitmap    fBG;
    SkBitmap    fSrcB, fDstB, fTransparent;

    /* The srcType argument indicates what to draw for the source part. Skia
     * uses the implied shape of the drawing command and these modes
     * demonstrate that.
     */
    void draw_mode(SkCanvas* canvas, SkXfermode* mode, SrcType srcType,
                   SkScalar x, SkScalar y) {
        SkPaint p;
        SkMatrix m;
        bool restoreNeeded = false;
        m.setTranslate(x, y);

        canvas->drawBitmap(fSrcB, x, y, &p);
        p.setXfermode(mode);
        switch (srcType) {
            case kSmallTransparentImage_SrcType: {
                m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);

                SkAutoCanvasRestore acr(canvas, true);
                canvas->concat(m);
                canvas->drawBitmap(fTransparent, 0, 0, &p);
                break;
            }
            case kQuarterClearInLayer_SrcType: {
                SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W),
                                                 SkIntToScalar(H));
                canvas->saveLayer(&bounds, &p);
                restoreNeeded = true;
                p.setXfermodeMode(SkXfermode::kSrcOver_Mode);
                // Fall through.
            }
            case kQuarterClear_SrcType: {
                SkScalar halfW = SkIntToScalar(W) / 2;
                SkScalar halfH = SkIntToScalar(H) / 2;
                p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
                SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW,
                                            SkIntToScalar(H));
                canvas->drawRect(r, p);
                p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF));
                r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH);
                canvas->drawRect(r, p);
                break;
            }
            case kRectangleWithMask_SrcType: {
                canvas->save();
                restoreNeeded = true;
                SkScalar w = SkIntToScalar(W);
                SkScalar h = SkIntToScalar(H);
                SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60);
                canvas->clipRect(r);
                // Fall through.
            }
            case kRectangle_SrcType: {
                SkScalar w = SkIntToScalar(W);
                SkScalar h = SkIntToScalar(H);
                SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
                                            w * 37 / 60, h * 37 / 60);
                p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
                canvas->drawRect(r, p);
                break;
            }
            case kSmallRectangleImageWithAlpha_SrcType:
                m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
                // Fall through.
            case kRectangleImageWithAlpha_SrcType:
                p.setAlpha(0x88);
                // Fall through.
            case kRectangleImage_SrcType: {
                SkAutoCanvasRestore acr(canvas, true);
                canvas->concat(m);
                canvas->drawBitmap(fDstB, 0, 0, &p);
                break;
            }
            default:
                break;
        }

        if (restoreNeeded) {
            canvas->restore();
        }
    }

    void onOnceBeforeDraw() override {
        fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
                                            kOpaque_SkAlphaType),
                          gData, 4);

        make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent);
    }

public:
    const static int W = 64;
    const static int H = 64;
    XfermodesGM() {}

protected:
    SkString onShortName() override {
        return SkString("xfermodes");
    }

    SkISize onISize() override {
        return SkISize::Make(1990, 640);
    }

    void onDraw(SkCanvas* canvas) override {
        canvas->translate(SkIntToScalar(10), SkIntToScalar(20));

        const SkScalar w = SkIntToScalar(W);
        const SkScalar h = SkIntToScalar(H);
        SkMatrix m;
        m.setScale(SkIntToScalar(6), SkIntToScalar(6));
        SkShader* s = SkShader::CreateBitmapShader(fBG,
                                                   SkShader::kRepeat_TileMode,
                                                   SkShader::kRepeat_TileMode,
                                                   &m);

        SkPaint labelP;
        labelP.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface(&labelP);
        labelP.setTextAlign(SkPaint::kCenter_Align);

        const int W = 5;

        SkScalar x0 = 0;
        SkScalar y0 = 0;
        for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) {
            SkScalar x = x0, y = y0;
            for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
                if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
                    continue;
                }
                SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
                SkAutoUnref aur(mode);
                SkRect r;
                r.set(x, y, x+w, y+h);

                SkPaint p;
                p.setStyle(SkPaint::kFill_Style);
                p.setShader(s);
                canvas->drawRect(r, p);

                canvas->saveLayer(&r, nullptr);
                draw_mode(canvas, mode, static_cast<SrcType>(sourceType),
                          r.fLeft, r.fTop);
                canvas->restore();

                r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
                p.setStyle(SkPaint::kStroke_Style);
                p.setShader(nullptr);
                canvas->drawRect(r, p);

#if 1
                canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
                                 x + w/2, y - labelP.getTextSize()/2, labelP);
#endif
                x += w + SkIntToScalar(10);
                if ((i % W) == W - 1) {
                    x = x0;
                    y += h + SkIntToScalar(30);
                }
            }
            if (y < 320) {
                if (x > x0) {
                    y += h + SkIntToScalar(30);
                }
                y0 = y;
            } else {
                x0 += SkIntToScalar(400);
                y0 = 0;
            }
        }
        s->unref();
    }

private:
    typedef GM INHERITED;
};
DEF_GM( return new XfermodesGM; )
<commit_msg>extend xfermodes gm to include 3 custom modes<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkBitmap.h"
#include "SkShader.h"
#include "SkXfermode.h"
#include "SkPM4f.h"

#include "SkArithmeticMode.h"
#include "SkPixelXorXfermode.h"
#include "SkAvoidXfermode.h"

#define kCustomShift    16
#define kCustomMask     (~0xFFFF)

enum CustomModes {
    kArithmetic_CustomMode  = 1 << kCustomShift,
    kPixelXor_CustomMode    = 2 << kCustomShift,
    kAvoid_CustomMode       = 3 << kCustomShift,
};

static SkXfermode* make_custom(int customMode) {
    switch (customMode) {
        case kArithmetic_CustomMode: {
            const SkScalar k1 = 0.25;
            const SkScalar k2 = 0.75;
            const SkScalar k3 = 0.75;
            const SkScalar k4 = -0.25;
            return SkArithmeticMode::Create(k1, k2, k3, k4);
        }
        case kPixelXor_CustomMode:
            return SkPixelXorXfermode::Create(0xFF88CC44);
        case kAvoid_CustomMode:
            return SkAvoidXfermode::Create(0xFFFF0000, 0x44, SkAvoidXfermode::kAvoidColor_Mode);
        default:
            break;
    }
    SkASSERT(false);
    return nullptr;
}

enum SrcType {
    //! A WxH image with a rectangle in the lower right.
    kRectangleImage_SrcType               = 0x01,
    //! kRectangleImage_SrcType with an alpha of 34.5%.
    kRectangleImageWithAlpha_SrcType      = 0x02,
    //! kRectnagleImageWithAlpha_SrcType scaled down by half.
    kSmallRectangleImageWithAlpha_SrcType = 0x04,
    //! kRectangleImage_SrcType drawn directly instead in an image.
    kRectangle_SrcType                    = 0x08,
    //! Two rectangles, first on the right half, second on the bottom half.
    kQuarterClear_SrcType                 = 0x10,
    //! kQuarterClear_SrcType in a layer.
    kQuarterClearInLayer_SrcType          = 0x20,
    //! A W/2xH/2 transparent image.
    kSmallTransparentImage_SrcType        = 0x40,
    //! kRectangleImage_SrcType drawn directly with a mask.
    kRectangleWithMask_SrcType            = 0x80,

    kAll_SrcType                          = 0xFF, //!< All the source types.
    kBasic_SrcType                        = 0x03, //!< Just basic source types.
};

const struct {
    SkXfermode::Mode  fMode;
    const char*       fLabel;
    int               fSourceTypeMask;  // The source types to use this
    // mode with. See draw_mode for
    // an explanation of each type.
    // PDF has to play some tricks
    // to support the base modes,
    // test those more extensively.
} gModes[] = {
    { SkXfermode::kClear_Mode,        "Clear",        kAll_SrcType   },
    { SkXfermode::kSrc_Mode,          "Src",          kAll_SrcType   },
    { SkXfermode::kDst_Mode,          "Dst",          kAll_SrcType   },
    { SkXfermode::kSrcOver_Mode,      "SrcOver",      kAll_SrcType   },
    { SkXfermode::kDstOver_Mode,      "DstOver",      kAll_SrcType   },
    { SkXfermode::kSrcIn_Mode,        "SrcIn",        kAll_SrcType   },
    { SkXfermode::kDstIn_Mode,        "DstIn",        kAll_SrcType   },
    { SkXfermode::kSrcOut_Mode,       "SrcOut",       kAll_SrcType   },
    { SkXfermode::kDstOut_Mode,       "DstOut",       kAll_SrcType   },
    { SkXfermode::kSrcATop_Mode,      "SrcATop",      kAll_SrcType   },
    { SkXfermode::kDstATop_Mode,      "DstATop",      kAll_SrcType   },

    { SkXfermode::kXor_Mode,          "Xor",          kBasic_SrcType },
    { SkXfermode::kPlus_Mode,         "Plus",         kBasic_SrcType },
    { SkXfermode::kModulate_Mode,     "Modulate",     kAll_SrcType   },
    { SkXfermode::kScreen_Mode,       "Screen",       kBasic_SrcType },
    { SkXfermode::kOverlay_Mode,      "Overlay",      kBasic_SrcType },
    { SkXfermode::kDarken_Mode,       "Darken",       kBasic_SrcType },
    { SkXfermode::kLighten_Mode,      "Lighten",      kBasic_SrcType },
    { SkXfermode::kColorDodge_Mode,   "ColorDodge",   kBasic_SrcType },
    { SkXfermode::kColorBurn_Mode,    "ColorBurn",    kBasic_SrcType },
    { SkXfermode::kHardLight_Mode,    "HardLight",    kBasic_SrcType },
    { SkXfermode::kSoftLight_Mode,    "SoftLight",    kBasic_SrcType },
    { SkXfermode::kDifference_Mode,   "Difference",   kBasic_SrcType },
    { SkXfermode::kExclusion_Mode,    "Exclusion",    kBasic_SrcType },
    { SkXfermode::kMultiply_Mode,     "Multiply",     kAll_SrcType   },
    { SkXfermode::kHue_Mode,          "Hue",          kBasic_SrcType },
    { SkXfermode::kSaturation_Mode,   "Saturation",   kBasic_SrcType },
    { SkXfermode::kColor_Mode,        "Color",        kBasic_SrcType },
    { SkXfermode::kLuminosity_Mode,   "Luminosity",   kBasic_SrcType },

    { SkXfermode::Mode(0xFFFF),       "Arithmetic",   kBasic_SrcType + kArithmetic_CustomMode   },
    { SkXfermode::Mode(0xFFFF),       "PixelXor",     kBasic_SrcType + kPixelXor_CustomMode     },
    { SkXfermode::Mode(0xFFFF),       "Avoid",        kBasic_SrcType + kAvoid_CustomMode        },
};

static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
                         SkBitmap* transparent) {
    src->allocN32Pixels(w, h);
    src->eraseColor(SK_ColorTRANSPARENT);

    SkPaint p;
    p.setAntiAlias(true);

    SkRect r;
    SkScalar ww = SkIntToScalar(w);
    SkScalar hh = SkIntToScalar(h);

    {
        SkCanvas c(*src);
        p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44));
        r.set(0, 0, ww*3/4, hh*3/4);
        c.drawOval(r, p);
    }

    dst->allocN32Pixels(w, h);
    dst->eraseColor(SK_ColorTRANSPARENT);

    {
        SkCanvas c(*dst);
        p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
        r.set(ww/3, hh/3, ww*19/20, hh*19/20);
        c.drawRect(r, p);
    }

    transparent->allocN32Pixels(w, h);
    transparent->eraseColor(SK_ColorTRANSPARENT);
}

static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };

class XfermodesGM : public skiagm::GM {
    SkBitmap    fBG;
    SkBitmap    fSrcB, fDstB, fTransparent;

    /* The srcType argument indicates what to draw for the source part. Skia
     * uses the implied shape of the drawing command and these modes
     * demonstrate that.
     */
    void draw_mode(SkCanvas* canvas, SkXfermode* mode, SrcType srcType,
                   SkScalar x, SkScalar y) {
        SkPaint p;
        SkMatrix m;
        bool restoreNeeded = false;
        m.setTranslate(x, y);

        canvas->drawBitmap(fSrcB, x, y, &p);
        p.setXfermode(mode);
        switch (srcType) {
            case kSmallTransparentImage_SrcType: {
                m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);

                SkAutoCanvasRestore acr(canvas, true);
                canvas->concat(m);
                canvas->drawBitmap(fTransparent, 0, 0, &p);
                break;
            }
            case kQuarterClearInLayer_SrcType: {
                SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W),
                                                 SkIntToScalar(H));
                canvas->saveLayer(&bounds, &p);
                restoreNeeded = true;
                p.setXfermodeMode(SkXfermode::kSrcOver_Mode);
                // Fall through.
            }
            case kQuarterClear_SrcType: {
                SkScalar halfW = SkIntToScalar(W) / 2;
                SkScalar halfH = SkIntToScalar(H) / 2;
                p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
                SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW,
                                            SkIntToScalar(H));
                canvas->drawRect(r, p);
                p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF));
                r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH);
                canvas->drawRect(r, p);
                break;
            }
            case kRectangleWithMask_SrcType: {
                canvas->save();
                restoreNeeded = true;
                SkScalar w = SkIntToScalar(W);
                SkScalar h = SkIntToScalar(H);
                SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60);
                canvas->clipRect(r);
                // Fall through.
            }
            case kRectangle_SrcType: {
                SkScalar w = SkIntToScalar(W);
                SkScalar h = SkIntToScalar(H);
                SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
                                            w * 37 / 60, h * 37 / 60);
                p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
                canvas->drawRect(r, p);
                break;
            }
            case kSmallRectangleImageWithAlpha_SrcType:
                m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
                // Fall through.
            case kRectangleImageWithAlpha_SrcType:
                p.setAlpha(0x88);
                // Fall through.
            case kRectangleImage_SrcType: {
                SkAutoCanvasRestore acr(canvas, true);
                canvas->concat(m);
                canvas->drawBitmap(fDstB, 0, 0, &p);
                break;
            }
            default:
                break;
        }

        if (restoreNeeded) {
            canvas->restore();
        }
    }

    void onOnceBeforeDraw() override {
        fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
                                            kOpaque_SkAlphaType),
                          gData, 4);

        make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent);
    }

public:
    const static int W = 64;
    const static int H = 64;
    XfermodesGM() {}

protected:
    SkString onShortName() override {
        return SkString("xfermodes");
    }

    SkISize onISize() override {
        return SkISize::Make(1990, 660);
    }

    void onDraw(SkCanvas* canvas) override {
        canvas->translate(SkIntToScalar(10), SkIntToScalar(20));

        const SkScalar w = SkIntToScalar(W);
        const SkScalar h = SkIntToScalar(H);
        SkMatrix m;
        m.setScale(SkIntToScalar(6), SkIntToScalar(6));
        SkShader* s = SkShader::CreateBitmapShader(fBG,
                                                   SkShader::kRepeat_TileMode,
                                                   SkShader::kRepeat_TileMode,
                                                   &m);

        SkPaint labelP;
        labelP.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface(&labelP);
        labelP.setTextAlign(SkPaint::kCenter_Align);

        const int W = 5;

        SkScalar x0 = 0;
        SkScalar y0 = 0;
        for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) {
            SkScalar x = x0, y = y0;
            for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
                if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
                    SkDebugf("skip %d %s for type %x\n", i, gModes[i].fLabel, sourceType);
                    continue;
                }
                SkAutoTUnref<SkXfermode> mode;
                if (gModes[i].fSourceTypeMask & kCustomMask) {
                    mode.reset(make_custom(gModes[i].fSourceTypeMask & kCustomMask));
                } else {
                    mode.reset(SkXfermode::Create(gModes[i].fMode));
                }
                SkRect r;
                r.set(x, y, x+w, y+h);

                SkPaint p;
                p.setStyle(SkPaint::kFill_Style);
                p.setShader(s);
                canvas->drawRect(r, p);

                canvas->saveLayer(&r, nullptr);
                draw_mode(canvas, mode, static_cast<SrcType>(sourceType),
                          r.fLeft, r.fTop);
                canvas->restore();

                r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
                p.setStyle(SkPaint::kStroke_Style);
                p.setShader(nullptr);
                canvas->drawRect(r, p);

#if 1
                canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
                                 x + w/2, y - labelP.getTextSize()/2, labelP);
#endif
                x += w + SkIntToScalar(10);
                if ((i % W) == W - 1) {
                    x = x0;
                    y += h + SkIntToScalar(30);
                }
            }
            if (y < 320) {
                if (x > x0) {
                    y += h + SkIntToScalar(30);
                }
                y0 = y;
            } else {
                x0 += SkIntToScalar(400);
                y0 = 0;
            }
        }
        s->unref();
    }

private:
    typedef GM INHERITED;
};
DEF_GM( return new XfermodesGM; )
<|endoftext|>


<commit_before>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE ExactTransientSolution
#define BOOST_TEST_MAIN
#include <cap/energy_storage_device.h>
#include <cap/mp_values.h>
#include <deal.II/base/types.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/dofs/dof_handler.h>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <cmath>
#include <iostream>
#include <fstream>
#include <numeric>

namespace cap {

void compute_parameters(std::shared_ptr<boost::property_tree::ptree const> input_database,
                        std::shared_ptr<boost::property_tree::ptree      > output_database)
{
    double const cross_sectional_area = 0.0001 * input_database->get<double>("geometry.geometric_area");
    double const electrode_width = 0.01 * input_database->get<double>("geometry.anode_electrode_thickness");
    double const separator_width = 0.01 * input_database->get<double>("geometry.separator_thickness");

    // getting the material parameters values
    std::shared_ptr<boost::property_tree::ptree> material_properties_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("material_properties"));
    cap::MPValuesParameters<2> mp_values_params(material_properties_database);
    std::shared_ptr<boost::property_tree::ptree> geometry_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("geometry"));
    mp_values_params.geometry = std::make_shared<cap::DummyGeometry<2>>(geometry_database);
    std::shared_ptr<cap::MPValues<2> > mp_values = std::shared_ptr<cap::MPValues<2> >
        (new cap::MPValues<2>(mp_values_params));
    // build dummy cell itertor and set its material id
    dealii::Triangulation<2> triangulation;
    dealii::GridGenerator::hyper_cube (triangulation);
    dealii::DoFHandler<2> dof_handler(triangulation);
    dealii::DoFHandler<2>::active_cell_iterator cell =
        dof_handler.begin_active();
    // electrode
    cell->set_material_id(
        input_database->get<dealii::types::material_id>("geometry.anode_electrode_material_id"));
    std::vector<double> electrode_solid_electrical_conductivity_values(1);
    std::vector<double> electrode_liquid_electrical_conductivity_values(1);
    std::vector<double> electrode_specific_capacitance_values(1);
    std::vector<double> electrode_exchange_current_density_values(1);
    std::vector<double> electrode_electron_thermal_voltage_values(1);
    mp_values->get_values("solid_electrical_conductivity" , cell, electrode_solid_electrical_conductivity_values );
    mp_values->get_values("liquid_electrical_conductivity", cell, electrode_liquid_electrical_conductivity_values);
    mp_values->get_values("specific_capacitance"          , cell, electrode_specific_capacitance_values          );
    mp_values->get_values("faradaic_reaction_coefficient" , cell, electrode_exchange_current_density_values      );
    mp_values->get_values("electron_thermal_voltage"      , cell, electrode_electron_thermal_voltage_values      );
    if (electrode_exchange_current_density_values[0] == 0.0)
        throw std::runtime_error("test assumes faradaic processes are present, exchange_current_density has to be non zero");
    double const total_current = -1.0; // normalized
    double const dimensionless_exchange_current_density = electrode_exchange_current_density_values[0]
        * std::pow(electrode_width,2)
        * ( 1.0 / electrode_solid_electrical_conductivity_values[0]
          + 1.0 / electrode_liquid_electrical_conductivity_values[0] );
    double const dimensionless_current_density = total_current
        * electrode_width
        / electrode_liquid_electrical_conductivity_values[0]
        / electrode_electron_thermal_voltage_values[0];
    double const ratio_of_solution_phase_to_matrix_phase_conductivities =
        electrode_liquid_electrical_conductivity_values[0] / electrode_solid_electrical_conductivity_values[0];

    output_database->put("dimensionless_current_density"                         , dimensionless_current_density                         );
    output_database->put("dimensionless_exchange_current_density"                , dimensionless_exchange_current_density                );
    output_database->put("ratio_of_solution_phase_to_matrix_phase_conductivities", ratio_of_solution_phase_to_matrix_phase_conductivities);

    output_database->put("position_normalization_factor", electrode_width);
    output_database->put("time_normalization_factor"    ,
        electrode_specific_capacitance_values[0]
            * ( 1.0 / electrode_solid_electrical_conductivity_values[0]
              + 1.0 / electrode_liquid_electrical_conductivity_values[0] )
            * std::pow(electrode_width,2) );

    // separator
    cell->set_material_id(
        input_database->get<dealii::types::material_id>("geometry.separator_material_id"));
    std::vector<double> separator_liquid_electrical_conductivity_values(1);
    mp_values->get_values("liquid_electrical_conductivity", cell, separator_liquid_electrical_conductivity_values);

    double const potential_drop_across_the_separator = -total_current * separator_width / separator_liquid_electrical_conductivity_values[0];
    double const voltage_normalization_factor        = electrode_electron_thermal_voltage_values[0];
    output_database->put("potential_drop_across_the_separator", potential_drop_across_the_separator);
    output_database->put("voltage_normalization_factor"       , voltage_normalization_factor       );
    output_database->put("cross_sectional_area"               , cross_sectional_area               );
}

void verification_problem(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database)
{
    double dimensionless_current_density                          = database->get<double>("dimensionless_current_density"                         );
    double dimensionless_exchange_current_density                 = database->get<double>("dimensionless_exchange_current_density"                );
    double ratio_of_solution_phase_to_matrix_phase_conductivities = database->get<double>("ratio_of_solution_phase_to_matrix_phase_conductivities");

    // gold vs computed
    double const charge_current = database->get<double>("charge_current");
    double const charge_time    = database->get<double>("charge_time"   );
    double const time_step      = database->get<double>("time_step"     );
    double const epsilon        = time_step * 1.0e-4;
    double const cross_sectional_area                = database->get<double>("cross_sectional_area"               );
    dimensionless_current_density *= charge_current / cross_sectional_area;

    std::cout<<"delta="<<dimensionless_current_density<<"\n";
    std::cout<<"nu2  ="<<dimensionless_exchange_current_density<<"\n";
    std::cout<<"beta ="<<ratio_of_solution_phase_to_matrix_phase_conductivities<<"\n";
    std::cout<<"time step = "<<time_step<<std::endl;

    unsigned int pos = 0;
    double computed_voltage;
    double const percent_tolerance = database->get<double>("percent_tolerance");
    std::vector<double> gold_solution(10);
    gold_solution[0] = 1.725914356067658e-01;
    gold_solution[1] = 1.802025636145941e-01;
    gold_solution[2] = 1.859326352495181e-01;
    gold_solution[3] = 1.905978440188036e-01;
    gold_solution[4] = 1.946022119085378e-01;
    gold_solution[5] = 1.981601232287249e-01;
    gold_solution[6] = 2.013936650249285e-01;
    gold_solution[7] = 2.043807296399895e-01;
    gold_solution[8] = 2.071701713934283e-01;
    gold_solution[9] = 2.097979282542038e-01;
    for (double time = 0.0; time <= charge_time+epsilon; time += time_step)
    {
        dev->evolve_one_time_step_constant_current(time_step, charge_current);
        dev->get_voltage(computed_voltage);
        if ((std::abs(time+time_step-1e-3) < 1e-7) || (std::abs(time+time_step-2e-3) < 1e-7) ||
            (std::abs(time+time_step-3e-3) < 1e-7) || (std::abs(time+time_step-4e-3) < 1e-7) ||
            (std::abs(time+time_step-5e-3) < 1e-7) || (std::abs(time+time_step-6e-3) < 1e-7) ||
            (std::abs(time+time_step-7e-3) < 1e-7) || (std::abs(time+time_step-8e-3) < 1e-7) ||
            (std::abs(time+time_step-9e-3) < 1e-7) || (std::abs(time+time_step-10e-3) < 1e-7))
        {
          BOOST_CHECK_CLOSE(computed_voltage, gold_solution[pos], percent_tolerance);
          ++pos;
        }
    }
}

} // end namespace cap

BOOST_AUTO_TEST_CASE( test_exact_transient_solution )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> input_database =
        std::make_shared<boost::property_tree::ptree>();
    boost::property_tree::info_parser::read_info("verification_problems.info", *input_database);

    // build an energy storage system
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("device"));
    device_database->put("type", "New_SuperCapacitor");
    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::EnergyStorageDevice::build(boost::mpi::communicator(), *device_database);

    // measure discharge curve
    std::fstream fout;
    fout.open("verification_problem_data", std::fstream::out);

    std::shared_ptr<boost::property_tree::ptree> verification_problem_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("verification_problem_subramanian"));

    cap::compute_parameters(device_database, verification_problem_database);

    cap::verification_problem(device, verification_problem_database);

    fout.close();
}
<commit_msg>Remove unused code.<commit_after>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE ExactTransientSolution
#define BOOST_TEST_MAIN
#include <cap/energy_storage_device.h>
#include <cap/mp_values.h>
#include <deal.II/base/types.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/dofs/dof_handler.h>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <cmath>
#include <iostream>
#include <fstream>
#include <numeric>

namespace cap {

void verification_problem(std::shared_ptr<cap::EnergyStorageDevice> dev)
{
    // gold vs computed
    double const charge_current = 5e-3;
    double const charge_time    = 0.01;
    double const time_step      = 1e-4;
    double const epsilon        = time_step * 1.0e-4;

    unsigned int pos = 0;
    double computed_voltage;
    double const percent_tolerance = 1e-6;
    std::vector<double> gold_solution(10);
    gold_solution[0] = 1.725914356067658e-01;
    gold_solution[1] = 1.802025636145941e-01;
    gold_solution[2] = 1.859326352495181e-01;
    gold_solution[3] = 1.905978440188036e-01;
    gold_solution[4] = 1.946022119085378e-01;
    gold_solution[5] = 1.981601232287249e-01;
    gold_solution[6] = 2.013936650249285e-01;
    gold_solution[7] = 2.043807296399895e-01;
    gold_solution[8] = 2.071701713934283e-01;
    gold_solution[9] = 2.097979282542038e-01;
    for (double time = 0.0; time <= charge_time+epsilon; time += time_step)
    {
        dev->evolve_one_time_step_constant_current(time_step, charge_current);
        dev->get_voltage(computed_voltage);
        if ((std::abs(time+time_step-1e-3) < 1e-7) || (std::abs(time+time_step-2e-3) < 1e-7) ||
            (std::abs(time+time_step-3e-3) < 1e-7) || (std::abs(time+time_step-4e-3) < 1e-7) ||
            (std::abs(time+time_step-5e-3) < 1e-7) || (std::abs(time+time_step-6e-3) < 1e-7) ||
            (std::abs(time+time_step-7e-3) < 1e-7) || (std::abs(time+time_step-8e-3) < 1e-7) ||
            (std::abs(time+time_step-9e-3) < 1e-7) || (std::abs(time+time_step-10e-3) < 1e-7))
        {
          BOOST_CHECK_CLOSE(computed_voltage, gold_solution[pos], percent_tolerance);
          ++pos;
        }
    }
}

} // end namespace cap

BOOST_AUTO_TEST_CASE( test_exact_transient_solution )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>();
    boost::property_tree::info_parser::read_info("super_capacitor.info", *device_database);
    device_database->put("type", "New_SuperCapacitor");

    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::EnergyStorageDevice::build(boost::mpi::communicator(), *device_database);

    cap::verification_problem(device);
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkRGBPixel.h"
#include "itkRGBToLuminanceImageFilter.h"
#include "itkRGBToLuminanceImageAdaptor.h"
#include "itkSubtractImageFilter.h"

int itkRGBToLuminanceImageFilterAndAdaptorTest(int, char* [] )
{

  // Define the dimension of the images
  const unsigned int ImageDimension = 3;

  // Declare the types of the images
  typedef itk::RGBPixel< float >                        InputPixelType;
  typedef float                                         OutputPixelType;

  typedef itk::Image< InputPixelType,  ImageDimension > InputImageType;
  typedef itk::Image< OutputPixelType, ImageDimension > OutputImageType;

  // Declare Iterator types apropriated for each image
  typedef itk::ImageRegionIteratorWithIndex<
                                  InputImageType>  InputIteratorType;

  typedef itk::ImageRegionIteratorWithIndex<
                                  OutputImageType>  OutputIteratorType;

  // Declare the type of the index to access images
  typedef itk::Index<ImageDimension>         IndexType;

  // Declare the type of the size
  typedef itk::Size<ImageDimension>          SizeType;

  // Declare the type of the Region
  typedef itk::ImageRegion<ImageDimension>   RegionType;

  // Create two images
  InputImageType::Pointer inputImage  = InputImageType::New();

  // Define their size, and start index
  SizeType size;
  size[0] = 2;
  size[1] = 2;
  size[2] = 2;

  IndexType start;
  start[0] = 0;
  start[1] = 0;
  start[2] = 0;

  RegionType region;
  region.SetIndex( start );
  region.SetSize( size );

  // Initialize Image A
  inputImage->SetLargestPossibleRegion( region );
  inputImage->SetBufferedRegion( region );
  inputImage->SetRequestedRegion( region );
  inputImage->Allocate();
  // Create one iterator for the Input Image (this is a light object)
  InputIteratorType it( inputImage, inputImage->GetBufferedRegion() );

  // Initialize the content of Image A
  InputPixelType pixel;
  pixel.SetRed( 1.0 );
  pixel.SetGreen( 1.0 );
  pixel.SetBlue( 1.0 );
  std::cout << "Content of the Input " << std::endl;
  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    it.Set( pixel );
    std::cout << it.Get() << std::endl;
    ++it;
  }

  // Declare the type for the RGBToLuminance filter
  typedef itk::RGBToLuminanceImageFilter< InputImageType,
                               OutputImageType  >  FilterType;

  // Create an ADD Filter
  FilterType::Pointer filter = FilterType::New();

  // Connect the input images
  filter->SetInput( inputImage );

  // Get the Smart Pointer to the Filter Output
  OutputImageType::Pointer outputImage = filter->GetOutput();

  // Execute the filter
  filter->Update();
  filter->SetFunctor(filter->GetFunctor());

  // Create an iterator for going through the image output
  OutputIteratorType ot(outputImage, outputImage->GetRequestedRegion());

  //  Check the content of the result image
  std::cout << "Verification of the output " << std::endl;
  const OutputImageType::PixelType epsilon = 1e-6;

  ot.GoToBegin();
  it.GoToBegin();
  while( !ot.IsAtEnd() )
    {
    std::cout <<  ot.Get() << " = ";
    std::cout <<  it.Get().GetLuminance()  << std::endl;
    const InputPixelType  input  = it.Get();
    const OutputPixelType output = ot.Get();
    const OutputPixelType value  = static_cast< OutputPixelType >( input.GetLuminance() );
    if( std::fabs( value - output ) > epsilon )
      {
      std::cerr << "Error in itkRGBToLuminanceImageFilterTest " << std::endl;
      std::cerr << " Luminance( " << input << ") = " << value << std::endl;
      std::cerr << " differs from " << output;
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++ot;
    ++it;
    }

  //---------------------------------------
  // This section tests for RGBToLuminanceImageAdaptor
  //---------------------------------------

  typedef itk::RGBToLuminanceImageAdaptor<InputImageType,
                          OutputPixelType>  AdaptorType;

  AdaptorType::Pointer luminanceAdaptor = AdaptorType::New();

  luminanceAdaptor->SetImage( inputImage );

  typedef itk::SubtractImageFilter<
                        OutputImageType,
                        AdaptorType,
                        OutputImageType   > DiffFilterType;

  DiffFilterType::Pointer diffFilter = DiffFilterType::New();

  diffFilter->SetInput1( outputImage );
  diffFilter->SetInput2( luminanceAdaptor  );

  diffFilter->Update();

  // Get the Smart Pointer to the Diff filter Output
  OutputImageType::Pointer diffImage = diffFilter->GetOutput();

  //  Check the content of the diff image
  std::cout << "Comparing the results with those of an Adaptor" << std::endl;
  std::cout << "Verification of the output " << std::endl;

  // Create an iterator for going through the image output
  OutputIteratorType dt(diffImage, diffImage->GetRequestedRegion());

  dt.GoToBegin();
  while( !dt.IsAtEnd() )
    {
    std::cout <<  dt.Get() << std::endl;
    const OutputPixelType diff = dt.Get();
    if( std::fabs( diff ) > epsilon )
      {
      std::cerr << "Error in itkRGBToLuminanceImageFilterTest " << std::endl;
      std::cerr << "Comparing results with Adaptors" << std::endl;
      std::cerr << " difference = " << diff << std::endl;
      std::cerr << " differs from 0 ";
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++dt;
    }

  return EXIT_SUCCESS;
}
<commit_msg>ENH: Improve RGBToLuminanceImageFilter and Adaptor coverage.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkMath.h"
#include "itkRGBPixel.h"
#include "itkRGBToLuminanceImageFilter.h"
#include "itkRGBToLuminanceImageAdaptor.h"
#include "itkSubtractImageFilter.h"
#include "itkTestingMacros.h"

int itkRGBToLuminanceImageFilterAndAdaptorTest( int, char* [] )
{

  // Define the dimension of the images
  const unsigned int ImageDimension = 3;

  // Declare the pixel types of the images
  typedef itk::RGBPixel< float >                        InputPixelType;
  typedef float                                         OutputPixelType;

  // Declare the types of the images
  typedef itk::Image< InputPixelType,  ImageDimension > InputImageType;
  typedef itk::Image< OutputPixelType, ImageDimension > OutputImageType;

  // Declare appropriate Iterator types for each image
  typedef itk::ImageRegionIteratorWithIndex<
                                  InputImageType >  InputIteratorType;

  typedef itk::ImageRegionIteratorWithIndex<
                                  OutputImageType > OutputIteratorType;

  // Declare the type of the index to access images
  typedef itk::Index< ImageDimension >         IndexType;

  // Declare the type of the size
  typedef itk::Size< ImageDimension >          SizeType;

  // Declare the type of the Region
  typedef itk::ImageRegion< ImageDimension >   RegionType;

  // Create the input image
  InputImageType::Pointer inputImage = InputImageType::New();

  // Define its size, and start index
  SizeType size;
  size[0] = 2;
  size[1] = 2;
  size[2] = 2;

  IndexType start;
  start[0] = 0;
  start[1] = 0;
  start[2] = 0;

  RegionType region;
  region.SetIndex( start );
  region.SetSize( size );

  // Initialize the input image
  inputImage->SetLargestPossibleRegion( region );
  inputImage->SetBufferedRegion( region );
  inputImage->SetRequestedRegion( region );
  inputImage->Allocate();

  // Create one iterator for the Input Image (this is a light object)
  InputIteratorType it( inputImage, inputImage->GetBufferedRegion() );

  // Initialize the content of the input image
  InputPixelType pixel;
  pixel.SetRed( 1.0 );
  pixel.SetGreen( 1.0 );
  pixel.SetBlue( 1.0 );

  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    it.Set( pixel );
    ++it;
  }

  // Declare the type for the RGBToLuminance filter
  typedef itk::RGBToLuminanceImageFilter< InputImageType,
                               OutputImageType > FilterType;

  // Create the filter
  FilterType::Pointer filter = FilterType::New();

  EXERCISE_BASIC_OBJECT_METHODS( filter, RGBToLuminanceImageFilter,
    UnaryFunctorImageFilter );

  // Set the input image
  filter->SetInput( inputImage );

  filter->SetFunctor( filter->GetFunctor() );

  // Execute the filter
  filter->Update();

  // Get the filter output
  OutputImageType::Pointer outputImage = filter->GetOutput();

  // Create an iterator for going through the image output
  OutputIteratorType ot( outputImage, outputImage->GetRequestedRegion() );

  // Check the content of the result image
  const OutputImageType::PixelType epsilon = 1e-6;

  ot.GoToBegin();
  it.GoToBegin();
  while( !ot.IsAtEnd() )
    {
    const InputPixelType  input  = it.Get();
    const OutputPixelType output = ot.Get();
    const OutputPixelType value  = static_cast< OutputPixelType >( input.GetLuminance() );
    if( !itk::Math::FloatAlmostEqual( value, output, 10, epsilon ) )
      {
      std::cerr.precision( static_cast< int >( itk::Math::abs( std::log10( epsilon ) ) ) );
      std::cerr << "Error " << std::endl;
      std::cerr << " Luminance( " << input << ") = " << value << std::endl;
      std::cerr << " differs from " << output;
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++ot;
    ++it;
    }

  //
  // Test the itk::RGBToLuminanceImageAdaptor
  //

  typedef itk::RGBToLuminanceImageAdaptor< InputImageType,
                          OutputPixelType> AdaptorType;

  AdaptorType::Pointer luminanceAdaptor = AdaptorType::New();

  EXERCISE_BASIC_OBJECT_METHODS( luminanceAdaptor, RGBToLuminanceImageAdaptor,
    ImageAdaptor );

  luminanceAdaptor->SetImage( inputImage );

  typedef itk::SubtractImageFilter<
                        OutputImageType,
                        AdaptorType,
                        OutputImageType > DiffFilterType;

  DiffFilterType::Pointer diffFilter = DiffFilterType::New();

  diffFilter->SetInput1( outputImage );
  diffFilter->SetInput2( luminanceAdaptor );

  diffFilter->Update();

  // Get the filter output
  OutputImageType::Pointer diffImage = diffFilter->GetOutput();

  // Check the content of the diff image
  //

  // Create an iterator for going through the image output
  OutputIteratorType dt( diffImage, diffImage->GetRequestedRegion() );

  dt.GoToBegin();
  while( !dt.IsAtEnd() )
    {
    const OutputPixelType diff = dt.Get();
    if( std::fabs( diff ) > epsilon )
      {
      std::cerr.precision( static_cast< int >( itk::Math::abs( std::log10( epsilon ) ) ) );
      std::cerr << "Error comparing results with Adaptors" << std::endl;
      std::cerr << " difference = " << diff << std::endl;
      std::cerr << " differs from 0 ";
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++dt;
    }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Silvio Traversaro
 * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 */

#include <fstream>
#include <iostream>
#include <sstream>

#include <dirl/dataset/DynamicDatasetFile.hpp>

namespace dirl {

DynamicDatasetFile::DynamicDatasetFile()
{

}

DynamicDatasetFile::~DynamicDatasetFile()
{

}

int DynamicDatasetFile::getNrOfSamples()
{
    return dynamic_samples.size();
}

bool DynamicDatasetFile::getSample(int sample_n, DynamicSample & sample)
{
    if( sample_n < 0 || sample_n >= getNrOfSamples() ) { return false; }
    sample = dynamic_samples[sample_n];
    return true;
}

double get_next_double(std::stringstream & ss,std::string & data_buffer)
{
    getline(ss,data_buffer,',');
    return atof(data_buffer.c_str());
}

bool DynamicDatasetFile::loadFromFile(const std::string file_name, const bool append)
{
    std::string data_buffer;
    std::string line_buffer;

    std::ifstream csv_file;

    #ifndef NDEBUG
    bool verbose = true;
    #endif

    csv_file.open (file_name.c_str(), std::ifstream::in);

    if( !csv_file ) {
        std::cerr << "DynamicDatasetFile error: it was not possible to open file " << file_name << std::endl;
        return false;
    }

    //First row: field names of the header (not useful)
    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading first row: " << data_buffer << std::endl;
    #endif

    //Second row: //N_DOFS,N_MEASURED_TORQUES,N_MEASURED_WRENCHES,N_MEASURED_3AXIS_FT,N_ADDITIONAL_ME
    getline(csv_file,data_buffer,',');
    if( !append ) {
        nrOfDOFs = atoi(data_buffer.c_str());
    } else {
        if( nrOfDOFs != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of DOFs " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfDOFs: " << nrOfDOFs << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasuredTorques = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasuredTorques != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of measured torques " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasuredTorques: " << nrOfMeasuredTorques << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasuredWrenches = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasuredWrenches != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of wrenches " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasuredWrenches: " << nrOfMeasuredWrenches << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasured3AxisFT = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasured3AxisFT != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of 3 axis ft measures " << std::endl;
            return false;
        }
    }
    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasured3AxisFT: " << nrOfMeasured3AxisFT << std::endl;
    #endif

    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading rest of second line: " << data_buffer << std::endl;
    #endif

    //Third row: field names of the data (not parsed)
    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading third line: " << data_buffer << std::endl;
    #endif

    //All remaining rows are data
    if( !append ) {
        DynamicSample sample(nrOfDOFs,nrOfMeasuredTorques,nrOfMeasuredWrenches,nrOfMeasured3AxisFT);
        dynamic_samples.resize(0,sample);
    }

    #ifndef NDEBUG
    int count = 4;
    #endif

    while(getline(csv_file,line_buffer)) {
        std::stringstream ss(line_buffer);

         #ifndef NDEBUG
         std::cout << "DynamicDatasetFile::loadFromFile: Reading " << count << "th line : " << line_buffer << std::endl;
         count++;
         #endif

        //Get timestamp
        sample.setTimestamp(get_next_double(ss,data_buffer));

        //Get world base orientation (colum major)
        {
            KDL::Rotation world_base_orientation;
            world_base_orientation(0,0) = get_next_double(ss,data_buffer);
            world_base_orientation(1,0) = get_next_double(ss,data_buffer);
            world_base_orientation(2,0) = get_next_double(ss,data_buffer);
            world_base_orientation(0,1) = get_next_double(ss,data_buffer);
            world_base_orientation(1,1) = get_next_double(ss,data_buffer);
            world_base_orientation(2,1) = get_next_double(ss,data_buffer);
            world_base_orientation(0,2) = get_next_double(ss,data_buffer);
            world_base_orientation(1,2) = get_next_double(ss,data_buffer);
            world_base_orientation(2,2) = get_next_double(ss,data_buffer);

            KDL::Vector world_base_position;
            world_base_position(0) = get_next_double(ss,data_buffer);
            world_base_position(1) = get_next_double(ss,data_buffer);
            world_base_position(2) = get_next_double(ss,data_buffer);

            sample.setWorldBaseTransform(KDL::Frame(world_base_orientation,world_base_position));
        }

        //Get base velocity
        {
            KDL::Twist v_base;
            for(int i=0; i < 6; i++ ) {
                v_base[i] = get_next_double(ss,data_buffer);
            }
            sample.getBaseVelocity() = v_base;
        }

        //Get base velocity
        {
            KDL::Twist a_base;
            for(int i=0; i < 6; i++ ) {
                a_base[i] = get_next_double(ss,data_buffer);
            }
            sample.setBaseClassicalAcceleration(a_base);
        }

        //Get joint positions
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointPosition(get_next_double(ss,data_buffer),i);
        }

        //Get joint speeds
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointVelocity(get_next_double(ss,data_buffer),i);
        }

        //Get joint accelerations
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointAcceleration(get_next_double(ss,data_buffer),i);
        }

        //Get torques measurments
        for(int i=0; i < nrOfMeasuredTorques; i++ ) {
            sample.setTorqueMeasure(get_next_double(ss,data_buffer),i);
        }

        //Get wrench measurements
        for(int i=0; i < nrOfMeasuredWrenches; i++) {
            KDL::Wrench f;
            for(int j=0; j < 6; j++ ) {
                f[j] = get_next_double(ss,data_buffer);
            }
            sample.setWrenchMeasure(f,i);
        }

        //Get 3 axis force/torque measurements
        for(int i=0; i < nrOfMeasured3AxisFT; i++ ) {
            Eigen::Vector3d three_ft;
            three_ft(0) = get_next_double(ss,data_buffer);
            three_ft(1) = get_next_double(ss,data_buffer);
            three_ft(2) = get_next_double(ss,data_buffer);
            sample.setThreeAxisForceTorqueMeasure(three_ft,i);
        }

        //Adding the sample
        dynamic_samples.push_back(sample);
    }

    return true;
}

}<commit_msg>Fixed bug in dataset loading<commit_after>/*
 * Copyright (C) 2013 Silvio Traversaro
 * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 */

#include <fstream>
#include <iostream>
#include <sstream>

#include <dirl/dataset/DynamicDatasetFile.hpp>

namespace dirl {

DynamicDatasetFile::DynamicDatasetFile()
{

}

DynamicDatasetFile::~DynamicDatasetFile()
{

}

int DynamicDatasetFile::getNrOfSamples()
{
    return dynamic_samples.size();
}

bool DynamicDatasetFile::getSample(int sample_n, DynamicSample & sample)
{
    if( sample_n < 0 || sample_n >= getNrOfSamples() ) { return false; }
    sample = dynamic_samples[sample_n];
    return true;
}

double get_next_double(std::stringstream & ss,std::string & data_buffer)
{
    getline(ss,data_buffer,',');
    return atof(data_buffer.c_str());
}

bool DynamicDatasetFile::loadFromFile(const std::string file_name, const bool append)
{
    std::string data_buffer;
    std::string line_buffer;

    std::ifstream csv_file;

    #ifndef NDEBUG
    bool verbose = true;
    #endif

    csv_file.open (file_name.c_str(), std::ifstream::in);

    if( !csv_file ) {
        std::cerr << "DynamicDatasetFile error: it was not possible to open file " << file_name << std::endl;
        return false;
    }

    //First row: field names of the header (not useful)
    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading first row: " << data_buffer << std::endl;
    #endif

    //Second row: //N_DOFS,N_MEASURED_TORQUES,N_MEASURED_WRENCHES,N_MEASURED_3AXIS_FT,N_ADDITIONAL_ME
    getline(csv_file,data_buffer,',');
    if( !append ) {
        nrOfDOFs = atoi(data_buffer.c_str());
    } else {
        if( nrOfDOFs != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of DOFs " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfDOFs: " << nrOfDOFs << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasuredTorques = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasuredTorques != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of measured torques " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasuredTorques: " << nrOfMeasuredTorques << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasuredWrenches = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasuredWrenches != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of wrenches " << std::endl;
            return false;
        }
    }

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasuredWrenches: " << nrOfMeasuredWrenches << std::endl;
    #endif

    getline(csv_file,data_buffer,',');
    if( !append) {
        nrOfMeasured3AxisFT = atoi(data_buffer.c_str());
    } else {
        if( nrOfMeasured3AxisFT != atoi(data_buffer.c_str()) ) {
            std::cerr << "DynamicDatasetFile error: it was not possible to append file " << file_name
                      << " because it has a different number of 3 axis ft measures " << std::endl;
            return false;
        }
    }
    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading nrOfMeasured3AxisFT: " << nrOfMeasured3AxisFT << std::endl;
    #endif

    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading rest of second line: " << data_buffer << std::endl;
    #endif

    //Third row: field names of the data (not parsed)
    getline(csv_file,data_buffer);

    #ifndef NDEBUG
    std::cout << "DynamicDatasetFile::loadFromFile: Reading third line: " << data_buffer << std::endl;
    #endif

    //All remaining rows are data
    if( !append ) {
        DynamicSample sample(nrOfDOFs,nrOfMeasuredTorques,nrOfMeasuredWrenches,nrOfMeasured3AxisFT);
        dynamic_samples.resize(0,sample);
    }

    #ifndef NDEBUG
    int count = 4;
    #endif

    DynamicSample sample;

    while(getline(csv_file,line_buffer)) {
        std::stringstream ss(line_buffer);

         #ifndef NDEBUG
         std::cout << "DynamicDatasetFile::loadFromFile: Reading " << count << "th line : " << line_buffer << std::endl;
         count++;
         #endif

        //Get timestamp
        sample.setTimestamp(get_next_double(ss,data_buffer));

        //Get world base orientation (colum major)
        {
            KDL::Rotation world_base_orientation;
            world_base_orientation(0,0) = get_next_double(ss,data_buffer);
            world_base_orientation(1,0) = get_next_double(ss,data_buffer);
            world_base_orientation(2,0) = get_next_double(ss,data_buffer);
            world_base_orientation(0,1) = get_next_double(ss,data_buffer);
            world_base_orientation(1,1) = get_next_double(ss,data_buffer);
            world_base_orientation(2,1) = get_next_double(ss,data_buffer);
            world_base_orientation(0,2) = get_next_double(ss,data_buffer);
            world_base_orientation(1,2) = get_next_double(ss,data_buffer);
            world_base_orientation(2,2) = get_next_double(ss,data_buffer);

            KDL::Vector world_base_position;
            world_base_position(0) = get_next_double(ss,data_buffer);
            world_base_position(1) = get_next_double(ss,data_buffer);
            world_base_position(2) = get_next_double(ss,data_buffer);

            sample.setWorldBaseTransform(KDL::Frame(world_base_orientation,world_base_position));
        }

        //Get base velocity
        {
            KDL::Twist v_base;
            for(int i=0; i < 6; i++ ) {
                v_base[i] = get_next_double(ss,data_buffer);
            }
            sample.getBaseVelocity() = v_base;
        }

        //Get base velocity
        {
            KDL::Twist a_base;
            for(int i=0; i < 6; i++ ) {
                a_base[i] = get_next_double(ss,data_buffer);
            }
            sample.setBaseClassicalAcceleration(a_base);
        }

        //Get joint positions
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointPosition(get_next_double(ss,data_buffer),i);
        }

        //Get joint speeds
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointVelocity(get_next_double(ss,data_buffer),i);
        }

        //Get joint accelerations
        for(int i=0; i < nrOfDOFs; i++ ) {
            sample.setJointAcceleration(get_next_double(ss,data_buffer),i);
        }

        //Get torques measurments
        for(int i=0; i < nrOfMeasuredTorques; i++ ) {
            sample.setTorqueMeasure(get_next_double(ss,data_buffer),i);
        }

        //Get wrench measurements
        for(int i=0; i < nrOfMeasuredWrenches; i++) {
            KDL::Wrench f;
            for(int j=0; j < 6; j++ ) {
                f[j] = get_next_double(ss,data_buffer);
            }
            sample.setWrenchMeasure(f,i);
        }

        //Get 3 axis force/torque measurements
        for(int i=0; i < nrOfMeasured3AxisFT; i++ ) {
            Eigen::Vector3d three_ft;
            three_ft(0) = get_next_double(ss,data_buffer);
            three_ft(1) = get_next_double(ss,data_buffer);
            three_ft(2) = get_next_double(ss,data_buffer);
            sample.setThreeAxisForceTorqueMeasure(three_ft,i);
        }

        //Adding the sample
        dynamic_samples.push_back(sample);
    }

    return true;
}

}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "dwi/tractography/SIFT/proc_mask.h"

#include "transform.h"
#include "algo/copy.h"
#include "algo/threaded_loop.h"

namespace MR
{
  namespace DWI
  {
    namespace Tractography
    {
      namespace SIFT
      {

        const App::OptionGroup SIFTModelProcMaskOption = App::OptionGroup ("Options for setting the processing mask for the SIFT fixel-streamlines comparison model")

          + App::Option ("proc_mask", "provide an image containing the processing mask weights for the model; image spatial dimensions must match the fixel image")
            + App::Argument ("image").type_image_in()

          + App::Option ("act", "use an ACT five-tissue-type segmented anatomical image to derive the processing mask")
            + App::Argument ("image").type_image_in();

        void initialise_processing_mask (Image<float>& in_dwi, Image<float>& out_mask, Image<float>& out_5tt)
        {
          // User-specified processing mask
          auto opt = App::get_options ("proc_mask");
          if (opt.size()) {
            auto image = Image<float>::open (opt[0][0]);
            if (!dimensions_match (out_mask, image, 0, 3))
              throw Exception ("Dimensions of processing mask image provided using -proc_mask option must match relevant fixel image");
            copy_with_progress_message ("Copying processing mask to memory", image, out_mask, 0, 3);

          } else {
            auto opt = App::get_options ("act");
            if (opt.size()) {

              auto in_5tt = Image<float>::open (opt[0][0]);
              ACT::verify_5TT_image (in_5tt);

              Header H_5tt = in_dwi.original_header();
              H_5tt.set_ndim (4);
              H_5tt.size(3) = 5;
              assert (!out_5tt.valid());
              out_5tt = Image<float>::scratch (H_5tt, "5TT scratch buffer");

              // Test to see if the image has already been re-gridded to match the fixel image
              // If it has, can do a direct import
              if (dimensions_match (out_5tt, in_5tt, 0, 3)) {
                INFO ("5TT image dimensions match fixel image - importing directly");
                copy (in_5tt, out_5tt);
              } else {
                auto threaded_loop  = ThreadedLoop ("resampling ACT 5TT image to fixel image space", in_dwi, 0, 3);
                ResampleFunctor functor (in_dwi, in_5tt, out_5tt);
                threaded_loop.run (functor);
              }

              // Once all of the 5TT data has been read in, use it to derive the processing mask
              out_5tt.index(3) = 2; // Access the WM fraction
              for (auto l = Loop (out_5tt, 0, 3) (out_5tt, out_mask); l; ++l)
                out_mask.value() = Math::pow2<float> (out_5tt.value()); // Processing mask value is the square of the WM fraction

            } else {

              auto f = [] (Image<float>& dwi, Image<float>& mask) {
                mask.value() = (dwi.value() && std::isfinite ((float) dwi.value())) ? 1.0 : 0.0;
              };
              ThreadedLoop ("Creating homogeneous processing mask", in_dwi, 0, 3).run (f, in_dwi, out_mask);

            }

          }

        }

        ResampleFunctor::ResampleFunctor (Image<float>& dwi, Image<float>& anat, Image<float>& out) :
            dwi (dwi),
            voxel2scanner (new transform_type (Transform(dwi).voxel2scanner.cast<float>())),
            interp_anat (anat),
            out (out)
        {
          dwi.index(3) = 0;
        }

        ResampleFunctor::ResampleFunctor (const ResampleFunctor& that) :
            dwi (that.dwi),
            voxel2scanner (that.voxel2scanner),
            interp_anat (that.interp_anat),
            out (that.out)
        {
          dwi.index(3) = 0;
        }

        void ResampleFunctor::operator() (const Iterator& pos)
        {
          assign_pos_of (pos).to (dwi, out);
          if (dwi.value() && std::isfinite ((float) dwi.value())) {
            const ACT::Tissues tissues = ACT2pve (pos);
            out.index (3) = 0; out.value() = tissues.get_cgm();
            out.index (3) = 1; out.value() = tissues.get_sgm();
            out.index (3) = 2; out.value() = tissues.get_wm();
            out.index (3) = 3; out.value() = tissues.get_csf();
            out.index (3) = 4; out.value() = tissues.get_path();
          } else {
            for (out.index(3) = 0; out.index(3) != 5; ++out.index(3))
              out.value() = 0.0;
          }
        }

        ACT::Tissues ResampleFunctor::ACT2pve (const Iterator& pos)
        {
          static const int os_ratio = 10;
          static const float os_step = 1.0 / float(os_ratio);
          static const float os_offset = 0.5 * os_step;

          size_t cgm_count = 0, sgm_count = 0, wm_count = 0, csf_count = 0, path_count = 0, total_count = 0;

          Eigen::Array3i i;
          Eigen::Vector3f subvoxel_pos_dwi;
          for (i[2] = 0; i[2] != os_ratio; ++i[2]) {
            subvoxel_pos_dwi[2] = pos.index(2) - 0.5 + os_offset + (i[2] * os_step);
            for (i[1] = 0; i[1] != os_ratio; ++i[1]) {
              subvoxel_pos_dwi[1] = pos.index(1) - 0.5 + os_offset + (i[1] * os_step);
              for (i[0] = 0; i[0] != os_ratio; ++i[0]) {
                subvoxel_pos_dwi[0] = pos.index(0) - 0.5 + os_offset + (i[0] * os_step);

                const auto p_scanner (*voxel2scanner * subvoxel_pos_dwi);
                if (interp_anat.scanner (p_scanner)) {
                  const Tractography::ACT::Tissues tissues (interp_anat);
                  ++total_count;
                  if (tissues.valid()) {
                    if (tissues.is_cgm())
                      ++cgm_count;
                    else if (tissues.is_sgm())
                      ++sgm_count;
                    else if (tissues.is_wm())
                      ++wm_count;
                    else if (tissues.is_csf())
                      ++csf_count;
                    else if (tissues.is_path())
                      ++path_count;
                    else
                      --total_count; // Should ideally never happen...
                  }
                }

          } } }

          if (total_count) {
            return ACT::Tissues (cgm_count  / float(total_count),
                                 sgm_count  / float(total_count),
                                 wm_count   / float(total_count),
                                 csf_count  / float(total_count),
                                 path_count / float(total_count));
          } else {
            return ACT::Tissues ();
          }
        }

      }
    }
  }
}

<commit_msg>SIFT model: Detect empty processing mask<commit_after>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "dwi/tractography/SIFT/proc_mask.h"

#include "transform.h"
#include "algo/copy.h"
#include "algo/threaded_loop.h"

namespace MR
{
  namespace DWI
  {
    namespace Tractography
    {
      namespace SIFT
      {

        const App::OptionGroup SIFTModelProcMaskOption = App::OptionGroup ("Options for setting the processing mask for the SIFT fixel-streamlines comparison model")

          + App::Option ("proc_mask", "provide an image containing the processing mask weights for the model; image spatial dimensions must match the fixel image")
            + App::Argument ("image").type_image_in()

          + App::Option ("act", "use an ACT five-tissue-type segmented anatomical image to derive the processing mask")
            + App::Argument ("image").type_image_in();

        void initialise_processing_mask (Image<float>& in_dwi, Image<float>& out_mask, Image<float>& out_5tt)
        {
          // User-specified processing mask
          auto opt = App::get_options ("proc_mask");
          if (opt.size()) {
            auto image = Image<float>::open (opt[0][0]);
            if (!dimensions_match (out_mask, image, 0, 3))
              throw Exception ("Dimensions of processing mask image provided using -proc_mask option must match relevant fixel image");
            copy_with_progress_message ("Copying processing mask to memory", image, out_mask, 0, 3);

          } else {
            auto opt = App::get_options ("act");
            if (opt.size()) {

              auto in_5tt = Image<float>::open (opt[0][0]);
              ACT::verify_5TT_image (in_5tt);

              Header H_5tt = in_dwi.original_header();
              H_5tt.set_ndim (4);
              H_5tt.size(3) = 5;
              assert (!out_5tt.valid());
              out_5tt = Image<float>::scratch (H_5tt, "5TT scratch buffer");

              // Test to see if the image has already been re-gridded to match the fixel image
              // If it has, can do a direct import
              if (dimensions_match (out_5tt, in_5tt, 0, 3)) {
                INFO ("5TT image dimensions match fixel image - importing directly");
                copy (in_5tt, out_5tt);
              } else {
                auto threaded_loop  = ThreadedLoop ("resampling ACT 5TT image to fixel image space", in_dwi, 0, 3);
                ResampleFunctor functor (in_dwi, in_5tt, out_5tt);
                threaded_loop.run (functor);
              }

              // Once all of the 5TT data has been read in, use it to derive the processing mask
              out_5tt.index(3) = 2; // Access the WM fraction
              float integral = 0.0f;
              for (auto l = Loop (out_5tt, 0, 3) (out_5tt, out_mask); l; ++l) {
                const float value = Math::pow2<float> (out_5tt.value()); // Processing mask value is the square of the WM fraction
                out_mask.value() = value;
                integral += value;
              }
              if (!integral)
                throw Exception ("Processing mask is empty; check input images / registration");

            } else {

              auto f = [] (Image<float>& dwi, Image<float>& mask) {
                mask.value() = (dwi.value() && std::isfinite ((float) dwi.value())) ? 1.0 : 0.0;
              };
              ThreadedLoop ("Creating homogeneous processing mask", in_dwi, 0, 3).run (f, in_dwi, out_mask);

            }

          }

        }

        ResampleFunctor::ResampleFunctor (Image<float>& dwi, Image<float>& anat, Image<float>& out) :
            dwi (dwi),
            voxel2scanner (new transform_type (Transform(dwi).voxel2scanner.cast<float>())),
            interp_anat (anat),
            out (out)
        {
          dwi.index(3) = 0;
        }

        ResampleFunctor::ResampleFunctor (const ResampleFunctor& that) :
            dwi (that.dwi),
            voxel2scanner (that.voxel2scanner),
            interp_anat (that.interp_anat),
            out (that.out)
        {
          dwi.index(3) = 0;
        }

        void ResampleFunctor::operator() (const Iterator& pos)
        {
          assign_pos_of (pos).to (dwi, out);
          if (dwi.value() && std::isfinite ((float) dwi.value())) {
            const ACT::Tissues tissues = ACT2pve (pos);
            out.index (3) = 0; out.value() = tissues.get_cgm();
            out.index (3) = 1; out.value() = tissues.get_sgm();
            out.index (3) = 2; out.value() = tissues.get_wm();
            out.index (3) = 3; out.value() = tissues.get_csf();
            out.index (3) = 4; out.value() = tissues.get_path();
          } else {
            for (out.index(3) = 0; out.index(3) != 5; ++out.index(3))
              out.value() = 0.0;
          }
        }

        ACT::Tissues ResampleFunctor::ACT2pve (const Iterator& pos)
        {
          static const int os_ratio = 10;
          static const float os_step = 1.0 / float(os_ratio);
          static const float os_offset = 0.5 * os_step;

          size_t cgm_count = 0, sgm_count = 0, wm_count = 0, csf_count = 0, path_count = 0, total_count = 0;

          Eigen::Array3i i;
          Eigen::Vector3f subvoxel_pos_dwi;
          for (i[2] = 0; i[2] != os_ratio; ++i[2]) {
            subvoxel_pos_dwi[2] = pos.index(2) - 0.5 + os_offset + (i[2] * os_step);
            for (i[1] = 0; i[1] != os_ratio; ++i[1]) {
              subvoxel_pos_dwi[1] = pos.index(1) - 0.5 + os_offset + (i[1] * os_step);
              for (i[0] = 0; i[0] != os_ratio; ++i[0]) {
                subvoxel_pos_dwi[0] = pos.index(0) - 0.5 + os_offset + (i[0] * os_step);

                const auto p_scanner (*voxel2scanner * subvoxel_pos_dwi);
                if (interp_anat.scanner (p_scanner)) {
                  const Tractography::ACT::Tissues tissues (interp_anat);
                  ++total_count;
                  if (tissues.valid()) {
                    if (tissues.is_cgm())
                      ++cgm_count;
                    else if (tissues.is_sgm())
                      ++sgm_count;
                    else if (tissues.is_wm())
                      ++wm_count;
                    else if (tissues.is_csf())
                      ++csf_count;
                    else if (tissues.is_path())
                      ++path_count;
                    else
                      --total_count; // Should ideally never happen...
                  }
                }

          } } }

          if (total_count) {
            return ACT::Tissues (cgm_count  / float(total_count),
                                 sgm_count  / float(total_count),
                                 wm_count   / float(total_count),
                                 csf_count  / float(total_count),
                                 path_count / float(total_count));
          } else {
            return ACT::Tissues ();
          }
        }

      }
    }
  }
}

<|endoftext|>


<commit_before>#include <complex>
#include <af/defines.h>
#include <af/dim4.hpp>
#include <af/reduce.h>
#include <err_common.hpp>
#include <handle.hpp>
#include <ops.hpp>
#include <backend.hpp>
#include <reduce.hpp>

using af::dim4;
using namespace detail;

template<af_op_t op, typename Ti, typename To>
static inline af_array reduce(const af_array in, const int dim)
{
    return getHandle(*reduce<op,Ti,To>(getArray<Ti>(in), dim));
}

template<af_op_t op, typename To>
static af_err reduce_type(af_array *out, const af_array in, const int dim)
{
    if (dim <  0) return AF_ERR_ARG;
    if (dim >= 4) return AF_ERR_ARG;

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        // FIXME: Need to change types for corner cases
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

   af_err ret = AF_SUCCESS;

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , To>(in, dim); break;
        case f64:  res = reduce<op, double , To>(in, dim); break;
        case c32:  res = reduce<op, cfloat , To>(in, dim); break;
        case c64:  res = reduce<op, cdouble, To>(in, dim); break;
        case u32:  res = reduce<op, uint   , To>(in, dim); break;
        case s32:  res = reduce<op, int    , To>(in, dim); break;
        case b8:   res = reduce<op, uchar  , To>(in, dim); break;
        case u8:   res = reduce<op, uchar  , To>(in, dim); break;
        case s8:   res = reduce<op, char   , To>(in, dim); break;
        default:
            ret = AF_ERR_NOT_SUPPORTED;
        }

        std::swap(*out, res);
        ret = AF_SUCCESS;
    }
    CATCHALL;

    return ret;
}

template<af_op_t op>
static af_err reduce_common(af_array *out, const af_array in, const int dim)
{
    if (dim <  0) return AF_ERR_ARG;
    if (dim >= 4) return AF_ERR_ARG;

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

    af_err ret = AF_SUCCESS;

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , float  >(in, dim); break;
        case f64:  res = reduce<op, double , double >(in, dim); break;
        case c32:  res = reduce<op, cfloat , cfloat >(in, dim); break;
        case c64:  res = reduce<op, cdouble, cdouble>(in, dim); break;
        case u32:  res = reduce<op, uint   , uint   >(in, dim); break;
        case s32:  res = reduce<op, int    , int    >(in, dim); break;
        case b8:   res = reduce<op, uchar  , uchar  >(in, dim); break;
        case u8:   res = reduce<op, uchar  , uchar  >(in, dim); break;
        case s8:   res = reduce<op, char   , char   >(in, dim); break;
        default:
            ret = AF_ERR_NOT_SUPPORTED;
        }

        std::swap(*out, res);
        ret = AF_SUCCESS;
    }
    CATCHALL;

    return ret;
}

template<af_op_t op>
static af_err reduce_promote(af_array *out, const af_array in, const int dim)
{

    if (dim <  0) return AF_ERR_ARG;
    if (dim >= 4) return AF_ERR_ARG;

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        // FIXME: Need to promote types for corner cases
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

    af_err ret = AF_SUCCESS;

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , float  >(in, dim); break;
        case f64:  res = reduce<op, double , double >(in, dim); break;
        case c32:  res = reduce<op, cfloat , cfloat >(in, dim); break;
        case c64:  res = reduce<op, cdouble, cdouble>(in, dim); break;
        case u32:  res = reduce<op, uint   , uint   >(in, dim); break;
        case s32:  res = reduce<op, int    , int    >(in, dim); break;
        case u8:   res = reduce<op, uchar  , uint   >(in, dim); break;
        case s8:   res = reduce<op, char   , int    >(in, dim); break;
        // Make sure you are adding only "1" for every non zero value, even if op == af_add_t
        case b8:   res = reduce<af_notzero_t, uchar  , uint   >(in, dim); break;
        default:
            ret = AF_ERR_NOT_SUPPORTED;
        }
        std::swap(*out, res);
        ret = AF_SUCCESS;
    }
    CATCHALL;

    return ret;
}

af_err af_min(af_array *out, const af_array in, const int dim)
{
    return reduce_common<af_min_t>(out, in, dim);
}

af_err af_max(af_array *out, const af_array in, const int dim)
{
    return reduce_common<af_max_t>(out, in, dim);
}

af_err af_sum(af_array *out, const af_array in, const int dim)
{
    return reduce_promote<af_add_t>(out, in, dim);
}

af_err af_count(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_notzero_t, uint>(out, in, dim);
}

af_err af_alltrue(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_and_t, uchar>(out, in, dim);
}

af_err af_anytrue(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_or_t, uchar>(out, in, dim);
}
<commit_msg>Changed backend/reduce.cpp to include the new error mechanisms<commit_after>#include <complex>
#include <af/defines.h>
#include <af/dim4.hpp>
#include <af/reduce.h>
#include <err_common.hpp>
#include <handle.hpp>
#include <ops.hpp>
#include <backend.hpp>
#include <reduce.hpp>

using af::dim4;
using namespace detail;

template<af_op_t op, typename Ti, typename To>
static inline af_array reduce(const af_array in, const int dim)
{
    return getHandle(*reduce<op,Ti,To>(getArray<Ti>(in), dim));
}

template<af_op_t op, typename To>
static af_err reduce_type(af_array *out, const af_array in, const int dim)
{
    ARG_ASSERT(2, dim >= 0);
    ARG_ASSERT(2, dim <  4);

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        // FIXME: Need to change types for corner cases
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , To>(in, dim); break;
        case f64:  res = reduce<op, double , To>(in, dim); break;
        case c32:  res = reduce<op, cfloat , To>(in, dim); break;
        case c64:  res = reduce<op, cdouble, To>(in, dim); break;
        case u32:  res = reduce<op, uint   , To>(in, dim); break;
        case s32:  res = reduce<op, int    , To>(in, dim); break;
        case b8:   res = reduce<op, uchar  , To>(in, dim); break;
        case u8:   res = reduce<op, uchar  , To>(in, dim); break;
        case s8:   res = reduce<op, char   , To>(in, dim); break;
        default:   TYPE_ERROR(1, type);
        }

        std::swap(*out, res);
    }
    CATCHALL;

    return AF_SUCCESS;
}

template<af_op_t op>
static af_err reduce_common(af_array *out, const af_array in, const int dim)
{
    ARG_ASSERT(2, dim >= 0);
    ARG_ASSERT(2, dim <  4);

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , float  >(in, dim); break;
        case f64:  res = reduce<op, double , double >(in, dim); break;
        case c32:  res = reduce<op, cfloat , cfloat >(in, dim); break;
        case c64:  res = reduce<op, cdouble, cdouble>(in, dim); break;
        case u32:  res = reduce<op, uint   , uint   >(in, dim); break;
        case s32:  res = reduce<op, int    , int    >(in, dim); break;
        case b8:   res = reduce<op, uchar  , uchar  >(in, dim); break;
        case u8:   res = reduce<op, uchar  , uchar  >(in, dim); break;
        case s8:   res = reduce<op, char   , char   >(in, dim); break;
        default:   TYPE_ERROR(1, type);
        }

        std::swap(*out, res);
    }
    CATCHALL;

    return AF_SUCCESS;
}

template<af_op_t op>
static af_err reduce_promote(af_array *out, const af_array in, const int dim)
{

    ARG_ASSERT(2, dim >= 0);
    ARG_ASSERT(2, dim <  4);

    const ArrayInfo in_info = getInfo(in);

    if (dim >= (int)in_info.ndims()) {
        // FIXME: Implement a simple assignment function which increments the reference count of parent
        // FIXME: Need to promote types for corner cases
        const af_seq indx[] = {span, span, span, span};
        return af_index(out, in, 4, indx);
    }

    try {
        af_dtype type = in_info.getType();
        af_array res;

        switch(type) {
        case f32:  res = reduce<op, float  , float  >(in, dim); break;
        case f64:  res = reduce<op, double , double >(in, dim); break;
        case c32:  res = reduce<op, cfloat , cfloat >(in, dim); break;
        case c64:  res = reduce<op, cdouble, cdouble>(in, dim); break;
        case u32:  res = reduce<op, uint   , uint   >(in, dim); break;
        case s32:  res = reduce<op, int    , int    >(in, dim); break;
        case u8:   res = reduce<op, uchar  , uint   >(in, dim); break;
        case s8:   res = reduce<op, char   , int    >(in, dim); break;
        // Make sure you are adding only "1" for every non zero value, even if op == af_add_t
        case b8:   res = reduce<af_notzero_t, uchar  , uint   >(in, dim); break;
        default:   TYPE_ERROR(1, type);
        }
        std::swap(*out, res);
    }
    CATCHALL;

    return AF_SUCCESS;
}

af_err af_min(af_array *out, const af_array in, const int dim)
{
    return reduce_common<af_min_t>(out, in, dim);
}

af_err af_max(af_array *out, const af_array in, const int dim)
{
    return reduce_common<af_max_t>(out, in, dim);
}

af_err af_sum(af_array *out, const af_array in, const int dim)
{
    return reduce_promote<af_add_t>(out, in, dim);
}

af_err af_count(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_notzero_t, uint>(out, in, dim);
}

af_err af_alltrue(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_and_t, uchar>(out, in, dim);
}

af_err af_anytrue(af_array *out, const af_array in, const int dim)
{
    return reduce_type<af_or_t, uchar>(out, in, dim);
}
<|endoftext|>