<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include "CustomPaintWidget.h"
#include <math.h>
#include <QPainter>
#include "Code/CaptureContext.h"
#include "renderdoc_replay.h"

CustomPaintWidget::CustomPaintWidget(QWidget *parent) : QWidget(parent)
{
  m_Ctx = NULL;
  m_Output = NULL;
  setAttribute(Qt::WA_OpaquePaintEvent);
  setAttribute(Qt::WA_PaintOnScreen);
  setMouseTracking(true);
}

CustomPaintWidget::CustomPaintWidget(CaptureContext *c, QWidget *parent) : QWidget(parent)
{
  m_Ctx = c;
  m_Output = NULL;
  setAttribute(Qt::WA_OpaquePaintEvent);
  setAttribute(Qt::WA_PaintOnScreen);
  setMouseTracking(true);
}

CustomPaintWidget::~CustomPaintWidget()
{
}

void CustomPaintWidget::mousePressEvent(QMouseEvent *e)
{
  emit clicked(e);
}

void CustomPaintWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
  emit(doubleClicked(event));
}

void CustomPaintWidget::mouseMoveEvent(QMouseEvent *e)
{
  emit mouseMove(e);
}

void CustomPaintWidget::wheelEvent(QWheelEvent *e)
{
  emit mouseWheel(e);
}

void CustomPaintWidget::resizeEvent(QResizeEvent *e)
{
  emit resize(e);
}

void CustomPaintWidget::keyPressEvent(QKeyEvent *e)
{
  emit keyPress(e);
}

void CustomPaintWidget::paintEvent(QPaintEvent *e)
{
  if(m_Ctx)
  {
    if(m_Output != NULL)
      m_Ctx->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { m_Output->Display(); });
  }
  else if(m_Dark == m_Light)
  {
    QPainter p(this);
    p.fillRect(rect(), m_Dark);
  }
  else
  {
    int numX = (int)ceil((float)rect().width() / 64.0f);
    int numY = (int)ceil((float)rect().height() / 64.0f);

    QPainter p(this);
    for(int x = 0; x < numX; x++)
    {
      for(int y = 0; y < numY; y++)
      {
        QColor &col = ((x % 2) == (y % 2)) ? m_Dark : m_Light;

        p.fillRect(QRect(x * 64, y * 64, 64, 64), col);
      }
    }
  }
}
<commit_msg>Only set WA_PaintOnScreen when doing custom painting<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include "CustomPaintWidget.h"
#include <math.h>
#include <QPainter>
#include "Code/CaptureContext.h"
#include "renderdoc_replay.h"

CustomPaintWidget::CustomPaintWidget(QWidget *parent) : QWidget(parent)
{
  m_Ctx = NULL;
  m_Output = NULL;
  setAttribute(Qt::WA_OpaquePaintEvent);
  setMouseTracking(true);
}

CustomPaintWidget::CustomPaintWidget(CaptureContext *c, QWidget *parent) : QWidget(parent)
{
  m_Ctx = c;
  m_Output = NULL;
  setAttribute(Qt::WA_OpaquePaintEvent);
  if(c)
    setAttribute(Qt::WA_PaintOnScreen);
  setMouseTracking(true);
}

CustomPaintWidget::~CustomPaintWidget()
{
}

void CustomPaintWidget::mousePressEvent(QMouseEvent *e)
{
  emit clicked(e);
}

void CustomPaintWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
  emit(doubleClicked(event));
}

void CustomPaintWidget::mouseMoveEvent(QMouseEvent *e)
{
  emit mouseMove(e);
}

void CustomPaintWidget::wheelEvent(QWheelEvent *e)
{
  emit mouseWheel(e);
}

void CustomPaintWidget::resizeEvent(QResizeEvent *e)
{
  emit resize(e);
}

void CustomPaintWidget::keyPressEvent(QKeyEvent *e)
{
  emit keyPress(e);
}

void CustomPaintWidget::paintEvent(QPaintEvent *e)
{
  if(m_Ctx)
  {
    if(m_Output != NULL)
      m_Ctx->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { m_Output->Display(); });
  }
  else if(m_Dark == m_Light)
  {
    QPainter p(this);
    p.fillRect(rect(), m_Dark);
  }
  else
  {
    int numX = (int)ceil((float)rect().width() / 64.0f);
    int numY = (int)ceil((float)rect().height() / 64.0f);

    QPainter p(this);
    for(int x = 0; x < numX; x++)
    {
      for(int y = 0; y < numY; y++)
      {
        QColor &col = ((x % 2) == (y % 2)) ? m_Dark : m_Light;

        p.fillRect(QRect(x * 64, y * 64, 64, 64), col);
      }
    }
  }
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2016 WandererFan <wandererfan@gmail.com>                *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#include <QPainter>
#include <QPainterPathStroker>
#include <QStyleOptionGraphicsItem>
#endif

#include <App/Application.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Parameter.h>

#include <Mod/TechDraw/App/DrawUtil.h>

#include <qmath.h>
#include "Rez.h"
#include "QGIView.h"
#include "QGISectionLine.h"

using namespace TechDrawGui;

QGISectionLine::QGISectionLine()
{
    m_symbol = "";
    m_symSize = 0.0;

    m_extLen = Rez::guiX(QGIArrow::getPrefArrowSize());
    m_arrowSize = QGIArrow::getPrefArrowSize();

    m_line = new QGraphicsPathItem();
    addToGroup(m_line);
    m_arrow1 = new QGIArrow();
    addToGroup(m_arrow1);
    m_arrow2 = new QGIArrow();
    addToGroup(m_arrow2);
    m_symbol1 = new QGCustomText();
    addToGroup(m_symbol1);
    m_symbol2 = new QGCustomText();
    addToGroup(m_symbol2);

    setWidth(Rez::guiX(0.75));
    setStyle(getSectionStyle());
    setColor(getSectionColor());

}

void QGISectionLine::draw()
{
    prepareGeometryChange();
    makeLine();
    makeArrows();
    makeSymbols();
    update();
}

void QGISectionLine::makeLine()
{
    QPainterPath pp;
    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);
    int format = getPrefSectionFormat();
    if (format == 0) {                           //"ASME"
        offset = 0.75 * m_extLen * offset;                  //0.75 is hack to hide line end behind arrowhead
        extLineStart = m_start + offset;
        extLineEnd = m_end + offset;
    } else {                                     //"ISO"
        offset = 2.0* m_extLen * offset;
        extLineStart = m_start - offset;
        extLineEnd = m_end - offset;
    }

    pp.moveTo(extLineStart);
    pp.lineTo(m_start);
    pp.lineTo(m_end);
    pp.lineTo(extLineEnd);
    m_line->setPath(pp);
}

void QGISectionLine::makeArrows()
{
    int format = getPrefSectionFormat();
    if (format == 0) {
        makeArrowsTrad();
    } else {
        makeArrowsISO();
    }
}
//make Euro (ISO) Arrows
void QGISectionLine::makeArrowsISO()
{
    double arrowRotation = 0.0;
    m_arrowDir.Normalize();
    double angle = atan2f(m_arrowDir.y,m_arrowDir.x);
    if (angle < 0.0) {
        angle = 2 * M_PI + angle;
    }
    arrowRotation = 360.0 - angle * (180.0/M_PI);   //convert to Qt rotation (clockwise degrees)

    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);              //remember Y dir is flipped
    offset = (m_extLen + (2.0 * QGIArrow::getPrefArrowSize())) * offset * -1.0;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;

    m_arrow1->setStyle(0);
    m_arrow1->setSize(QGIArrow::getPrefArrowSize());
    m_arrow1->setPos(m_start);
    m_arrow1->draw();
    m_arrow1->setRotation(arrowRotation);                   //rotation = 0  ==>  ->  horizontal, pointing right

    m_arrow2->setStyle(0);
    m_arrow2->setSize(QGIArrow::getPrefArrowSize());
    m_arrow2->setPos(m_end);
    m_arrow2->draw();
    m_arrow2->setRotation(arrowRotation);
}

//make traditional (ASME) section arrows
void QGISectionLine::makeArrowsTrad()
{
    double arrowRotation = 0.0;
    m_arrowDir.Normalize();
    double angle = atan2f(m_arrowDir.y,m_arrowDir.x);
    if (angle < 0.0) {
        angle = 2 * M_PI + angle;
    }
    arrowRotation = 360.0 - angle * (180.0/M_PI);   //convert to Qt rotation (clockwise degrees)

    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);              //remember Y dir is flipped
    offset = (m_extLen + (2.0 * QGIArrow::getPrefArrowSize())) * offset;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;

    m_arrow1->setStyle(0);
    m_arrow1->setSize(QGIArrow::getPrefArrowSize());
    m_arrow1->setPos(extLineStart);
    m_arrow1->draw();
    m_arrow1->setRotation(arrowRotation);                   //rotation = 0  ==>  ->  horizontal, pointing right

    m_arrow2->setStyle(0);
    m_arrow2->setSize(QGIArrow::getPrefArrowSize());
    m_arrow2->setPos(extLineEnd);
    m_arrow2->draw();
    m_arrow2->setRotation(arrowRotation);
}

void QGISectionLine::makeSymbols()
{
    int format = getPrefSectionFormat();
    if (format == 0) {
        makeSymbolsTrad();
    } else {
        makeSymbolsISO();
    }
}

void QGISectionLine::makeSymbolsTrad()
{
    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);
    offset = 1.5 * m_extLen * offset;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;
    prepareGeometryChange();
    m_symFont.setPointSize(m_symSize);
    m_symbol1->setFont(m_symFont);
    m_symbol1->setPlainText(QString::fromUtf8(m_symbol));
    if (m_arrowDir.y < 0.0) {         //pointing down
        extLineStart  += QPointF (0.0, m_symSize);  //move text down a bit
    } else if (m_arrowDir.y >  0.0) {  //pointing up
        extLineStart  -= QPointF (0.0, m_symSize);  //move text up a bit
    }
    if (m_arrowDir.x < 0.0) {         //pointing left
        extLineStart  -= QPointF (m_symSize, 0.0);  //move text left a bit
    } else if (m_arrowDir.x >  0.0) {  //pointing rightup
        extLineStart  += QPointF (m_symSize, 0.0);  //move text right a bit
    }
    m_symbol1->centerAt(extLineStart);

    m_symbol2->setFont(m_symFont);
    m_symbol2->setPlainText(QString::fromUtf8(m_symbol));
    if (m_arrowDir.y < 0.0) {         //pointing down
        extLineEnd  += QPointF (0.0, m_symSize);  //move text down a bit
    } else if (m_arrowDir.y > 0.0) {  //pointing up
        extLineEnd  -= QPointF (0.0, m_symSize);  //move text up a bit
    }
     if (m_arrowDir.x < 0.0) {         //pointing left
        extLineEnd  -= QPointF (m_symSize, 0.0);  //move text left a bit
    } else if (m_arrowDir.x >  0.0) {  //pointing rightup
        extLineEnd  += QPointF (m_symSize, 0.0);  //move text right a bit
    }
    m_symbol2->centerAt(extLineEnd);

}

void QGISectionLine::makeSymbolsISO()
{
    QPointF symPosStart, symPosEnd;
    QPointF dist = (m_start - m_end);
    double lenDist = sqrt(dist.x()*dist.x() + dist.y()*dist.y());
    QPointF distDir = dist / lenDist;

    QPointF offset = m_extLen * distDir;
    symPosStart = m_start + offset;
    symPosEnd = m_end - offset;

    prepareGeometryChange();
    m_symFont.setPointSize(m_symSize);
    m_symbol1->setFont(m_symFont);
    m_symbol1->setPlainText(QString::fromUtf8(m_symbol));
    m_symbol1->centerAt(symPosStart);

    m_symbol2->setFont(m_symFont);
    m_symbol2->setPlainText(QString::fromUtf8(m_symbol));
    m_symbol2->centerAt(symPosEnd);

}

void QGISectionLine::setBounds(double x1,double y1,double x2,double y2)
{
    m_start = QPointF(x1,y1);
    m_end = QPointF(x2,y2);
}

void QGISectionLine::setSymbol(char* sym)
{
    m_symbol = sym;
}

void QGISectionLine::setDirection(double xDir,double yDir)
{
    Base::Vector3d newDir(xDir,yDir,0.0);
    setDirection(newDir);
}

void QGISectionLine::setDirection(Base::Vector3d dir)
{
    m_arrowDir = dir;
}

void QGISectionLine::setFont(QFont f, double fsize)
{
    m_symFont = f;
    m_symSize = fsize;
}

QColor QGISectionLine::getSectionColor()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors");
    App::Color fcColor = App::Color((uint32_t) hGrp->GetUnsigned("SectionColor", 0x00000000));
    return fcColor.asValue<QColor>();
}

//SectionLineStyle
Qt::PenStyle QGISectionLine::getSectionStyle()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
                                         GetGroup("Preferences")->GetGroup("Mod/TechDraw");
    Qt::PenStyle sectStyle = static_cast<Qt::PenStyle> (hGrp->GetInt("SectionLine", 2));
    return sectStyle;
}

//ASME("traditional") vs ISO("reference arrow method") arrows
int QGISectionLine::getPrefSectionFormat()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().
                                         GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Format");
    int format = hGrp->GetInt("SectionFormat", 0);
    return format;
}

void QGISectionLine::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
    QStyleOptionGraphicsItem myOption(*option);
    myOption.state &= ~QStyle::State_Selected;

    setTools();
    QGIDecoration::paint (painter, &myOption, widget);
}

void QGISectionLine::setTools()
{
    // Use our own style
    if (m_styleCurrent == Qt::DashDotLine) {
        QVector<qreal> dashes;
        // the stroke width is double the one of center lines, but we like to
        // have the same spacing. thus these values must be half as large
        qreal space = 2;  // in unit r_width
        qreal dash = 8;
        // dot must be really small when using CapStyle RoundCap but > 0
        // for CapStyle FlatCap you would need to set it to 1
        qreal dot = 0.000001;

        dashes << dot << space << dash << space;

        // TODO for fancyness: calculate the offset so both arrows start with a
        // dash!

        m_pen.setDashPattern(dashes);

        m_pen.setDashOffset(2);
    }
    else {
        m_pen.setStyle(m_styleCurrent);
    }
    m_pen.setWidthF(m_width);
    m_pen.setColor(m_colCurrent);
    m_pen.setCapStyle(Qt::RoundCap);
    m_brush.setStyle(m_brushCurrent);
    m_brush.setColor(m_colCurrent);

    m_line->setPen(m_pen);

    m_arrow1->setPen(m_pen);
    m_arrow2->setPen(m_pen);
    m_arrow1->setBrush(m_brush);
    m_arrow2->setBrush(m_brush);

    m_symbol1->setDefaultTextColor(m_colCurrent);
    m_symbol2->setDefaultTextColor(m_colCurrent);
}
<commit_msg>Fix SectionLine preference location<commit_after>/***************************************************************************
 *   Copyright (c) 2016 WandererFan <wandererfan@gmail.com>                *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#include <QPainter>
#include <QPainterPathStroker>
#include <QStyleOptionGraphicsItem>
#endif

#include <App/Application.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Parameter.h>

#include <Mod/TechDraw/App/DrawUtil.h>

#include <qmath.h>
#include "Rez.h"
#include "QGIView.h"
#include "QGISectionLine.h"

using namespace TechDrawGui;

QGISectionLine::QGISectionLine()
{
    m_symbol = "";
    m_symSize = 0.0;

    m_extLen = Rez::guiX(QGIArrow::getPrefArrowSize());
    m_arrowSize = QGIArrow::getPrefArrowSize();

    m_line = new QGraphicsPathItem();
    addToGroup(m_line);
    m_arrow1 = new QGIArrow();
    addToGroup(m_arrow1);
    m_arrow2 = new QGIArrow();
    addToGroup(m_arrow2);
    m_symbol1 = new QGCustomText();
    addToGroup(m_symbol1);
    m_symbol2 = new QGCustomText();
    addToGroup(m_symbol2);

    setWidth(Rez::guiX(0.75));
    setStyle(getSectionStyle());
    setColor(getSectionColor());

}

void QGISectionLine::draw()
{
    prepareGeometryChange();
    makeLine();
    makeArrows();
    makeSymbols();
    update();
}

void QGISectionLine::makeLine()
{
    QPainterPath pp;
    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);
    int format = getPrefSectionFormat();
    if (format == 0) {                           //"ASME"
        offset = 0.75 * m_extLen * offset;                  //0.75 is hack to hide line end behind arrowhead
        extLineStart = m_start + offset;
        extLineEnd = m_end + offset;
    } else {                                     //"ISO"
        offset = 2.0* m_extLen * offset;
        extLineStart = m_start - offset;
        extLineEnd = m_end - offset;
    }

    pp.moveTo(extLineStart);
    pp.lineTo(m_start);
    pp.lineTo(m_end);
    pp.lineTo(extLineEnd);
    m_line->setPath(pp);
}

void QGISectionLine::makeArrows()
{
    int format = getPrefSectionFormat();
    if (format == 0) {
        makeArrowsTrad();
    } else {
        makeArrowsISO();
    }
}
//make Euro (ISO) Arrows
void QGISectionLine::makeArrowsISO()
{
    double arrowRotation = 0.0;
    m_arrowDir.Normalize();
    double angle = atan2f(m_arrowDir.y,m_arrowDir.x);
    if (angle < 0.0) {
        angle = 2 * M_PI + angle;
    }
    arrowRotation = 360.0 - angle * (180.0/M_PI);   //convert to Qt rotation (clockwise degrees)

    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);              //remember Y dir is flipped
    offset = (m_extLen + (2.0 * QGIArrow::getPrefArrowSize())) * offset * -1.0;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;

    m_arrow1->setStyle(0);
    m_arrow1->setSize(QGIArrow::getPrefArrowSize());
    m_arrow1->setPos(m_start);
    m_arrow1->draw();
    m_arrow1->setRotation(arrowRotation);                   //rotation = 0  ==>  ->  horizontal, pointing right

    m_arrow2->setStyle(0);
    m_arrow2->setSize(QGIArrow::getPrefArrowSize());
    m_arrow2->setPos(m_end);
    m_arrow2->draw();
    m_arrow2->setRotation(arrowRotation);
}

//make traditional (ASME) section arrows
void QGISectionLine::makeArrowsTrad()
{
    double arrowRotation = 0.0;
    m_arrowDir.Normalize();
    double angle = atan2f(m_arrowDir.y,m_arrowDir.x);
    if (angle < 0.0) {
        angle = 2 * M_PI + angle;
    }
    arrowRotation = 360.0 - angle * (180.0/M_PI);   //convert to Qt rotation (clockwise degrees)

    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);              //remember Y dir is flipped
    offset = (m_extLen + (2.0 * QGIArrow::getPrefArrowSize())) * offset;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;

    m_arrow1->setStyle(0);
    m_arrow1->setSize(QGIArrow::getPrefArrowSize());
    m_arrow1->setPos(extLineStart);
    m_arrow1->draw();
    m_arrow1->setRotation(arrowRotation);                   //rotation = 0  ==>  ->  horizontal, pointing right

    m_arrow2->setStyle(0);
    m_arrow2->setSize(QGIArrow::getPrefArrowSize());
    m_arrow2->setPos(extLineEnd);
    m_arrow2->draw();
    m_arrow2->setRotation(arrowRotation);
}

void QGISectionLine::makeSymbols()
{
    int format = getPrefSectionFormat();
    if (format == 0) {
        makeSymbolsTrad();
    } else {
        makeSymbolsISO();
    }
}

void QGISectionLine::makeSymbolsTrad()
{
    QPointF extLineStart,extLineEnd;
    QPointF offset(m_arrowDir.x,-m_arrowDir.y);
    offset = 1.5 * m_extLen * offset;
    extLineStart = m_start + offset;
    extLineEnd = m_end + offset;
    prepareGeometryChange();
    m_symFont.setPointSize(m_symSize);
    m_symbol1->setFont(m_symFont);
    m_symbol1->setPlainText(QString::fromUtf8(m_symbol));
    if (m_arrowDir.y < 0.0) {         //pointing down
        extLineStart  += QPointF (0.0, m_symSize);  //move text down a bit
    } else if (m_arrowDir.y >  0.0) {  //pointing up
        extLineStart  -= QPointF (0.0, m_symSize);  //move text up a bit
    }
    if (m_arrowDir.x < 0.0) {         //pointing left
        extLineStart  -= QPointF (m_symSize, 0.0);  //move text left a bit
    } else if (m_arrowDir.x >  0.0) {  //pointing rightup
        extLineStart  += QPointF (m_symSize, 0.0);  //move text right a bit
    }
    m_symbol1->centerAt(extLineStart);

    m_symbol2->setFont(m_symFont);
    m_symbol2->setPlainText(QString::fromUtf8(m_symbol));
    if (m_arrowDir.y < 0.0) {         //pointing down
        extLineEnd  += QPointF (0.0, m_symSize);  //move text down a bit
    } else if (m_arrowDir.y > 0.0) {  //pointing up
        extLineEnd  -= QPointF (0.0, m_symSize);  //move text up a bit
    }
     if (m_arrowDir.x < 0.0) {         //pointing left
        extLineEnd  -= QPointF (m_symSize, 0.0);  //move text left a bit
    } else if (m_arrowDir.x >  0.0) {  //pointing rightup
        extLineEnd  += QPointF (m_symSize, 0.0);  //move text right a bit
    }
    m_symbol2->centerAt(extLineEnd);

}

void QGISectionLine::makeSymbolsISO()
{
    QPointF symPosStart, symPosEnd;
    QPointF dist = (m_start - m_end);
    double lenDist = sqrt(dist.x()*dist.x() + dist.y()*dist.y());
    QPointF distDir = dist / lenDist;

    QPointF offset = m_extLen * distDir;
    symPosStart = m_start + offset;
    symPosEnd = m_end - offset;

    prepareGeometryChange();
    m_symFont.setPointSize(m_symSize);
    m_symbol1->setFont(m_symFont);
    m_symbol1->setPlainText(QString::fromUtf8(m_symbol));
    m_symbol1->centerAt(symPosStart);

    m_symbol2->setFont(m_symFont);
    m_symbol2->setPlainText(QString::fromUtf8(m_symbol));
    m_symbol2->centerAt(symPosEnd);

}

void QGISectionLine::setBounds(double x1,double y1,double x2,double y2)
{
    m_start = QPointF(x1,y1);
    m_end = QPointF(x2,y2);
}

void QGISectionLine::setSymbol(char* sym)
{
    m_symbol = sym;
}

void QGISectionLine::setDirection(double xDir,double yDir)
{
    Base::Vector3d newDir(xDir,yDir,0.0);
    setDirection(newDir);
}

void QGISectionLine::setDirection(Base::Vector3d dir)
{
    m_arrowDir = dir;
}

void QGISectionLine::setFont(QFont f, double fsize)
{
    m_symFont = f;
    m_symSize = fsize;
}

QColor QGISectionLine::getSectionColor()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors");
    App::Color fcColor = App::Color((uint32_t) hGrp->GetUnsigned("SectionColor", 0x00000000));
    return fcColor.asValue<QColor>();
}

//SectionLineStyle
Qt::PenStyle QGISectionLine::getSectionStyle()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
                                         GetGroup("Preferences")->GetGroup("Mod/TechDraw/Decorations");
    Qt::PenStyle sectStyle = static_cast<Qt::PenStyle> (hGrp->GetInt("SectionLine", 2));
    return sectStyle;
}

//ASME("traditional") vs ISO("reference arrow method") arrows
int QGISectionLine::getPrefSectionFormat()
{
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().
                                         GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Format");
    int format = hGrp->GetInt("SectionFormat", 0);
    return format;
}

void QGISectionLine::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
    QStyleOptionGraphicsItem myOption(*option);
    myOption.state &= ~QStyle::State_Selected;

    setTools();
    QGIDecoration::paint (painter, &myOption, widget);
}

void QGISectionLine::setTools()
{
    // Use our own style
    if (m_styleCurrent == Qt::DashDotLine) {
        QVector<qreal> dashes;
        // the stroke width is double the one of center lines, but we like to
        // have the same spacing. thus these values must be half as large
        qreal space = 2;  // in unit r_width
        qreal dash = 8;
        // dot must be really small when using CapStyle RoundCap but > 0
        // for CapStyle FlatCap you would need to set it to 1
        qreal dot = 0.000001;

        dashes << dot << space << dash << space;

        // TODO for fancyness: calculate the offset so both arrows start with a
        // dash!

        m_pen.setDashPattern(dashes);

        m_pen.setDashOffset(2);
    }
    else {
        m_pen.setStyle(m_styleCurrent);
    }
    m_pen.setWidthF(m_width);
    m_pen.setColor(m_colCurrent);
    m_pen.setCapStyle(Qt::RoundCap);
    m_brush.setStyle(m_brushCurrent);
    m_brush.setColor(m_colCurrent);

    m_line->setPen(m_pen);

    m_arrow1->setPen(m_pen);
    m_arrow2->setPen(m_pen);
    m_arrow1->setBrush(m_brush);
    m_arrow2->setBrush(m_brush);

    m_symbol1->setDefaultTextColor(m_colCurrent);
    m_symbol2->setDefaultTextColor(m_colCurrent);
}
<|endoftext|>


<commit_before>#include "nicolivemanager.h"
#include "../../ui/mainwindow.h"

NicoLiveManager::NicoLiveManager(MainWindow* mwin, AccountWindow* awin, NewWakuSettingsWindow* nwin, FollowCommunity* fwin, QObject *parent) :
  QObject(parent),
  nowWaku(mwin, this, this),
  wakutcp(nullptr),
  mPostKeyManager(nullptr),
  mLoginAlertManager(nullptr),
  mAdminAlertManager(nullptr),
  mHeartBeat(nullptr),
  mLoginManager(nullptr),
  mOwnerCommentManager(nullptr),
  mOwnerCommentSManager(nullptr),
  mRawMyLiveManager(nullptr),
  mTags(nullptr),
  mNewWaku(nullptr)
{
  this->mwin = mwin;
  this->awin = awin;
  this->nwin = nwin;
  this->fwin = fwin;

  // set timer to delete the ended elements in waku list.
  delWakuTimer = new QTimer(this);

  connect(delWakuTimer, SIGNAL(timeout()), this, SLOT(deleteWakuList()));
  delWakuTimer->start(15000);
}

NicoLiveManager::~NicoLiveManager()
{
  delWakuTimer->stop();
  delWakuTimer->deleteLater();
}

QVariant NicoLiveManager::makePostData(QString session_id)
{
  QVariant postData;

  // make cookies
  QList <QNetworkCookie> cookies;
  QNetworkCookie ck;
  ck.toRawForm(QNetworkCookie::NameAndValueOnly);
  ck.setName("user_session");

  QByteArray user_id_ba;
  user_id_ba.append(session_id);

  ck.setValue(user_id_ba);
  cookies.append(ck);

  postData.setValue(cookies);
  return postData;
}

void NicoLiveManager::insertLiveWakuList(LiveWaku* livewaku)
{
  const QString livewakuBID = livewaku->getBroadID();
  foreach (LiveWaku* alistwaku, liveWakuList) {
    if (livewakuBID == alistwaku->getBroadID()) {
      delete livewaku;
      return;
    }
  }

  livewaku->getPlayerStatusAPI();
  liveWakuList << livewaku;
}

void NicoLiveManager::broadStart()
{
  nowWaku.init();
  nowWaku.getPlayerStatusAPI();
}

void NicoLiveManager::broadDisconnect(bool disableFollow)
{
  mwin->setWatchCount("0");
  nowWaku.broadDisconnect();
  if (disableFollow)
    nowWaku.setCommunity("");
}

void NicoLiveManager::deleteWakuList()
{
  QDateTime nowTime = QDateTime::currentDateTimeUtc();
  for (int i = 0; i < liveWakuList.size(); ++i) {
    if ( nowTime > liveWakuList[i]->getEd() ) {
      liveWakuList[i]->getPlayerStatusAPI();
    }
  }
}

void NicoLiveManager::allGotWakuInfo(QString communityID, QString broadID)
{
  if (mwin->settings.isAutoNextWaku()) {
    if ( nowWaku.getCommunity() == communityID &&
         nowWaku.getBroadID() != broadID )
    {
      mwin->setHousouID(broadID);
      mwin->on_receive_clicked();

      if (mwin->settings.isCommandNextWakuChecked()) {
        QProcess pr;
        QString cmd = mwin->settings.getCommandNextWaku();

        cmd.replace("%wakuURL%","http://live.nicovideo.jp/watch/lv" + broadID);

        pr.start(cmd);
        pr.waitForFinished(5000);
      }
    }
  }
}

QString NicoLiveManager::HTMLdecode(QString st)
{
  st.replace("&", "&");
  st.replace("<", "<");
  st.replace(">", ">");
  return st;
}
<commit_msg>bug fix : mConfigure and mCommunityInfo was not initialized<commit_after>#include "nicolivemanager.h"
#include "../../ui/mainwindow.h"

NicoLiveManager::NicoLiveManager(MainWindow* mwin, AccountWindow* awin, NewWakuSettingsWindow* nwin, FollowCommunity* fwin, QObject *parent) :
  QObject(parent),
  nowWaku(mwin, this, this),
  wakutcp(nullptr),
  mPostKeyManager(nullptr),
  mLoginAlertManager(nullptr),
  mAdminAlertManager(nullptr),
  mHeartBeat(nullptr),
  mLoginManager(nullptr),
  mOwnerCommentManager(nullptr),
  mOwnerCommentSManager(nullptr),
  mRawMyLiveManager(nullptr),
  mTags(nullptr),
  mNewWaku(nullptr),
  mConfigure(nullptr),
  mCommunityInfo(nullptr)
{
  this->mwin = mwin;
  this->awin = awin;
  this->nwin = nwin;
  this->fwin = fwin;

  // set timer to delete the ended elements in waku list.
  delWakuTimer = new QTimer(this);

  connect(delWakuTimer, SIGNAL(timeout()), this, SLOT(deleteWakuList()));
  delWakuTimer->start(15000);
}

NicoLiveManager::~NicoLiveManager()
{
  delWakuTimer->stop();
  delWakuTimer->deleteLater();
}

QVariant NicoLiveManager::makePostData(QString session_id)
{
  QVariant postData;

  // make cookies
  QList <QNetworkCookie> cookies;
  QNetworkCookie ck;
  ck.toRawForm(QNetworkCookie::NameAndValueOnly);
  ck.setName("user_session");

  QByteArray user_id_ba;
  user_id_ba.append(session_id);

  ck.setValue(user_id_ba);
  cookies.append(ck);

  postData.setValue(cookies);
  return postData;
}

void NicoLiveManager::insertLiveWakuList(LiveWaku* livewaku)
{
  const QString livewakuBID = livewaku->getBroadID();
  foreach (LiveWaku* alistwaku, liveWakuList) {
    if (livewakuBID == alistwaku->getBroadID()) {
      delete livewaku;
      return;
    }
  }

  livewaku->getPlayerStatusAPI();
  liveWakuList << livewaku;
}

void NicoLiveManager::broadStart()
{
  nowWaku.init();
  nowWaku.getPlayerStatusAPI();
}

void NicoLiveManager::broadDisconnect(bool disableFollow)
{
  mwin->setWatchCount("0");
  nowWaku.broadDisconnect();
  if (disableFollow)
    nowWaku.setCommunity("");
}

void NicoLiveManager::deleteWakuList()
{
  QDateTime nowTime = QDateTime::currentDateTimeUtc();
  for (int i = 0; i < liveWakuList.size(); ++i) {
    if ( nowTime > liveWakuList[i]->getEd() ) {
      liveWakuList[i]->getPlayerStatusAPI();
    }
  }
}

void NicoLiveManager::allGotWakuInfo(QString communityID, QString broadID)
{
  if (mwin->settings.isAutoNextWaku()) {
    if ( nowWaku.getCommunity() == communityID &&
         nowWaku.getBroadID() != broadID )
    {
      mwin->setHousouID(broadID);
      mwin->on_receive_clicked();

      if (mwin->settings.isCommandNextWakuChecked()) {
        QProcess pr;
        QString cmd = mwin->settings.getCommandNextWaku();

        cmd.replace("%wakuURL%","http://live.nicovideo.jp/watch/lv" + broadID);

        pr.start(cmd);
        pr.waitForFinished(5000);
      }
    }
  }
}

QString NicoLiveManager::HTMLdecode(QString st)
{
  st.replace("&", "&");
  st.replace("<", "<");
  st.replace(">", ">");
  return st;
}
<|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "TgaImporter.h"

#include "Utility/Endianness.h"
#include "Math/Vector2.h"
#include "Trade/ImageData.h"

using namespace std;
using namespace Corrade::Utility;

namespace Magnum { namespace Trade { namespace TgaImporter {

#ifndef DOXYGEN_GENERATING_OUTPUT
static_assert(sizeof(TgaImporter::Header) == 18, "TgaImporter: header size is not 18 bytes");
#endif

bool TgaImporter::TgaImporter::open(const string& filename, const string& name) {
    ifstream in(filename.c_str());
    if(!in.good()) {
        Error() << "TgaImporter: cannot open file" << filename;
        return false;
    }
    bool status = open(in, name);
    in.close();
    return status;
}

bool TgaImporter::open(istream& in, const string& name) {
    if(_image) close();
    if(!in.good()) {
        Error() << "TgaImporter: cannot read input stream";
        return false;
    }

    /* Check if the file is long enough */
    in.seekg(0, istream::end);
    streampos filesize = in.tellg();
    in.seekg(0, istream::beg);
    if(filesize < streampos(sizeof(Header))) {
        Error() << "TgaImporter: the file is too short:" << filesize << "bytes";
        return false;
    }

    Header header;
    in.read(reinterpret_cast<char*>(&header), sizeof(Header));

    /* Convert to machine endian */
    header.width = Endianness::littleEndian<unsigned short>(header.width);
    header.height = Endianness::littleEndian<unsigned short>(header.height);

    if(header.colorMapType != 0) {
        Error() << "TgaImporter: paletted files are not supported";
        return false;
    }

    if(header.imageType != 2) {
        Error() << "TgaImporter: non-RGB files are not supported";
        return false;
    }

    AbstractImage::Components components;
    switch(header.bpp) {
        case 24:
            components = AbstractImage::Components::BGR;
            break;
        case 32:
            components = AbstractImage::Components::BGRA;
            break;
        default:
            Error() << "TgaImporter: unsupported bits-per-pixel:" << (int) header.bpp;
            return false;
    }

    size_t size = header.width*header.height*header.bpp/8;
    GLubyte* buffer = new GLubyte[size];
    in.read(reinterpret_cast<char*>(buffer), size);

    Math::Vector2<GLsizei> dimensions(header.width, header.height);

    _image = new ImageData2D(name, dimensions, components, buffer);
    return true;
}

void TgaImporter::close() {
    delete _image;
    _image = nullptr;
}

ImageData2D* TgaImporter::image2D(unsigned int id) {
    return _image;
}

}}}
<commit_msg>TgaImporter: quick ugly fix - don't delete the image data on closing.<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "TgaImporter.h"

#include "Utility/Endianness.h"
#include "Math/Vector2.h"
#include "Trade/ImageData.h"

using namespace std;
using namespace Corrade::Utility;

namespace Magnum { namespace Trade { namespace TgaImporter {

#ifndef DOXYGEN_GENERATING_OUTPUT
static_assert(sizeof(TgaImporter::Header) == 18, "TgaImporter: header size is not 18 bytes");
#endif

bool TgaImporter::TgaImporter::open(const string& filename, const string& name) {
    ifstream in(filename.c_str());
    if(!in.good()) {
        Error() << "TgaImporter: cannot open file" << filename;
        return false;
    }
    bool status = open(in, name);
    in.close();
    return status;
}

bool TgaImporter::open(istream& in, const string& name) {
    if(_image) close();
    if(!in.good()) {
        Error() << "TgaImporter: cannot read input stream";
        return false;
    }

    /* Check if the file is long enough */
    in.seekg(0, istream::end);
    streampos filesize = in.tellg();
    in.seekg(0, istream::beg);
    if(filesize < streampos(sizeof(Header))) {
        Error() << "TgaImporter: the file is too short:" << filesize << "bytes";
        return false;
    }

    Header header;
    in.read(reinterpret_cast<char*>(&header), sizeof(Header));

    /* Convert to machine endian */
    header.width = Endianness::littleEndian<unsigned short>(header.width);
    header.height = Endianness::littleEndian<unsigned short>(header.height);

    if(header.colorMapType != 0) {
        Error() << "TgaImporter: paletted files are not supported";
        return false;
    }

    if(header.imageType != 2) {
        Error() << "TgaImporter: non-RGB files are not supported";
        return false;
    }

    AbstractImage::Components components;
    switch(header.bpp) {
        case 24:
            components = AbstractImage::Components::BGR;
            break;
        case 32:
            components = AbstractImage::Components::BGRA;
            break;
        default:
            Error() << "TgaImporter: unsupported bits-per-pixel:" << (int) header.bpp;
            return false;
    }

    size_t size = header.width*header.height*header.bpp/8;
    GLubyte* buffer = new GLubyte[size];
    in.read(reinterpret_cast<char*>(buffer), size);

    Math::Vector2<GLsizei> dimensions(header.width, header.height);

    _image = new ImageData2D(name, dimensions, components, buffer);
    return true;
}

void TgaImporter::close() {
    /** @todo fixme: delete it only if it wasn't retrieved by user */
    //delete _image;
    _image = nullptr;
}

ImageData2D* TgaImporter::image2D(unsigned int id) {
    return _image;
}

}}}
<|endoftext|>


<commit_before>#include "GaloisField16.h"
#include <stdexcept>

namespace SRFS {

	GaloisField16 GaloisField16::_instance = GaloisField16();

	GaloisField16::GaloisField16() {

		// The starting value for log table construnction.  We shift this left with each subsequent entry, using the primitive polynomial
		// to handle an overflow.
		uint16_t value = 0x01u;
		for (int exponent = 0; exponent < MASK; exponent++) {
			expTable[exponent] = value;
			logTable[value] = exponent;
			// Check for overflow on the next shift left
			if ((value & HIGH_BIT) != 0) value = ((value << 1) & MASK) ^ PRIMITIVE_POLYNOMIAL;
			else value = value << 1;
		}
		// Add in the last value.
		expTable[MASK] = expTable[0];
		// The log of zero is undefined, but I do not want unitialized data.
		logTable[0] = 0;

		// The T-Tables will be filled out when they're first called.
		for (int i = 0; i <= MAX_VALUE; i++) _lookupTables[i] = nullptr;
	}

	GaloisField16::~GaloisField16() {
		for (int i = 0; i <= MAX_VALUE; i++) {
			if (_lookupTables[i] != nullptr) delete _lookupTables[i];
		}
	}

	void GaloisField16::Add(uint16_t* a, uint16_t* b, uint16_t* result, int count) {
		for (int i = 0; i < count; i++) {
			*result = Add(*a, *b);
			a++;
			b++;
			result++;
		}
	}

	uint16_t GaloisField16::Multiply(uint16_t x, uint16_t y) {
		if ((x == 0) || (y == 0)) return 0;

		int sum = _instance.logTable[x] + _instance.logTable[y];
		sum = (sum >> BITS) + (sum & MASK);
		return _instance.expTable[sum];
	}

	void GaloisField16::Multiply(uint16_t x, uint16_t* y, uint16_t* result, int count) {
		if (x == 0) {
			// Set everything to zero
			while (count-- > 0) *(result++) = 0;
		}
		else {
			uint32_t logx = _instance.logTable[x];
			uint32_t sum = 0;
			while (count-- > 0) {
				if (*y == 0) {
					*result = 0;
				}
				else {
					sum = logx + _instance.logTable[*y];
					*result = _instance.expTable[((sum >> BITS) + (sum & MASK))];
				}
				result++;
				y++;
			}
		}
	}

	void GaloisField16::SSEAdd(uint16_t* a, uint16_t* b, uint16_t* result, int count) {
		if (count % 8 != 0) throw std::invalid_argument("count must be a multiple of 8");
		for (int i = 0; i < count; i += 8) {
			__m128i xmm1 = _mm_loadu_si128((__m128i*)a);
			__m128i xmm2 = _mm_loadu_si128((__m128i*)b);
			__m128i r = _mm_xor_si128(xmm1, xmm2);
			_mm_storeu_si128((__m128i*)result, r);

			a += 8;
			b += 8;
			result += 8;
		}
	}

	void GaloisField16::SSEMultiplyStandard(uint16_t y, uint16_t* a, uint16_t* result, int count) {
		if (count % 16 != 0) throw std::invalid_argument("count must be a multiple of 16");

		LookupTable* ttable = _instance._lookupTables[y];
		if (ttable == nullptr) {
			ttable = new LookupTable(y);
			_instance._lookupTables[y] = ttable;
		}

		__m128i mask = _mm_set1_epi16(0xff);
		__m128i mask1 = _mm_set1_epi8(0x0f);
		__m128i mask2 = _mm_set1_epi8((char)0xf0);

		for (int i = 0; i < count; i += 16) {
			__m128i ab = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i cd = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i ab_h = _mm_srli_epi16(ab, 8);
			__m128i ab_l = _mm_and_si128(ab, mask);
			__m128i cd_h = _mm_srli_epi16(cd, 8);
			__m128i cd_l = _mm_and_si128(cd, mask);

			__m128i low = _mm_packus_epi16(ab_l, cd_l);
			__m128i high = _mm_packus_epi16(ab_h, cd_h);

			// Low order
			// 0 b0 0 c0 0 d0 0 e0
			__m128i nybble = _mm_and_si128(low, mask1);
			__m128i resultHigh = _mm_shuffle_epi8(*ttable->T0High, nybble);
			__m128i resultLow = _mm_shuffle_epi8(*ttable->T0Low, nybble);

			// 0 b1 0 c1 0 d1 0 e1
			__m128i high_nybble = _mm_and_si128(low, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T1High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T1Low, nybble));

			// High order
			// 0 b2 0 c2 0 d2 0 e2
			nybble = _mm_and_si128(high, mask1);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T2High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T2Low, nybble));

			// 0 b3 0 c3 0 d3 0 e3
			high_nybble = _mm_and_si128(high, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T3High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T3Low, nybble));

			ab = _mm_unpacklo_epi8(resultLow, resultHigh);
			cd = _mm_unpackhi_epi8(resultLow, resultHigh);

			_mm_storeu_si128((__m128i*)result, ab);
			result += 8;
			_mm_storeu_si128((__m128i*)result, cd);
			result += 8;
		}
	}

	void GaloisField16::SSEMultiplyAlternate(uint16_t y, uint16_t* a, uint16_t* result, int count) {
		if (count % 16 != 0) throw std::invalid_argument("count must be a multiple of 16");

		LookupTable* ttable = _instance._lookupTables[y];
		if (ttable == nullptr) {
			ttable = new LookupTable(y);
			_instance._lookupTables[y] = ttable;
		}

		__m128i mask = _mm_set1_epi16(0xff);
		__m128i mask1 = _mm_set1_epi8(0x0f);
		__m128i mask2 = _mm_set1_epi8((char)0xf0);

		for (int i = 0; i < count; i += 16) {
			__m128i low = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i high = _mm_loadu_si128((__m128i*)a);
			a += 8;

			// Low order
			// 0 b0 0 c0 0 d0 0 e0
			__m128i nybble = _mm_and_si128(low, mask1);
			__m128i resultHigh = _mm_shuffle_epi8(*ttable->T0High, nybble);
			__m128i resultLow = _mm_shuffle_epi8(*ttable->T0Low, nybble);

			// 0 b1 0 c1 0 d1 0 e1
			__m128i high_nybble = _mm_and_si128(low, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T1High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T1Low, nybble));

			// High order
			// 0 b2 0 c2 0 d2 0 e2
			nybble = _mm_and_si128(high, mask1);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T2High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T2Low, nybble));

			// 0 b3 0 c3 0 d3 0 e3
			high_nybble = _mm_and_si128(high, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*ttable->T3High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*ttable->T3Low, nybble));

			_mm_storeu_si128((__m128i*)result, resultLow);
			result += 8;
			_mm_storeu_si128((__m128i*)result, resultHigh);
			result += 8;
		}
	}

	uint16_t GaloisField16::Power(uint16_t x, int a) {
		if (x == 0) {
			if (a == 0) throw std::invalid_argument("0 raised to the 0 power is undefined.");
			return 0;
		}
		if (a == 0) return 1;
		return _instance.expTable[(_instance.logTable[x] * a) % MAX_VALUE];
	}

	uint16_t GaloisField16::Inverse(uint16_t x) {
		if (x == 0) throw std::invalid_argument("Cannot take the inverse of zero");
		return _instance.expTable[MAX_VALUE - _instance.logTable[x]];
	}

	GaloisField16::LookupTable::LookupTable(uint16_t y) {

		T = (uint8_t*)_aligned_malloc(128, 16);

		uint16_t product;
		uint8_t* pLow = (uint8_t*)(&product);
		uint8_t* pHigh = pLow + 1;

		uint8_t* pT0l = T;
		uint8_t* pT0h = T + 16;
		uint8_t* pT1l = T + 32;
		uint8_t* pT1h = T + 48;
		uint8_t* pT2l = T + 64;
		uint8_t* pT2h = T + 80;
		uint8_t* pT3l = T + 96;
		uint8_t* pT3h = T + 112;

		T0Low = (__m128i*)pT0l;
		T0High = (__m128i*)pT0h;
		T1Low = (__m128i*)pT1l;
		T1High = (__m128i*)pT1h;
		T2Low = (__m128i*)pT2l;
		T2High = (__m128i*)pT2h;
		T3Low = (__m128i*)pT3l;
		T3High = (__m128i*)pT3h;

		for (uint16_t i = 0; i < 16; i++) {
			uint16_t v = i;
			product = GaloisField16::Multiply(y, v);
			*pT0l = *pLow;
			*pT0h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT1l = *pLow;
			*pT1h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT2l = *pLow;
			*pT2h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT3l = *pLow;
			*pT3h = *pHigh;

			pT0l++;
			pT0h++;
			pT1l++;
			pT1h++;
			pT2l++;
			pT2h++;
			pT3l++;
			pT3h++;
		}
	}

	GaloisField16::LookupTable::~LookupTable() {
		_aligned_free(T);
	}
}<commit_msg>Renamed ttable variable to table.  Added Polynomial class.<commit_after>#include "GaloisField16.h"
#include <stdexcept>

namespace SRFS {

	GaloisField16 GaloisField16::_instance = GaloisField16();

	GaloisField16::GaloisField16() {

		// The starting value for log table construnction.  We shift this left with each subsequent entry, using the primitive polynomial
		// to handle an overflow.
		uint16_t value = 0x01u;
		for (int exponent = 0; exponent < MASK; exponent++) {
			expTable[exponent] = value;
			logTable[value] = exponent;
			// Check for overflow on the next shift left
			if ((value & HIGH_BIT) != 0) value = ((value << 1) & MASK) ^ PRIMITIVE_POLYNOMIAL;
			else value = value << 1;
		}
		// Add in the last value.
		expTable[MASK] = expTable[0];
		// The log of zero is undefined, but I do not want unitialized data.
		logTable[0] = 0;

		// The T-Tables will be filled out when they're first called.
		for (int i = 0; i <= MAX_VALUE; i++) _lookupTables[i] = nullptr;
	}

	GaloisField16::~GaloisField16() {
		for (int i = 0; i <= MAX_VALUE; i++) {
			if (_lookupTables[i] != nullptr) delete _lookupTables[i];
		}
	}

	void GaloisField16::Add(uint16_t* a, uint16_t* b, uint16_t* result, int count) {
		for (int i = 0; i < count; i++) {
			*result = Add(*a, *b);
			a++;
			b++;
			result++;
		}
	}

	uint16_t GaloisField16::Multiply(uint16_t x, uint16_t y) {
		if ((x == 0) || (y == 0)) return 0;

		int sum = _instance.logTable[x] + _instance.logTable[y];
		sum = (sum >> BITS) + (sum & MASK);
		return _instance.expTable[sum];
	}

	void GaloisField16::Multiply(uint16_t x, uint16_t* y, uint16_t* result, int count) {
		if (x == 0) {
			// Set everything to zero
			while (count-- > 0) *(result++) = 0;
		}
		else {
			uint32_t logx = _instance.logTable[x];
			uint32_t sum = 0;
			while (count-- > 0) {
				if (*y == 0) {
					*result = 0;
				}
				else {
					sum = logx + _instance.logTable[*y];
					*result = _instance.expTable[((sum >> BITS) + (sum & MASK))];
				}
				result++;
				y++;
			}
		}
	}

	void GaloisField16::SSEAdd(uint16_t* a, uint16_t* b, uint16_t* result, int count) {
		if (count % 8 != 0) throw std::invalid_argument("count must be a multiple of 8");
		for (int i = 0; i < count; i += 8) {
			__m128i xmm1 = _mm_loadu_si128((__m128i*)a);
			__m128i xmm2 = _mm_loadu_si128((__m128i*)b);
			__m128i r = _mm_xor_si128(xmm1, xmm2);
			_mm_storeu_si128((__m128i*)result, r);

			a += 8;
			b += 8;
			result += 8;
		}
	}

	void GaloisField16::SSEMultiplyStandard(uint16_t y, uint16_t* a, uint16_t* result, int count) {
		if (count % 16 != 0) throw std::invalid_argument("count must be a multiple of 16");

		LookupTable* table = _instance._lookupTables[y];
		if (table == nullptr) {
			table = new LookupTable(y);
			_instance._lookupTables[y] = table;
		}

		__m128i mask = _mm_set1_epi16(0xff);
		__m128i mask1 = _mm_set1_epi8(0x0f);
		__m128i mask2 = _mm_set1_epi8((char)0xf0);

		for (int i = 0; i < count; i += 16) {
			__m128i ab = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i cd = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i ab_h = _mm_srli_epi16(ab, 8);
			__m128i ab_l = _mm_and_si128(ab, mask);
			__m128i cd_h = _mm_srli_epi16(cd, 8);
			__m128i cd_l = _mm_and_si128(cd, mask);

			__m128i low = _mm_packus_epi16(ab_l, cd_l);
			__m128i high = _mm_packus_epi16(ab_h, cd_h);

			// Low order
			// 0 b0 0 c0 0 d0 0 e0
			__m128i nybble = _mm_and_si128(low, mask1);
			__m128i resultHigh = _mm_shuffle_epi8(*table->T0High, nybble);
			__m128i resultLow = _mm_shuffle_epi8(*table->T0Low, nybble);

			// 0 b1 0 c1 0 d1 0 e1
			__m128i high_nybble = _mm_and_si128(low, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T1High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T1Low, nybble));

			// High order
			// 0 b2 0 c2 0 d2 0 e2
			nybble = _mm_and_si128(high, mask1);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T2High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T2Low, nybble));

			// 0 b3 0 c3 0 d3 0 e3
			high_nybble = _mm_and_si128(high, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T3High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T3Low, nybble));

			ab = _mm_unpacklo_epi8(resultLow, resultHigh);
			cd = _mm_unpackhi_epi8(resultLow, resultHigh);

			_mm_storeu_si128((__m128i*)result, ab);
			result += 8;
			_mm_storeu_si128((__m128i*)result, cd);
			result += 8;
		}
	}

	void GaloisField16::SSEMultiplyAlternate(uint16_t y, uint16_t* a, uint16_t* result, int count) {
		if (count % 16 != 0) throw std::invalid_argument("count must be a multiple of 16");

		LookupTable* table = _instance._lookupTables[y];
		if (table == nullptr) {
			table = new LookupTable(y);
			_instance._lookupTables[y] = table;
		}

		__m128i mask = _mm_set1_epi16(0xff);
		__m128i mask1 = _mm_set1_epi8(0x0f);
		__m128i mask2 = _mm_set1_epi8((char)0xf0);

		for (int i = 0; i < count; i += 16) {
			__m128i low = _mm_loadu_si128((__m128i*)a);
			a += 8;
			__m128i high = _mm_loadu_si128((__m128i*)a);
			a += 8;

			// Low order
			// 0 b0 0 c0 0 d0 0 e0
			__m128i nybble = _mm_and_si128(low, mask1);
			__m128i resultHigh = _mm_shuffle_epi8(*table->T0High, nybble);
			__m128i resultLow = _mm_shuffle_epi8(*table->T0Low, nybble);

			// 0 b1 0 c1 0 d1 0 e1
			__m128i high_nybble = _mm_and_si128(low, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T1High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T1Low, nybble));

			// High order
			// 0 b2 0 c2 0 d2 0 e2
			nybble = _mm_and_si128(high, mask1);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T2High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T2Low, nybble));

			// 0 b3 0 c3 0 d3 0 e3
			high_nybble = _mm_and_si128(high, mask2);
			nybble = _mm_srli_epi64(high_nybble, 4);
			resultHigh = _mm_xor_si128(resultHigh, _mm_shuffle_epi8(*table->T3High, nybble));
			resultLow = _mm_xor_si128(resultLow, _mm_shuffle_epi8(*table->T3Low, nybble));

			_mm_storeu_si128((__m128i*)result, resultLow);
			result += 8;
			_mm_storeu_si128((__m128i*)result, resultHigh);
			result += 8;
		}
	}

	uint16_t GaloisField16::Power(uint16_t x, int a) {
		if (x == 0) {
			if (a == 0) throw std::invalid_argument("0 raised to the 0 power is undefined.");
			return 0;
		}
		if (a == 0) return 1;
		return _instance.expTable[(_instance.logTable[x] * a) % MAX_VALUE];
	}

	uint16_t GaloisField16::Inverse(uint16_t x) {
		if (x == 0) throw std::invalid_argument("Cannot take the inverse of zero");
		return _instance.expTable[MAX_VALUE - _instance.logTable[x]];
	}

	GaloisField16::LookupTable::LookupTable(uint16_t y) {

		T = (uint8_t*)_aligned_malloc(128, 16);

		uint16_t product;
		uint8_t* pLow = (uint8_t*)(&product);
		uint8_t* pHigh = pLow + 1;

		uint8_t* pT0l = T;
		uint8_t* pT0h = T + 16;
		uint8_t* pT1l = T + 32;
		uint8_t* pT1h = T + 48;
		uint8_t* pT2l = T + 64;
		uint8_t* pT2h = T + 80;
		uint8_t* pT3l = T + 96;
		uint8_t* pT3h = T + 112;

		T0Low = (__m128i*)pT0l;
		T0High = (__m128i*)pT0h;
		T1Low = (__m128i*)pT1l;
		T1High = (__m128i*)pT1h;
		T2Low = (__m128i*)pT2l;
		T2High = (__m128i*)pT2h;
		T3Low = (__m128i*)pT3l;
		T3High = (__m128i*)pT3h;

		for (uint16_t i = 0; i < 16; i++) {
			uint16_t v = i;
			product = GaloisField16::Multiply(y, v);
			*pT0l = *pLow;
			*pT0h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT1l = *pLow;
			*pT1h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT2l = *pLow;
			*pT2h = *pHigh;

			v <<= 4;
			product = GaloisField16::Multiply(y, v);
			*pT3l = *pLow;
			*pT3h = *pHigh;

			pT0l++;
			pT0h++;
			pT1l++;
			pT1h++;
			pT2l++;
			pT2h++;
			pT3l++;
			pT3h++;
		}
	}

	GaloisField16::LookupTable::~LookupTable() {
		_aligned_free(T);
	}
}<|endoftext|>


<commit_before>#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkUnitMapper.h"

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);

static const struct {
    GradMaker   fMaker;
    const char* fName;
    int         fRepeat;
} gGrads[] = {
    { MakeLinear,   "linear",  15 },
    { MakeRadial,   "radial1", 10 },
    { MakeSweep,    "sweep",    1 },
    { Make2Radial,  "radial2",  5 },
};

enum GradType { // these must match the order in gGrads
    kLinear_GradType,
    kRadial_GradType,
    kSweep_GradType,
    kRadial2_GradType
};

static const char* tilemodename(SkShader::TileMode tm) {
    switch (tm) {
        case SkShader::kClamp_TileMode:
            return "clamp";
        case SkShader::kRepeat_TileMode:
            return "repeat";
        case SkShader::kMirror_TileMode:
            return "mirror";
        default:
            SkASSERT(!"unknown tilemode");
            return "error";
    }
}

///////////////////////////////////////////////////////////////////////////////

class GradientBench : public SkBenchmark {
    SkString fName;
    SkShader* fShader;
    int      fCount;
    enum {
        W   = 400,
        H   = 400,
        N   = 1
    };
public:
    GradientBench(void* param, GradType gt,
                  SkShader::TileMode tm = SkShader::kClamp_TileMode) : INHERITED(param) {
        fName.printf("gradient_%s_%s", gGrads[gt].fName, tilemodename(tm));

        const SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(W), SkIntToScalar(H) }
        };

        fCount = N * gGrads[gt].fRepeat;
        fShader = gGrads[gt].fMaker(pts, gGradData[0], tm, NULL);
    }

    virtual ~GradientBench() {
        fShader->unref();
    }

protected:
    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkPaint paint;
        this->setupPaint(&paint);

        paint.setShader(fShader);

        SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
        for (int i = 0; i < fCount; i++) {
            canvas->drawRect(r, paint);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

class Gradient2Bench : public SkBenchmark {
public:
    Gradient2Bench(void* param) : INHERITED(param) {}

protected:
    virtual const char* onGetName() {
        return "gradient_create";
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkPaint paint;
        this->setupPaint(&paint);

        const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
        const SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };

        for (int i = 0; i < 1000; i++) {
            const int a = i % 256;
            SkColor colors[] = { SK_ColorBLACK, SkColorSetARGB(a, a, a, a), SK_ColorWHITE };
            SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
                                                         SK_ARRAY_COUNT(colors),
                                                         SkShader::kClamp_TileMode);
            paint.setShader(s)->unref();
            canvas->drawRect(r, paint);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); }
static SkBenchmark* Fact01(void* p) { return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType); }
static SkBenchmark* Fact11(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); }
static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); }
static SkBenchmark* Fact31(void* p) { return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); }

static SkBenchmark* Fact4(void* p) { return new Gradient2Bench(p); }

static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg11(Fact11);
static BenchRegistry gReg2(Fact2);
static BenchRegistry gReg3(Fact3);
static BenchRegistry gReg31(Fact31);

static BenchRegistry gReg4(Fact4);

<commit_msg>fix warning about SkPoint initialization<commit_after>#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkUnitMapper.h"

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);

static const struct {
    GradMaker   fMaker;
    const char* fName;
    int         fRepeat;
} gGrads[] = {
    { MakeLinear,   "linear",  15 },
    { MakeRadial,   "radial1", 10 },
    { MakeSweep,    "sweep",    1 },
    { Make2Radial,  "radial2",  5 },
};

enum GradType { // these must match the order in gGrads
    kLinear_GradType,
    kRadial_GradType,
    kSweep_GradType,
    kRadial2_GradType
};

static const char* tilemodename(SkShader::TileMode tm) {
    switch (tm) {
        case SkShader::kClamp_TileMode:
            return "clamp";
        case SkShader::kRepeat_TileMode:
            return "repeat";
        case SkShader::kMirror_TileMode:
            return "mirror";
        default:
            SkASSERT(!"unknown tilemode");
            return "error";
    }
}

///////////////////////////////////////////////////////////////////////////////

class GradientBench : public SkBenchmark {
    SkString fName;
    SkShader* fShader;
    int      fCount;
    enum {
        W   = 400,
        H   = 400,
        N   = 1
    };
public:
    GradientBench(void* param, GradType gt,
                  SkShader::TileMode tm = SkShader::kClamp_TileMode) : INHERITED(param) {
        fName.printf("gradient_%s_%s", gGrads[gt].fName, tilemodename(tm));

        const SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(W), SkIntToScalar(H) }
        };

        fCount = N * gGrads[gt].fRepeat;
        fShader = gGrads[gt].fMaker(pts, gGradData[0], tm, NULL);
    }

    virtual ~GradientBench() {
        fShader->unref();
    }

protected:
    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkPaint paint;
        this->setupPaint(&paint);

        paint.setShader(fShader);

        SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
        for (int i = 0; i < fCount; i++) {
            canvas->drawRect(r, paint);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

class Gradient2Bench : public SkBenchmark {
public:
    Gradient2Bench(void* param) : INHERITED(param) {}

protected:
    virtual const char* onGetName() {
        return "gradient_create";
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkPaint paint;
        this->setupPaint(&paint);

        const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
        const SkPoint pts[] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) },
        };

        for (int i = 0; i < 1000; i++) {
            const int a = i % 256;
            SkColor colors[] = { SK_ColorBLACK, SkColorSetARGB(a, a, a, a), SK_ColorWHITE };
            SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
                                                         SK_ARRAY_COUNT(colors),
                                                         SkShader::kClamp_TileMode);
            paint.setShader(s)->unref();
            canvas->drawRect(r, paint);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); }
static SkBenchmark* Fact01(void* p) { return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType); }
static SkBenchmark* Fact11(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); }
static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); }
static SkBenchmark* Fact31(void* p) { return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); }

static SkBenchmark* Fact4(void* p) { return new Gradient2Bench(p); }

static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg11(Fact11);
static BenchRegistry gReg2(Fact2);
static BenchRegistry gReg3(Fact3);
static BenchRegistry gReg31(Fact31);

static BenchRegistry gReg4(Fact4);

<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/simulation.h"

// GRINS
#include "grins/simulation_builder.h"
#include "grins/multiphysics_sys.h"
#include "grins/solver_context.h"

// libMesh
#include "libmesh/dof_map.h"

namespace GRINS
{

  Simulation::Simulation( const GetPot& input,
                          SimulationBuilder& sim_builder )
    :  _mesh( sim_builder.build_mesh(input) ),
       _equation_system( new libMesh::EquationSystems( *_mesh ) ),
       _solver( sim_builder.build_solver(input) ),
       _system_name( input("screen-options/system_name", "GRINS" ) ),
       _multiphysics_system( &(_equation_system->add_system<MultiphysicsSystem>( _system_name )) ),
       _vis( sim_builder.build_vis(input) ),
       _postprocessing( sim_builder.build_postprocessing(input) ),
    _print_mesh_info( input("screen-options/print_mesh_info", false ) ),
    _print_log_info( input("screen-options/print_log_info", false ) ),
    _print_equation_system_info( input("screen-options/print_equation_system_info", false ) ),
    _print_qoi( input("screen-options/print_qoi", false ) ),
    _output_vis( input("vis-options/output_vis", false ) ),
    _output_residual( input( "vis-options/output_residual", false ) ),
    _error_estimator() // effectively NULL
  {
    // Only print libMesh logging info if the user requests it
    libMesh::perflog.disable_logging();
    if( this->_print_log_info ) libMesh::perflog.enable_logging();

    PhysicsList physics_list = sim_builder.build_physics(input);

    _multiphysics_system->attach_physics_list( physics_list );

    _multiphysics_system->read_input_options( input );

    // This *must* be done before equation_system->init
    this->attach_dirichlet_bc_funcs( sim_builder.build_dirichlet_bcs(), _multiphysics_system );

    /* Postprocessing needs to be initialized before the solver since that's
       where equation_system gets init'ed */
    _postprocessing->initialize( *_multiphysics_system, *_equation_system );

    _solver->initialize( input, _equation_system, _multiphysics_system );

    // Useful for debugging
    if( input("screen-options/print_dof_constraints", false ) )
      {
        _multiphysics_system->get_dof_map().print_dof_constraints();
      }

    // This *must* be done after equation_system->init in order to get variable indices
    this->attach_neumann_bc_funcs( sim_builder.build_neumann_bcs( *_equation_system ), _multiphysics_system );

    // If the user actually asks for a QoI, then we add it.
    std::tr1::shared_ptr<CompositeQoI> qois = sim_builder.build_qoi( input );
    if( qois.n_qois() > 0 )
      {
        // This *must* be done after equation_system->init in order to get variable indices
        qois->init(input, *_multiphysics_system );

        /* Note that we are effectively transfering ownership of the qoi pointer because
           it will be cloned in _multiphysics_system and all the calculations are done there. */

        _multiphysics_system->attach_qoi( qois.get() );
      }

    // Must be called after setting QoI on the MultiphysicsSystem
    _error_estimator = sim_builder.build_error_estimator( input, libMesh::QoISet(*_multiphysics_system) );

    this->check_for_restart( input );

    return;
  }

  Simulation::~Simulation()
  {
    return;
  }

  void Simulation::run()
  {
    this->print_sim_info();

    SolverContext context;
    context.system = _multiphysics_system;
    context.equation_system = _equation_system;
    context.vis = _vis;
    context.output_vis = _output_vis;
    context.output_residual = _output_residual;
    context.postprocessing = _postprocessing;
    context.error_estimator = _error_estimator;

    _solver->solve( context );

    if( this->_print_qoi )
      {
        _multiphysics_system->assemble_qoi( libMesh::QoISet( *_multiphysics_system ) );
        const CompositeQoI* my_qoi = libmesh_cast_ptr<const CompositeQoI*>(this->_multiphysics_system->get_qoi());
        my_qoi->output_qoi( std::cout );
      }

    return;
  }

  void Simulation::print_sim_info()
  {
    // Print mesh info if the user wants it
    if( this->_print_mesh_info ) this->_mesh->print_info();

    // Print info if requested
    if( this->_print_equation_system_info ) this->_equation_system->print_info();

    return;
  }

  std::tr1::shared_ptr<libMesh::EquationSystems> Simulation::get_equation_system()
  {
    return _equation_system;
  }

  libMesh::Number Simulation::get_qoi_value( unsigned int qoi_index ) const
  {
    const CompositeQoI* qoi = libmesh_cast_ptr<const CompositeQoI*>(this->_multiphysics_system->get_qoi());
    return qoi->get_qoi_value(qoi_index);
  }

  void Simulation::check_for_restart( const GetPot& input )
  {
    const std::string restart_file = input( "restart-options/restart_file", "none" );

    // Most of this was pulled from FIN-S
    if (restart_file != "none")
      {
        std::cout << " ====== Restarting from " << restart_file << std::endl;

        // Must have correct file type to restart
        if (restart_file.rfind(".xdr") < restart_file.size())
          _equation_system->read(restart_file,libMeshEnums::DECODE,
                                 //EquationSystems::READ_HEADER |  // Allow for thermochemistry upgrades
                                 EquationSystems::READ_DATA |
                                 EquationSystems::READ_ADDITIONAL_DATA);

        else if  (restart_file.rfind(".xda") < restart_file.size())
          _equation_system->read(restart_file,libMeshEnums::READ,
                                 //EquationSystems::READ_HEADER |  // Allow for thermochemistry upgrades
                                 EquationSystems::READ_DATA |
                                 EquationSystems::READ_ADDITIONAL_DATA);

        else
          {
            std::cerr << "Error: Restart filename must have .xdr or .xda extension!" << std::endl;
            libmesh_error();
          }

        const std::string system_name = input("screen-options/system_name", "GRINS" );

        MultiphysicsSystem& system =
          _equation_system->get_system<MultiphysicsSystem>(system_name);

        // Update the old data
        system.update();
      }

    return;
  }

  void Simulation::attach_neumann_bc_funcs( std::map< std::string, NBCContainer > neumann_bcs,
                                            MultiphysicsSystem* system )
  {
    //_neumann_bc_funcs = neumann_bcs;

    if( neumann_bcs.size() > 0 )
      {
        for( std::map< std::string, NBCContainer >::iterator bc = neumann_bcs.begin();
             bc != neumann_bcs.end();
             bc++ )
          {
            std::tr1::shared_ptr<Physics> physics = system->get_physics( bc->first );
            physics->attach_neumann_bound_func( bc->second );
          }
      }

    return;
  }

  void Simulation::attach_dirichlet_bc_funcs( std::multimap< PhysicsName, DBCContainer > dbc_map,
                                              MultiphysicsSystem* system )
  {
    for( std::multimap< PhysicsName, DBCContainer >::const_iterator it = dbc_map.begin();
         it != dbc_map.end();
         it++ )
      {
        std::tr1::shared_ptr<Physics> physics = system->get_physics( it->first );

        physics->attach_dirichlet_bound_func( it->second );
      }
    return;
  }

#ifdef GRINS_USE_GRVY_TIMERS
  void Simulation::attach_grvy_timer( GRVY::GRVY_Timer_Class* grvy_timer )
  {
    this->_multiphysics_system->attach_grvy_timer( grvy_timer );
    return;
  }
#endif

} // namespace GRINS
<commit_msg>It's a pointer, not a reference<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/simulation.h"

// GRINS
#include "grins/simulation_builder.h"
#include "grins/multiphysics_sys.h"
#include "grins/solver_context.h"

// libMesh
#include "libmesh/dof_map.h"

namespace GRINS
{

  Simulation::Simulation( const GetPot& input,
                          SimulationBuilder& sim_builder )
    :  _mesh( sim_builder.build_mesh(input) ),
       _equation_system( new libMesh::EquationSystems( *_mesh ) ),
       _solver( sim_builder.build_solver(input) ),
       _system_name( input("screen-options/system_name", "GRINS" ) ),
       _multiphysics_system( &(_equation_system->add_system<MultiphysicsSystem>( _system_name )) ),
       _vis( sim_builder.build_vis(input) ),
       _postprocessing( sim_builder.build_postprocessing(input) ),
    _print_mesh_info( input("screen-options/print_mesh_info", false ) ),
    _print_log_info( input("screen-options/print_log_info", false ) ),
    _print_equation_system_info( input("screen-options/print_equation_system_info", false ) ),
    _print_qoi( input("screen-options/print_qoi", false ) ),
    _output_vis( input("vis-options/output_vis", false ) ),
    _output_residual( input( "vis-options/output_residual", false ) ),
    _error_estimator() // effectively NULL
  {
    // Only print libMesh logging info if the user requests it
    libMesh::perflog.disable_logging();
    if( this->_print_log_info ) libMesh::perflog.enable_logging();

    PhysicsList physics_list = sim_builder.build_physics(input);

    _multiphysics_system->attach_physics_list( physics_list );

    _multiphysics_system->read_input_options( input );

    // This *must* be done before equation_system->init
    this->attach_dirichlet_bc_funcs( sim_builder.build_dirichlet_bcs(), _multiphysics_system );

    /* Postprocessing needs to be initialized before the solver since that's
       where equation_system gets init'ed */
    _postprocessing->initialize( *_multiphysics_system, *_equation_system );

    _solver->initialize( input, _equation_system, _multiphysics_system );

    // Useful for debugging
    if( input("screen-options/print_dof_constraints", false ) )
      {
        _multiphysics_system->get_dof_map().print_dof_constraints();
      }

    // This *must* be done after equation_system->init in order to get variable indices
    this->attach_neumann_bc_funcs( sim_builder.build_neumann_bcs( *_equation_system ), _multiphysics_system );

    // If the user actually asks for a QoI, then we add it.
    std::tr1::shared_ptr<CompositeQoI> qois = sim_builder.build_qoi( input );
    if( qois->n_qois() > 0 )
      {
        // This *must* be done after equation_system->init in order to get variable indices
        qois->init(input, *_multiphysics_system );

        /* Note that we are effectively transfering ownership of the qoi pointer because
           it will be cloned in _multiphysics_system and all the calculations are done there. */

        _multiphysics_system->attach_qoi( qois.get() );
      }

    // Must be called after setting QoI on the MultiphysicsSystem
    _error_estimator = sim_builder.build_error_estimator( input, libMesh::QoISet(*_multiphysics_system) );

    this->check_for_restart( input );

    return;
  }

  Simulation::~Simulation()
  {
    return;
  }

  void Simulation::run()
  {
    this->print_sim_info();

    SolverContext context;
    context.system = _multiphysics_system;
    context.equation_system = _equation_system;
    context.vis = _vis;
    context.output_vis = _output_vis;
    context.output_residual = _output_residual;
    context.postprocessing = _postprocessing;
    context.error_estimator = _error_estimator;

    _solver->solve( context );

    if( this->_print_qoi )
      {
        _multiphysics_system->assemble_qoi( libMesh::QoISet( *_multiphysics_system ) );
        const CompositeQoI* my_qoi = libmesh_cast_ptr<const CompositeQoI*>(this->_multiphysics_system->get_qoi());
        my_qoi->output_qoi( std::cout );
      }

    return;
  }

  void Simulation::print_sim_info()
  {
    // Print mesh info if the user wants it
    if( this->_print_mesh_info ) this->_mesh->print_info();

    // Print info if requested
    if( this->_print_equation_system_info ) this->_equation_system->print_info();

    return;
  }

  std::tr1::shared_ptr<libMesh::EquationSystems> Simulation::get_equation_system()
  {
    return _equation_system;
  }

  libMesh::Number Simulation::get_qoi_value( unsigned int qoi_index ) const
  {
    const CompositeQoI* qoi = libmesh_cast_ptr<const CompositeQoI*>(this->_multiphysics_system->get_qoi());
    return qoi->get_qoi_value(qoi_index);
  }

  void Simulation::check_for_restart( const GetPot& input )
  {
    const std::string restart_file = input( "restart-options/restart_file", "none" );

    // Most of this was pulled from FIN-S
    if (restart_file != "none")
      {
        std::cout << " ====== Restarting from " << restart_file << std::endl;

        // Must have correct file type to restart
        if (restart_file.rfind(".xdr") < restart_file.size())
          _equation_system->read(restart_file,libMeshEnums::DECODE,
                                 //EquationSystems::READ_HEADER |  // Allow for thermochemistry upgrades
                                 EquationSystems::READ_DATA |
                                 EquationSystems::READ_ADDITIONAL_DATA);

        else if  (restart_file.rfind(".xda") < restart_file.size())
          _equation_system->read(restart_file,libMeshEnums::READ,
                                 //EquationSystems::READ_HEADER |  // Allow for thermochemistry upgrades
                                 EquationSystems::READ_DATA |
                                 EquationSystems::READ_ADDITIONAL_DATA);

        else
          {
            std::cerr << "Error: Restart filename must have .xdr or .xda extension!" << std::endl;
            libmesh_error();
          }

        const std::string system_name = input("screen-options/system_name", "GRINS" );

        MultiphysicsSystem& system =
          _equation_system->get_system<MultiphysicsSystem>(system_name);

        // Update the old data
        system.update();
      }

    return;
  }

  void Simulation::attach_neumann_bc_funcs( std::map< std::string, NBCContainer > neumann_bcs,
                                            MultiphysicsSystem* system )
  {
    //_neumann_bc_funcs = neumann_bcs;

    if( neumann_bcs.size() > 0 )
      {
        for( std::map< std::string, NBCContainer >::iterator bc = neumann_bcs.begin();
             bc != neumann_bcs.end();
             bc++ )
          {
            std::tr1::shared_ptr<Physics> physics = system->get_physics( bc->first );
            physics->attach_neumann_bound_func( bc->second );
          }
      }

    return;
  }

  void Simulation::attach_dirichlet_bc_funcs( std::multimap< PhysicsName, DBCContainer > dbc_map,
                                              MultiphysicsSystem* system )
  {
    for( std::multimap< PhysicsName, DBCContainer >::const_iterator it = dbc_map.begin();
         it != dbc_map.end();
         it++ )
      {
        std::tr1::shared_ptr<Physics> physics = system->get_physics( it->first );

        physics->attach_dirichlet_bound_func( it->second );
      }
    return;
  }

#ifdef GRINS_USE_GRVY_TIMERS
  void Simulation::attach_grvy_timer( GRVY::GRVY_Timer_Class* grvy_timer )
  {
    this->_multiphysics_system->attach_grvy_timer( grvy_timer );
    return;
  }
#endif

} // namespace GRINS
<|endoftext|>