<commit_before>#include "qhexrenderer.h"
#include <QApplication>
#include <QTextCursor>
#include <QWidget>
#include <cctype>
#include <cmath>

#define HEX_UNPRINTABLE_CHAR '.'

QHexRenderer::QHexRenderer(QHexDocument* document, const QFontMetrics &fontmetrics, QObject *parent) : QObject(parent), m_document(document), m_fontmetrics(fontmetrics)
{
    m_selectedarea = QHexRenderer::HexArea;
    m_cursorenabled = false;
}

void QHexRenderer::renderFrame(QPainter *painter)
{
    QWidget* widget = dynamic_cast<QWidget*>(painter->device());

    if(!widget)
        return;

    QRect rect = widget->rect();
    int hexx = this->getHexColumnX();
    int asciix = this->getAsciiColumnX();
    int endx = this->getEndColumnX();

    painter->drawLine(rect.x() + hexx,
                      rect.top(),
                      rect.x() + hexx,
                      rect.bottom());

    painter->drawLine(rect.x() + asciix,
                      rect.top(),
                      rect.x() + asciix,
                      rect.bottom());

    painter->drawLine(rect.x() + endx,
                      rect.top(),
                      rect.x() + endx,
                      rect.bottom());
}

void QHexRenderer::render(QPainter *painter, int start, int count, int firstline)
{
    int end = start + count;
    QPalette palette = qApp->palette();

    for(int line = start; line < std::min(end, this->documentLines()); line++)
    {
        QRect linerect = this->getLineRect(line, firstline);

        if(line % 2)
            painter->fillRect(linerect, palette.brush(QPalette::Window));
        else
            painter->fillRect(linerect, palette.brush(QPalette::Base));

        this->drawAddress(painter, palette, linerect, line);
        this->drawHex(painter, palette, linerect, line);
        this->drawAscii(painter, palette, linerect, line);
    }
}

void QHexRenderer::enableCursor(bool b) { m_cursorenabled = b; }

void QHexRenderer::selectArea(const QPoint &pt)
{
    int area = this->hitTestArea(pt);

    if(area == QHexRenderer::AddressArea)
        return;

    m_selectedarea = area;
}

bool QHexRenderer::hitTest(const QPoint &pt, QHexPosition *position, int firstline) const
{
    int area = this->hitTestArea(pt);

    if(area == QHexRenderer::AddressArea)
        return false;

    position->line = std::min(firstline + (pt.y() / this->lineHeight()), this->documentLastLine());

    if(area == QHexRenderer::HexArea)
    {
        int relx = pt.x() - this->getHexColumnX();
        position->column = relx / (this->getCellWidth() * 3);
        position->nibbleindex = this->getNibbleIndex(position->line, relx);
    }
    else
    {
        int relx = pt.x() - this->getAsciiColumnX() - this->getCellWidth();
        position->column = relx / this->getCellWidth();
        position->nibbleindex = 1;
    }

    if(position->line == this->documentLastLine()) // Check last line's columns
    {
        QByteArray ba = this->getLine(position->line);
        position->column = std::min(position->column, ba.length());
    }
    else
        position->column = std::min(position->column, HEX_LINE_LAST_COLUMN);

    return true;
}

int QHexRenderer::hitTestArea(const QPoint &pt) const
{
    if((pt.x() >= 0) && (pt.x() <= this->getHexColumnX()))
        return QHexRenderer::AddressArea;

    if((pt.x() > this->getHexColumnX()) && (pt.x() < this->getAsciiColumnX()))
        return QHexRenderer::HexArea;

    if((pt.x() > this->getAsciiColumnX()) && (pt.x() < this->getEndColumnX()))
        return QHexRenderer::AsciiArea;

    return QHexRenderer::ExtraArea;
}

int QHexRenderer::selectedArea() const { return m_selectedarea; }
int QHexRenderer::documentLastLine() const { return this->documentLines() - 1; }
int QHexRenderer::documentLastColumn() const { return this->getLine(this->documentLastLine()).length(); }
int QHexRenderer::documentLines() const { return std::ceil(this->rendererLength() / static_cast<float>(HEX_LINE_LENGTH));  }
int QHexRenderer::documentWidth() const { return this->getAsciiColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH + 1)); }
int QHexRenderer::lineHeight() const { return m_fontmetrics.height(); }
QRect QHexRenderer::getLineRect(int line, int firstline) const { return QRect(0, (line - firstline) * m_fontmetrics.height(), this->getEndColumnX(), m_fontmetrics.height()); }

QString QHexRenderer::hexString(int line, QByteArray* rawline) const
{
    QByteArray lrawline = this->getLine(line);

    if(rawline)
        *rawline = lrawline;

    return lrawline.toHex(' ').toUpper() + " ";
}

QString QHexRenderer::asciiString(int line, QByteArray* rawline) const
{
    QByteArray lrawline = this->getLine(line);

    if(rawline)
        *rawline = lrawline;

    QByteArray ascii = lrawline;
    this->unprintableChars(ascii);
    return ascii;
}

QByteArray QHexRenderer::getLine(int line) const { return m_document->read(line * HEX_LINE_LENGTH, HEX_LINE_LENGTH); }
void QHexRenderer::blinkCursor() { m_cursorenabled = !m_cursorenabled; }
int QHexRenderer::rendererLength() const { return m_document->length() + 1; }

int QHexRenderer::getAddressWidth() const
{
    if(this->rendererLength() <= 0xFFFF)
        return 8;

    if(this->rendererLength() <= 0xFFFFFFFF)
        return 16;

    return QString::number(this->rendererLength(), 16).length();
}

int QHexRenderer::getHexColumnX() const { return this->getCellWidth() * (this->getAddressWidth() + 1); }
int QHexRenderer::getAsciiColumnX() const { return this->getHexColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH * 3)); }
int QHexRenderer::getEndColumnX() const { return this->getAsciiColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH + 1)); }

int QHexRenderer::getCellWidth() const
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    return m_fontmetrics.horizontalAdvance(" ");
#else
    return m_fontmetrics.width(" ");
#endif
}

int QHexRenderer::getNibbleIndex(int line, int relx) const
{
    relx -= this->getCellWidth(); // Remove padding
    QString hexstring = this->hexString(line);

    for(int i = 0; i < hexstring.size(); i++)
    {
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
        int x = m_fontmetrics.horizontalAdvance(hexstring, i + 1);
#else
        int x = m_fontmetrics.width(hexstring, i + 1);
#endif
        if(x < relx)
            continue;

        if((i == (hexstring.size() - 1)) || (hexstring[i + 1] == ' '))
            return 0;

        break;
    }

    return 1;
}

void QHexRenderer::unprintableChars(QByteArray &ascii) const
{
    for(char& ch : ascii)
    {
        if(std::isprint(ch))
            continue;

        ch = HEX_UNPRINTABLE_CHAR;
    }
}

void QHexRenderer::applyDocumentStyles(QPainter *painter, QTextDocument* textdocument) const
{
    textdocument->setDocumentMargin(0);
    textdocument->setUndoRedoEnabled(false);
    textdocument->setDefaultFont(painter->font());
}

void QHexRenderer::applyBasicStyle(QTextCursor &textcursor, const QByteArray &rawline, int factor) const
{
    QPalette palette = qApp->palette();
    QTextCharFormat charformat;
    charformat.setForeground(palette.color(QPalette::WindowText).lighter(350));

    for(int i = 0; i < rawline.length(); i++)
    {
        if((rawline[i] != 0x00) && (rawline[i] != 0xFF))
            continue;

        textcursor.setPosition(i * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, factor);
        textcursor.setCharFormat(charformat);
    }
}

void QHexRenderer::applyMetadata(QTextCursor &textcursor, int line, int factor) const
{
    QHexMetadata* metadata = m_document->metadata();

    if(!metadata->hasMetadata(line))
        return;

    const QHexLineMetadata& linemetadata = metadata->get(line);

    for(const QHexMetadataItem& mi : linemetadata)
    {
        QTextCharFormat charformat;

        if(mi.background.isValid())
            charformat.setBackground(mi.background);

        if(mi.foreground.isValid())
            charformat.setForeground(mi.foreground);

        if(!mi.comment.isEmpty())
            charformat.setUnderlineStyle(QTextCharFormat::SingleUnderline);

        textcursor.setPosition(mi.start * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, (mi.length * factor) - (factor > 1 ? 1 : 0));
        textcursor.setCharFormat(charformat);
    }
}

void QHexRenderer::applySelection(QTextCursor &textcursor, int line, int factor) const
{
    QHexCursor* cursor = m_document->cursor();

    if(!cursor->isLineSelected(line))
        return;

    const QHexPosition& startsel = cursor->selectionStart();
    const QHexPosition& endsel = cursor->selectionEnd();

    if(startsel.line == endsel.line)
    {
        textcursor.setPosition(startsel.column * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ((endsel.column - startsel.column + 1) * factor) - 1);
    }
    else
    {
        if(line == startsel.line)
            textcursor.setPosition(startsel.column * factor);
        else
            textcursor.setPosition(0);

        if(line == endsel.line)
            textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ((endsel.column + 1) * factor) - 1);
        else
            textcursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
    }

    QPalette palette = qApp->palette();

    QTextCharFormat charformat;
    charformat.setBackground(palette.color(QPalette::Highlight));
    charformat.setForeground(palette.color(QPalette::HighlightedText));
    textcursor.setCharFormat(charformat);
}

void QHexRenderer::applyCursorAscii(QTextCursor &textcursor, int line) const
{
    QHexCursor* cursor = m_document->cursor();

    if((line != cursor->currentLine()) || !m_cursorenabled)
        return;

    textcursor.clearSelection();
    textcursor.setPosition(m_document->cursor()->currentColumn());
    textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    QPalette palette = qApp->palette();

    QTextCharFormat charformat;

    if((cursor->insertionMode() == QHexCursor::OverwriteMode) || (m_selectedarea != QHexRenderer::AsciiArea))
    {
        charformat.setForeground(palette.color(QPalette::Window));

        if(m_selectedarea == QHexRenderer::AsciiArea)
            charformat.setBackground(palette.color(QPalette::WindowText));
        else
            charformat.setBackground(palette.color(QPalette::WindowText).lighter(250));
    }
    else
    {
        charformat.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline);
    }

    textcursor.setCharFormat(charformat);
}

void QHexRenderer::applyCursorHex(QTextCursor &textcursor, int line) const
{
    QHexCursor* cursor = m_document->cursor();

    if((line != cursor->currentLine()) || !m_cursorenabled)
        return;

    textcursor.clearSelection();
    textcursor.setPosition(m_document->cursor()->currentColumn() * 3);

    if((m_selectedarea == QHexRenderer::HexArea) && !m_document->cursor()->currentNibble())
        textcursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);

    textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    if(m_selectedarea == QHexRenderer::AsciiArea)
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    QPalette palette = qApp->palette();
    QTextCharFormat charformat;

    if((cursor->insertionMode() == QHexCursor::OverwriteMode) || (m_selectedarea != QHexRenderer::HexArea))
    {
        charformat.setForeground(palette.color(QPalette::Window));

        if(m_selectedarea == QHexRenderer::HexArea)
            charformat.setBackground(palette.color(QPalette::WindowText));
        else
            charformat.setBackground(palette.color(QPalette::WindowText).lighter(250));
    }
    else
        charformat.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline);

    textcursor.setCharFormat(charformat);
}

void QHexRenderer::drawAddress(QPainter* painter, const QPalette& palette, const QRect& linerect, int line)
{
    QRect addressrect = linerect;
    addressrect.setWidth(this->getHexColumnX());

    painter->save();
    painter->setPen(palette.color(QPalette::Highlight));

    painter->drawText(addressrect, Qt::AlignHCenter | Qt::AlignVCenter, QString("%1").arg(line * HEX_LINE_LENGTH,
                                                                                this->getAddressWidth(), 16,
                                                                                QLatin1Char('0')).toUpper());
    painter->restore();
}

void QHexRenderer::drawHex(QPainter *painter, const QPalette &palette, const QRect &linerect, int line)
{
    QTextDocument textdocument;
    QTextCursor textcursor(&textdocument);
    QByteArray rawline;

    textcursor.insertText(this->hexString(line, &rawline));

    if(line == this->documentLastLine())
        textcursor.insertText(" ");

    QRect hexrect = linerect;
    hexrect.setX(this->getHexColumnX() + this->getCellWidth());

    this->applyDocumentStyles(painter, &textdocument);
    this->applyBasicStyle(textcursor, rawline, 3);
    this->applyMetadata(textcursor, line, 3);
    this->applySelection(textcursor, line, 3);
    this->applyCursorHex(textcursor, line);

    painter->save();
    painter->translate(hexrect.topLeft());
    textdocument.drawContents(painter);
    painter->restore();
}

void QHexRenderer::drawAscii(QPainter *painter, const QPalette &palette, const QRect &linerect, int line)
{
    QTextDocument textdocument;
    QTextCursor textcursor(&textdocument);
    QByteArray rawline;
    textcursor.insertText(this->asciiString(line, &rawline));

    if(line == this->documentLastLine())
        textcursor.insertText(" ");

    QRect asciirect = linerect;
    asciirect.setX(this->getAsciiColumnX() + this->getCellWidth());

    this->applyDocumentStyles(painter, &textdocument);
    this->applyBasicStyle(textcursor, rawline);
    this->applyMetadata(textcursor, line);
    this->applySelection(textcursor, line);
    this->applyCursorAscii(textcursor, line);

    painter->save();
    painter->translate(asciirect.topLeft());
    textdocument.drawContents(painter);
    painter->restore();
}
<commit_msg>QHexRenderer: Detect dark themes, added workaround for black foreground color<commit_after>#include "qhexrenderer.h"
#include <QApplication>
#include <QTextCursor>
#include <QWidget>
#include <cctype>
#include <cmath>

#define HEX_UNPRINTABLE_CHAR     '.'

QHexRenderer::QHexRenderer(QHexDocument* document, const QFontMetrics &fontmetrics, QObject *parent) : QObject(parent), m_document(document), m_fontmetrics(fontmetrics)
{
    m_selectedarea = QHexRenderer::HexArea;
    m_cursorenabled = false;
}

void QHexRenderer::renderFrame(QPainter *painter)
{
    QWidget* widget = dynamic_cast<QWidget*>(painter->device());

    if(!widget)
        return;

    QRect rect = widget->rect();
    int hexx = this->getHexColumnX();
    int asciix = this->getAsciiColumnX();
    int endx = this->getEndColumnX();

    painter->drawLine(rect.x() + hexx,
                      rect.top(),
                      rect.x() + hexx,
                      rect.bottom());

    painter->drawLine(rect.x() + asciix,
                      rect.top(),
                      rect.x() + asciix,
                      rect.bottom());

    painter->drawLine(rect.x() + endx,
                      rect.top(),
                      rect.x() + endx,
                      rect.bottom());
}

void QHexRenderer::render(QPainter *painter, int start, int count, int firstline)
{
    int end = start + count;
    QPalette palette = qApp->palette();

    for(int line = start; line < std::min(end, this->documentLines()); line++)
    {
        QRect linerect = this->getLineRect(line, firstline);

        if(line % 2)
            painter->fillRect(linerect, palette.brush(QPalette::Window));
        else
            painter->fillRect(linerect, palette.brush(QPalette::Base));

        this->drawAddress(painter, palette, linerect, line);
        this->drawHex(painter, palette, linerect, line);
        this->drawAscii(painter, palette, linerect, line);
    }
}

void QHexRenderer::enableCursor(bool b) { m_cursorenabled = b; }

void QHexRenderer::selectArea(const QPoint &pt)
{
    int area = this->hitTestArea(pt);

    if(area == QHexRenderer::AddressArea)
        return;

    m_selectedarea = area;
}

bool QHexRenderer::hitTest(const QPoint &pt, QHexPosition *position, int firstline) const
{
    int area = this->hitTestArea(pt);

    if(area == QHexRenderer::AddressArea)
        return false;

    position->line = std::min(firstline + (pt.y() / this->lineHeight()), this->documentLastLine());

    if(area == QHexRenderer::HexArea)
    {
        int relx = pt.x() - this->getHexColumnX();
        position->column = relx / (this->getCellWidth() * 3);
        position->nibbleindex = this->getNibbleIndex(position->line, relx);
    }
    else
    {
        int relx = pt.x() - this->getAsciiColumnX() - this->getCellWidth();
        position->column = relx / this->getCellWidth();
        position->nibbleindex = 1;
    }

    if(position->line == this->documentLastLine()) // Check last line's columns
    {
        QByteArray ba = this->getLine(position->line);
        position->column = std::min(position->column, ba.length());
    }
    else
        position->column = std::min(position->column, HEX_LINE_LAST_COLUMN);

    return true;
}

int QHexRenderer::hitTestArea(const QPoint &pt) const
{
    if((pt.x() >= 0) && (pt.x() <= this->getHexColumnX()))
        return QHexRenderer::AddressArea;

    if((pt.x() > this->getHexColumnX()) && (pt.x() < this->getAsciiColumnX()))
        return QHexRenderer::HexArea;

    if((pt.x() > this->getAsciiColumnX()) && (pt.x() < this->getEndColumnX()))
        return QHexRenderer::AsciiArea;

    return QHexRenderer::ExtraArea;
}

int QHexRenderer::selectedArea() const { return m_selectedarea; }
int QHexRenderer::documentLastLine() const { return this->documentLines() - 1; }
int QHexRenderer::documentLastColumn() const { return this->getLine(this->documentLastLine()).length(); }
int QHexRenderer::documentLines() const { return std::ceil(this->rendererLength() / static_cast<float>(HEX_LINE_LENGTH));  }
int QHexRenderer::documentWidth() const { return this->getAsciiColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH + 1)); }
int QHexRenderer::lineHeight() const { return m_fontmetrics.height(); }
QRect QHexRenderer::getLineRect(int line, int firstline) const { return QRect(0, (line - firstline) * m_fontmetrics.height(), this->getEndColumnX(), m_fontmetrics.height()); }

QString QHexRenderer::hexString(int line, QByteArray* rawline) const
{
    QByteArray lrawline = this->getLine(line);

    if(rawline)
        *rawline = lrawline;

    return lrawline.toHex(' ').toUpper() + " ";
}

QString QHexRenderer::asciiString(int line, QByteArray* rawline) const
{
    QByteArray lrawline = this->getLine(line);

    if(rawline)
        *rawline = lrawline;

    QByteArray ascii = lrawline;
    this->unprintableChars(ascii);
    return ascii;
}

QByteArray QHexRenderer::getLine(int line) const { return m_document->read(line * HEX_LINE_LENGTH, HEX_LINE_LENGTH); }
void QHexRenderer::blinkCursor() { m_cursorenabled = !m_cursorenabled; }
int QHexRenderer::rendererLength() const { return m_document->length() + 1; }

int QHexRenderer::getAddressWidth() const
{
    if(this->rendererLength() <= 0xFFFF)
        return 8;

    if(this->rendererLength() <= 0xFFFFFFFF)
        return 16;

    return QString::number(this->rendererLength(), 16).length();
}

int QHexRenderer::getHexColumnX() const { return this->getCellWidth() * (this->getAddressWidth() + 1); }
int QHexRenderer::getAsciiColumnX() const { return this->getHexColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH * 3)); }
int QHexRenderer::getEndColumnX() const { return this->getAsciiColumnX() + (this->getCellWidth() * (HEX_LINE_LENGTH + 1)); }

int QHexRenderer::getCellWidth() const
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    return m_fontmetrics.horizontalAdvance(" ");
#else
    return m_fontmetrics.width(" ");
#endif
}

int QHexRenderer::getNibbleIndex(int line, int relx) const
{
    relx -= this->getCellWidth(); // Remove padding
    QString hexstring = this->hexString(line);

    for(int i = 0; i < hexstring.size(); i++)
    {
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
        int x = m_fontmetrics.horizontalAdvance(hexstring, i + 1);
#else
        int x = m_fontmetrics.width(hexstring, i + 1);
#endif
        if(x < relx)
            continue;

        if((i == (hexstring.size() - 1)) || (hexstring[i + 1] == ' '))
            return 0;

        break;
    }

    return 1;
}

void QHexRenderer::unprintableChars(QByteArray &ascii) const
{
    for(char& ch : ascii)
    {
        if(std::isprint(ch))
            continue;

        ch = HEX_UNPRINTABLE_CHAR;
    }
}

void QHexRenderer::applyDocumentStyles(QPainter *painter, QTextDocument* textdocument) const
{
    textdocument->setDocumentMargin(0);
    textdocument->setUndoRedoEnabled(false);
    textdocument->setDefaultFont(painter->font());
}

void QHexRenderer::applyBasicStyle(QTextCursor &textcursor, const QByteArray &rawline, int factor) const
{
    QPalette palette = qApp->palette();
    QColor color = palette.color(QPalette::WindowText);

    if(color.lightness() < 50)
    {
        if(color == Qt::black)
            color = Qt::gray;
        else
            color = color.lighter();
    }
    else
        color = color.darker();

    QTextCharFormat charformat;
    charformat.setForeground(color);

    for(int i = 0; i < rawline.length(); i++)
    {
        if((rawline[i] != 0x00) && (rawline[i] != 0xFF))
            continue;

        textcursor.setPosition(i * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, factor);
        textcursor.setCharFormat(charformat);
    }
}

void QHexRenderer::applyMetadata(QTextCursor &textcursor, int line, int factor) const
{
    QHexMetadata* metadata = m_document->metadata();

    if(!metadata->hasMetadata(line))
        return;

    const QHexLineMetadata& linemetadata = metadata->get(line);

    for(const QHexMetadataItem& mi : linemetadata)
    {
        QTextCharFormat charformat;

        if(mi.background.isValid())
            charformat.setBackground(mi.background);

        if(mi.foreground.isValid())
            charformat.setForeground(mi.foreground);

        if(!mi.comment.isEmpty())
            charformat.setUnderlineStyle(QTextCharFormat::SingleUnderline);

        textcursor.setPosition(mi.start * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, (mi.length * factor) - (factor > 1 ? 1 : 0));
        textcursor.setCharFormat(charformat);
    }
}

void QHexRenderer::applySelection(QTextCursor &textcursor, int line, int factor) const
{
    QHexCursor* cursor = m_document->cursor();

    if(!cursor->isLineSelected(line))
        return;

    const QHexPosition& startsel = cursor->selectionStart();
    const QHexPosition& endsel = cursor->selectionEnd();

    if(startsel.line == endsel.line)
    {
        textcursor.setPosition(startsel.column * factor);
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ((endsel.column - startsel.column + 1) * factor) - 1);
    }
    else
    {
        if(line == startsel.line)
            textcursor.setPosition(startsel.column * factor);
        else
            textcursor.setPosition(0);

        if(line == endsel.line)
            textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ((endsel.column + 1) * factor) - 1);
        else
            textcursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
    }

    QPalette palette = qApp->palette();

    QTextCharFormat charformat;
    charformat.setBackground(palette.color(QPalette::Highlight));
    charformat.setForeground(palette.color(QPalette::HighlightedText));
    textcursor.setCharFormat(charformat);
}

void QHexRenderer::applyCursorAscii(QTextCursor &textcursor, int line) const
{
    QHexCursor* cursor = m_document->cursor();

    if((line != cursor->currentLine()) || !m_cursorenabled)
        return;

    textcursor.clearSelection();
    textcursor.setPosition(m_document->cursor()->currentColumn());
    textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    QPalette palette = qApp->palette();

    QTextCharFormat charformat;

    if((cursor->insertionMode() == QHexCursor::OverwriteMode) || (m_selectedarea != QHexRenderer::AsciiArea))
    {
        charformat.setForeground(palette.color(QPalette::Window));

        if(m_selectedarea == QHexRenderer::AsciiArea)
            charformat.setBackground(palette.color(QPalette::WindowText));
        else
            charformat.setBackground(palette.color(QPalette::WindowText).lighter(250));
    }
    else
    {
        charformat.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline);
    }

    textcursor.setCharFormat(charformat);
}

void QHexRenderer::applyCursorHex(QTextCursor &textcursor, int line) const
{
    QHexCursor* cursor = m_document->cursor();

    if((line != cursor->currentLine()) || !m_cursorenabled)
        return;

    textcursor.clearSelection();
    textcursor.setPosition(m_document->cursor()->currentColumn() * 3);

    if((m_selectedarea == QHexRenderer::HexArea) && !m_document->cursor()->currentNibble())
        textcursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);

    textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    if(m_selectedarea == QHexRenderer::AsciiArea)
        textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);

    QPalette palette = qApp->palette();
    QTextCharFormat charformat;

    if((cursor->insertionMode() == QHexCursor::OverwriteMode) || (m_selectedarea != QHexRenderer::HexArea))
    {
        charformat.setForeground(palette.color(QPalette::Window));

        if(m_selectedarea == QHexRenderer::HexArea)
            charformat.setBackground(palette.color(QPalette::WindowText));
        else
            charformat.setBackground(palette.color(QPalette::WindowText).lighter(250));
    }
    else
        charformat.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline);

    textcursor.setCharFormat(charformat);
}

void QHexRenderer::drawAddress(QPainter* painter, const QPalette& palette, const QRect& linerect, int line)
{
    QRect addressrect = linerect;
    addressrect.setWidth(this->getHexColumnX());

    painter->save();
    painter->setPen(palette.color(QPalette::Highlight));

    painter->drawText(addressrect, Qt::AlignHCenter | Qt::AlignVCenter, QString("%1").arg(line * HEX_LINE_LENGTH,
                                                                                this->getAddressWidth(), 16,
                                                                                QLatin1Char('0')).toUpper());
    painter->restore();
}

void QHexRenderer::drawHex(QPainter *painter, const QPalette &palette, const QRect &linerect, int line)
{
    QTextDocument textdocument;
    QTextCursor textcursor(&textdocument);
    QByteArray rawline;

    textcursor.insertText(this->hexString(line, &rawline));

    if(line == this->documentLastLine())
        textcursor.insertText(" ");

    QRect hexrect = linerect;
    hexrect.setX(this->getHexColumnX() + this->getCellWidth());

    this->applyDocumentStyles(painter, &textdocument);
    this->applyBasicStyle(textcursor, rawline, 3);
    this->applyMetadata(textcursor, line, 3);
    this->applySelection(textcursor, line, 3);
    this->applyCursorHex(textcursor, line);

    painter->save();
    painter->translate(hexrect.topLeft());
    textdocument.drawContents(painter);
    painter->restore();
}

void QHexRenderer::drawAscii(QPainter *painter, const QPalette &palette, const QRect &linerect, int line)
{
    QTextDocument textdocument;
    QTextCursor textcursor(&textdocument);
    QByteArray rawline;
    textcursor.insertText(this->asciiString(line, &rawline));

    if(line == this->documentLastLine())
        textcursor.insertText(" ");

    QRect asciirect = linerect;
    asciirect.setX(this->getAsciiColumnX() + this->getCellWidth());

    this->applyDocumentStyles(painter, &textdocument);
    this->applyBasicStyle(textcursor, rawline);
    this->applyMetadata(textcursor, line);
    this->applySelection(textcursor, line);
    this->applyCursorAscii(textcursor, line);

    painter->save();
    painter->translate(asciirect.topLeft());
    textdocument.drawContents(painter);
    painter->restore();
}
<|endoftext|>


<commit_before>/*
 * File:   CrossMatch.cpp
 * Author: xy
 *
 * Created on October 18, 2013, 8:48 AM
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "CrossMatch.h"

CrossMatch::CrossMatch() {

  refNum = 0;
  objNum = 0;
  refStarList = NULL;
  objStarList = NULL;
  refStarListNoPtn = NULL;
  objStarListNoPtn = NULL;
  zones = NULL;
}

CrossMatch::CrossMatch(const CrossMatch& orig) {
}

CrossMatch::~CrossMatch() {
}

void CrossMatch::match(char *refName, char *objName, float errorBox) {

  float minZoneLen = errorBox * TimesOfErrorRadius;
  float searchRds = errorBox;

  refStarList = readStarFile(refName, refNum);
  objStarList = readStarFile(objName, objNum);

  zones = new Partition(errorBox, minZoneLen, searchRds);
  zones->partitonStarField(refStarList, refNum);
  refStarList = NULL;

  cm_star *nextStar = objStarList;
  while (nextStar) {
    zones->getMatchStar(nextStar);
    nextStar = nextStar->next;
  }

#ifdef PRINT_CM_DETAIL
  printf("partition match done!\n");
#endif
}

void CrossMatch::match(cm_star *ref, int refNum, cm_star *obj, float errorBox) {

  float minZoneLen = errorBox * TimesOfErrorRadius;
  float searchRds = errorBox;

  zones = new Partition(errorBox, minZoneLen, searchRds);
  zones->partitonStarField(ref, refNum);
  ref = NULL;

  cm_star *nextStar = obj;
  while (nextStar) {
    zones->getMatchStar(nextStar);
    nextStar = nextStar->next;
  }

#ifdef PRINT_CM_DETAIL
  printf("partition match done!\n");
#endif
}

/**
 * circulate each star on 'refList', find the nearest on as the match star of objStar
 * the matched star is stored on obj->match,
 * the distance between two stars is stored on obj->error
 * @param ref
 * @param obj
 */
void CrossMatch::matchNoPartition(char *refName, char *objName, float errorBox) {

  int refNum, objNum;
  refStarListNoPtn = readStarFile(refName, refNum);
  objStarListNoPtn = readStarFile(objName, objNum);

  cm_star *tObj = objStarListNoPtn;

  while (tObj) {
    float tError = 0.0;
    float minError = getLineDistance(refStarListNoPtn, tObj);
    tObj->match = refStarListNoPtn;
    tObj->error = minError;
    cm_star *tRef = refStarListNoPtn->next;
    while (tRef) {
      tError = getLineDistance(tRef, tObj);
      if (tError < minError) {
        minError = tError;
        tObj->match = tRef;
        tObj->error = tError;
      }
      tRef = tRef->next;
    }
    tObj = tObj->next;
  }

  //freeStarList(refStarListNoPtn);
  //freeStarList(objStarListNoPtn);
#ifdef PRINT_CM_DETAIL
  printf("no partition match done!\n");
#endif
}

/**
 * the matched star is stored on obj->match,
 * the distance between two stars is stored on obj->error
 * @param ref
 * @param obj
 */
void CrossMatch::matchNoPartition(cm_star *ref, cm_star *obj, float errorBox) {

  cm_star *tObj = obj;

  while (tObj) {
    float tError = 0.0;
    float minError = getLineDistance(ref, tObj);
    tObj->match = refStarListNoPtn;
    tObj->error = minError;
    cm_star *tRef = ref->next;
    while (tRef) {
      tError = getLineDistance(tRef, tObj);
      if (tError < minError) {
        minError = tError;
        tObj->match = tRef;
        tObj->error = tError;
      }
      tRef = tRef->next;
    }
    tObj = tObj->next;
  }
}

/**
 * default only read first three column(X, Y, mag)
 * @param fName
 * @param starNum
 * @return
 */
cm_star *CrossMatch::readStarFile(char *fName, int &starNum) {

  FILE *fp = fopen(fName, "r");
  if (fp == NULL) {
    return NULL;
  }

  starNum = 0;
  cm_star *starList = NULL;
  cm_star *tStar = NULL;
  cm_star *nextStar = NULL;
  char line[MaxStringLength];

  while (fgets(line, MaxStringLength, fp) != NULL) {
    if (3 == sscanf(line, "%f%f%f", &nextStar->pixx, &nextStar->pixy, &nextStar->mag)) {
      nextStar = (cm_star *) malloc(sizeof (cm_star));
      nextStar->id = starNum;
      nextStar->next = NULL;
      if (NULL == starList) {
        starList = nextStar;
        tStar = nextStar;
      } else {
        tStar->next = nextStar;
        tStar = nextStar;
      }
      starNum++;
    }
  }

#ifdef PRINT_CM_DETAIL
  printf("%s\t%d stars\n", fName, starNum);
#endif
  return starList;
}

cm_star *CrossMatch::copyStarList(cm_star *starlst) {

  cm_star *tHead = NULL;
  cm_star *tStar = NULL;
  cm_star *origlst = starlst;

  if (NULL != origlst) {
    tHead = (cm_star *) malloc(sizeof (cm_star));
    memcpy(tHead, origlst, sizeof (cm_star));
    origlst = origlst->next;
    tStar = tHead;
  }

  while (NULL != origlst) {
    tStar->next = (cm_star *) malloc(sizeof (cm_star));
    memcpy(tStar->next, origlst, sizeof (cm_star));
    origlst = origlst->next;
    tStar = tStar->next;
  }
  return tHead;
}

void CrossMatch::freeStarList(cm_star *starList) {

  if (NULL != starList) {
    cm_star *tStar = starList->next;
    while (tStar) {
      starList->next = tStar->next;
      free(tStar);
      tStar = starList->next;
    }
    free(starList);
  }
}

void CrossMatch::freeAllMemory() {

  freeStarList(refStarList);
  freeStarList(objStarList);
  freeStarList(refStarListNoPtn);
  freeStarList(objStarListNoPtn);
  if (NULL != zones) {
    zones->freeZoneArray();
  }
}

void CrossMatch::compareResult(char *refName, char *objName, char *outfName, float errorBox) {

  match(refName, objName, errorBox);
  matchNoPartition(refName, objName, errorBox);

  FILE *fp = fopen(outfName, "w");

  cm_star *tStar1 = objStarList;
  cm_star *tStar2 = objStarListNoPtn;
  int i = 0, j = 0, k = 0, m = 0, n = 0, g = 0;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL != tStar1->match && NULL != tStar2->match) {
      i++;
      float errDiff = fabs(tStar1->error - tStar2->error);
      if (errDiff < CompareFloat)
        n++;
    } else if (NULL != tStar1->match && NULL == tStar2->match) {
      j++;
    } else if (NULL == tStar1->match && NULL != tStar2->match) {//ommit and OT
      k++;
      if (tStar2->error < errorBox)
        g++;
    } else {
      m++;
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }
  fprintf(fp, "total star %d\n", i + j + k + m);
  fprintf(fp, "matched %d , two method same %d\n", i, n);
  fprintf(fp, "partition matched but nopartition notmatched %d\n", j);
  fprintf(fp, "nopartition matched but partition notmatched %d, small than errorBox %d\n", k, g);
  fprintf(fp, "two method are not matched %d\n", m);

  fprintf(fp, "\nX1,Y1,X1m,Y1m,err1 is the partition related info\n");
  fprintf(fp, "X2,Y2,X2m,Y2m,err2 is the nopartition related info\n");
  fprintf(fp, "X1,Y1,X2,Y2 is orig X and Y position of stars\n");
  fprintf(fp, "X1m,Y1m,X2m,Y2m is matched X and Y position of stars\n");
  fprintf(fp, "pos1,pos2 is the two method's match distance\n");
  fprintf(fp, "the following list is leaked star of partition method\n");
  fprintf(fp, "X1\tY1\tX2\tY2\tX1m\tY1m\tX2m\tY2m\tpos1\tpos2\n");
  tStar1 = objStarList;
  tStar2 = objStarListNoPtn;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL == tStar1->match && NULL != tStar2->match && tStar2->error < errorBox) { //ommit and OT
      fprintf(fp, "%12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\n",
              tStar1->pixx, tStar1->pixy, tStar2->pixx, tStar2->pixy,
              0.0, 0.0, tStar2->match->pixx, tStar2->match->pixy,
              tStar1->error, tStar2->error);
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }

  fprintf(fp, "the following list is OT\n");
  fprintf(fp, "X1\tY1\tX2\tY2\tX1m\tY1m\tX2m\tY2m\tpos1\tpos2\n");
  tStar1 = objStarList;
  tStar2 = objStarListNoPtn;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL == tStar1->match && NULL != tStar2->match && tStar2->error > errorBox) { //ommit and OT
      fprintf(fp, "%12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\n",
              tStar1->pixx, tStar1->pixy, tStar2->pixx, tStar2->pixy,
              0.0, 0.0, tStar2->match->pixx, tStar2->match->pixy,
              tStar1->error, tStar2->error);
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }

  fclose(fp);
  freeAllMemory();
}

void CrossMatch::printMatchedRst(char *outfName, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = objStarList;
  while (NULL != tStar) {
    if (NULL != tStar->match && tStar->error < errorBox) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printMatchedRst(char *outfName, cm_star *starList, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = starList;
  while (NULL != tStar) {
    if (NULL != tStar->match && tStar->error < errorBox) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printAllStarList(char *outfName, cm_star *starList, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = starList;
  while (NULL != tStar) {
    if (NULL != tStar->match) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
    } else {
      fprintf(fp, "%8ld %12f %12f %8d %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, 0, 0.0, 0.0, tStar->error);
    }
    count++;
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printOTStar(char *outfName, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\n");

  long count = 0;
  cm_star *tStar = objStarList;
  while (NULL != tStar) {
    if (NULL == tStar->match) {
      fprintf(fp, "%8ld %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("OT stars %d\n", count);
#endif
}<commit_msg>Bugs repair: CrossMatch->readStarFile Bring a bug to function readStarFile on last time's repair.<commit_after>/*
 * File:   CrossMatch.cpp
 * Author: xy
 *
 * Created on October 18, 2013, 8:48 AM
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "CrossMatch.h"

CrossMatch::CrossMatch() {

  refNum = 0;
  objNum = 0;
  refStarList = NULL;
  objStarList = NULL;
  refStarListNoPtn = NULL;
  objStarListNoPtn = NULL;
  zones = NULL;
}

CrossMatch::CrossMatch(const CrossMatch& orig) {
}

CrossMatch::~CrossMatch() {
}

void CrossMatch::match(char *refName, char *objName, float errorBox) {

  float minZoneLen = errorBox * TimesOfErrorRadius;
  float searchRds = errorBox;

  refStarList = readStarFile(refName, refNum);
  objStarList = readStarFile(objName, objNum);

  zones = new Partition(errorBox, minZoneLen, searchRds);
  zones->partitonStarField(refStarList, refNum);
  refStarList = NULL;

  cm_star *nextStar = objStarList;
  while (nextStar) {
    zones->getMatchStar(nextStar);
    nextStar = nextStar->next;
  }

#ifdef PRINT_CM_DETAIL
  printf("partition match done!\n");
#endif
}

void CrossMatch::match(cm_star *ref, int refNum, cm_star *obj, float errorBox) {

  float minZoneLen = errorBox * TimesOfErrorRadius;
  float searchRds = errorBox;

  zones = new Partition(errorBox, minZoneLen, searchRds);
  zones->partitonStarField(ref, refNum);
  ref = NULL;

  cm_star *nextStar = obj;
  while (nextStar) {
    zones->getMatchStar(nextStar);
    nextStar = nextStar->next;
  }

#ifdef PRINT_CM_DETAIL
  printf("partition match done!\n");
#endif
}

/**
 * circulate each star on 'refList', find the nearest on as the match star of objStar
 * the matched star is stored on obj->match,
 * the distance between two stars is stored on obj->error
 * @param ref
 * @param obj
 */
void CrossMatch::matchNoPartition(char *refName, char *objName, float errorBox) {

  int refNum, objNum;
  refStarListNoPtn = readStarFile(refName, refNum);
  objStarListNoPtn = readStarFile(objName, objNum);

  cm_star *tObj = objStarListNoPtn;

  while (tObj) {
    float tError = 0.0;
    float minError = getLineDistance(refStarListNoPtn, tObj);
    tObj->match = refStarListNoPtn;
    tObj->error = minError;
    cm_star *tRef = refStarListNoPtn->next;
    while (tRef) {
      tError = getLineDistance(tRef, tObj);
      if (tError < minError) {
        minError = tError;
        tObj->match = tRef;
        tObj->error = tError;
      }
      tRef = tRef->next;
    }
    tObj = tObj->next;
  }

  //freeStarList(refStarListNoPtn);
  //freeStarList(objStarListNoPtn);
#ifdef PRINT_CM_DETAIL
  printf("no partition match done!\n");
#endif
}

/**
 * the matched star is stored on obj->match,
 * the distance between two stars is stored on obj->error
 * @param ref
 * @param obj
 */
void CrossMatch::matchNoPartition(cm_star *ref, cm_star *obj, float errorBox) {

  cm_star *tObj = obj;

  while (tObj) {
    float tError = 0.0;
    float minError = getLineDistance(ref, tObj);
    tObj->match = refStarListNoPtn;
    tObj->error = minError;
    cm_star *tRef = ref->next;
    while (tRef) {
      tError = getLineDistance(tRef, tObj);
      if (tError < minError) {
        minError = tError;
        tObj->match = tRef;
        tObj->error = tError;
      }
      tRef = tRef->next;
    }
    tObj = tObj->next;
  }
}

/**
 * default only read first three column(X, Y, mag)
 * @param fName
 * @param starNum
 * @return
 */
cm_star *CrossMatch::readStarFile(char *fName, int &starNum) {

  FILE *fp = fopen(fName, "r");
  if (fp == NULL) {
    return NULL;
  }

  starNum = 0;
  float tx=0, ty=0, tmag=0;
  cm_star *starList = NULL;
  cm_star *tStar = NULL;
  cm_star *nextStar = NULL;
  char line[MaxStringLength];

  while (fgets(line, MaxStringLength, fp) != NULL) {
    if (3 == sscanf(line, "%f%f%f", &tx, &ty, &tmag)) {
      nextStar = (cm_star *) malloc(sizeof (cm_star));
      nextStar->id = starNum;
      nextStar->pixx = tx;
      nextStar->pixy = ty;
      nextStar->mag = tmag;
      nextStar->next = NULL;
      if (NULL == starList) {
        starList = nextStar;
        tStar = nextStar;
      } else {
        tStar->next = nextStar;
        tStar = nextStar;
      }
      starNum++;
    }
  }

#ifdef PRINT_CM_DETAIL
  printf("%s\t%d stars\n", fName, starNum);
#endif
  return starList;
}

cm_star *CrossMatch::copyStarList(cm_star *starlst) {

  cm_star *tHead = NULL;
  cm_star *tStar = NULL;
  cm_star *origlst = starlst;

  if (NULL != origlst) {
    tHead = (cm_star *) malloc(sizeof (cm_star));
    memcpy(tHead, origlst, sizeof (cm_star));
    origlst = origlst->next;
    tStar = tHead;
  }

  while (NULL != origlst) {
    tStar->next = (cm_star *) malloc(sizeof (cm_star));
    memcpy(tStar->next, origlst, sizeof (cm_star));
    origlst = origlst->next;
    tStar = tStar->next;
  }
  return tHead;
}

void CrossMatch::freeStarList(cm_star *starList) {

  if (NULL != starList) {
    cm_star *tStar = starList->next;
    while (tStar) {
      starList->next = tStar->next;
      free(tStar);
      tStar = starList->next;
    }
    free(starList);
  }
}

void CrossMatch::freeAllMemory() {

  freeStarList(refStarList);
  freeStarList(objStarList);
  freeStarList(refStarListNoPtn);
  freeStarList(objStarListNoPtn);
  if (NULL != zones) {
    zones->freeZoneArray();
  }
}

void CrossMatch::compareResult(char *refName, char *objName, char *outfName, float errorBox) {

  match(refName, objName, errorBox);
  matchNoPartition(refName, objName, errorBox);

  FILE *fp = fopen(outfName, "w");

  cm_star *tStar1 = objStarList;
  cm_star *tStar2 = objStarListNoPtn;
  int i = 0, j = 0, k = 0, m = 0, n = 0, g = 0;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL != tStar1->match && NULL != tStar2->match) {
      i++;
      float errDiff = fabs(tStar1->error - tStar2->error);
      if (errDiff < CompareFloat)
        n++;
    } else if (NULL != tStar1->match && NULL == tStar2->match) {
      j++;
    } else if (NULL == tStar1->match && NULL != tStar2->match) {//ommit and OT
      k++;
      if (tStar2->error < errorBox)
        g++;
    } else {
      m++;
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }
  fprintf(fp, "total star %d\n", i + j + k + m);
  fprintf(fp, "matched %d , two method same %d\n", i, n);
  fprintf(fp, "partition matched but nopartition notmatched %d\n", j);
  fprintf(fp, "nopartition matched but partition notmatched %d, small than errorBox %d\n", k, g);
  fprintf(fp, "two method are not matched %d\n", m);

  fprintf(fp, "\nX1,Y1,X1m,Y1m,err1 is the partition related info\n");
  fprintf(fp, "X2,Y2,X2m,Y2m,err2 is the nopartition related info\n");
  fprintf(fp, "X1,Y1,X2,Y2 is orig X and Y position of stars\n");
  fprintf(fp, "X1m,Y1m,X2m,Y2m is matched X and Y position of stars\n");
  fprintf(fp, "pos1,pos2 is the two method's match distance\n");
  fprintf(fp, "the following list is leaked star of partition method\n");
  fprintf(fp, "X1\tY1\tX2\tY2\tX1m\tY1m\tX2m\tY2m\tpos1\tpos2\n");
  tStar1 = objStarList;
  tStar2 = objStarListNoPtn;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL == tStar1->match && NULL != tStar2->match && tStar2->error < errorBox) { //ommit and OT
      fprintf(fp, "%12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\n",
              tStar1->pixx, tStar1->pixy, tStar2->pixx, tStar2->pixy,
              0.0, 0.0, tStar2->match->pixx, tStar2->match->pixy,
              tStar1->error, tStar2->error);
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }

  fprintf(fp, "the following list is OT\n");
  fprintf(fp, "X1\tY1\tX2\tY2\tX1m\tY1m\tX2m\tY2m\tpos1\tpos2\n");
  tStar1 = objStarList;
  tStar2 = objStarListNoPtn;
  while (NULL != tStar1 && NULL != tStar2) {
    if (NULL == tStar1->match && NULL != tStar2->match && tStar2->error > errorBox) { //ommit and OT
      fprintf(fp, "%12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\n",
              tStar1->pixx, tStar1->pixy, tStar2->pixx, tStar2->pixy,
              0.0, 0.0, tStar2->match->pixx, tStar2->match->pixy,
              tStar1->error, tStar2->error);
    }
    tStar1 = tStar1->next;
    tStar2 = tStar2->next;
  }

  fclose(fp);
  freeAllMemory();
}

void CrossMatch::printMatchedRst(char *outfName, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = objStarList;
  while (NULL != tStar) {
    if (NULL != tStar->match && tStar->error < errorBox) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printMatchedRst(char *outfName, cm_star *starList, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = starList;
  while (NULL != tStar) {
    if (NULL != tStar->match && tStar->error < errorBox) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printAllStarList(char *outfName, cm_star *starList, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\tmId\tmX\tmY\tdistance\n");

  long count = 0;
  cm_star *tStar = starList;
  while (NULL != tStar) {
    if (NULL != tStar->match) {
      fprintf(fp, "%8ld %12f %12f %8ld %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, tStar->match->starId,
              tStar->match->pixx, tStar->match->pixy, tStar->error);
    } else {
      fprintf(fp, "%8ld %12f %12f %8d %12f %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy, 0, 0.0, 0.0, tStar->error);
    }
    count++;
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("matched stars %d\n", count);
#endif
}

void CrossMatch::printOTStar(char *outfName, float errorBox) {

  FILE *fp = fopen(outfName, "w");
  fprintf(fp, "Id\tX\tY\n");

  long count = 0;
  cm_star *tStar = objStarList;
  while (NULL != tStar) {
    if (NULL == tStar->match) {
      fprintf(fp, "%8ld %12f %12f\n",
              tStar->starId, tStar->pixx, tStar->pixy);
      count++;
    }
    tStar = tStar->next;
  }
  fclose(fp);

#ifdef PRINT_CM_DETAIL
  printf("OT stars %d\n", count);
#endif
}<|endoftext|>


<commit_before>#include "CurlClient.h"

#include "BasicAuth.h"

#include <cstdio>
#include <cstring>
#include <cassert>
#include <cctype>
#include <iostream>
#include <pthread.h>

using namespace std;

#include <curl/curl.h>

class CurlClient : public HTTPClient {
 public:
  CurlClient(const std::string & _interface, const std::string & _user_agent, bool _enable_cookies = true, bool _enable_keepalive = true)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive),
      interface_name(_interface)
  {

  }
  CurlClient(const CurlClient & other) : HTTPClient(other),
					 interface_name(other.interface_name)
  {

  }

  ~CurlClient() {
    if (curl) curl_easy_cleanup(curl);
  }

  HTTPResponse request(const HTTPRequest & req, const Authorization & auth,   HTTPClientInterface * callback) override {
    if (req.getURI().empty()) {
      return HTTPResponse(0, "empty URI");
    }
    if (!initialize()) {
      return HTTPResponse(0, "Unable to initialize client");
    }

    // string ascii_uri = encodeIDN(uri);
    // if (ascii_uri.empty()) {
    //   cerr << "failed to convert url " << uri << endl;
    //   assert(0);
    // }

    struct curl_slist * headers = 0;
    if (req.getType() == HTTPRequest::POST) {
      if (!req.getContentType().empty()) {
	string h = "Content-type: ";
	h += req.getContentType();
	headers = curl_slist_append(headers, h.c_str());
      }
    }

    const BasicAuth * basic = dynamic_cast<const BasicAuth *>(&auth);
    if (basic) {
      string s = basic->getUsername();
      s += ':';
      s += basic->getPassword();
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
      curl_easy_setopt(curl, CURLOPT_USERPWD, s.c_str());
    } else {
      string auth_header = auth.createHeader();
      if (!auth_header.empty()) {
	string s = auth.getHeaderName();
	s += ": ";
	s += auth_header;
	headers = curl_slist_append(headers, s.c_str());
      }
    }

    map<string, string> combined_headers;
    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      string s = hd.first;
      s += ": ";
      s += hd.second;
      headers = curl_slist_append(headers, s.c_str());
    }

    HTTPResponse response;
    response.setCallback(callback);

    if (req.getType() == HTTPRequest::POST) {
      curl_easy_setopt(curl, CURLOPT_POST, 1);
      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req.getContent().size());
      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req.getContent().data());
    } else {
      curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
    }
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, req.getFollowLocation());
    curl_easy_setopt(curl, CURLOPT_URL, req.getURI().c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, req.getTimeout());
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &response);
    if (!cookie_jar.empty()) {
      curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar.c_str());
      curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar.c_str());
    }

    CURLcode res = curl_easy_perform(curl);
    if (res == 0) {
      unsigned long a = 0;
      if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &a) == CURLE_OK) {
	response.setResultCode(a);
      }
      if (!req.getFollowLocation()) {
	char * ptr = 0;
	curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &ptr);
	if (ptr) {
	  if (callback) callback->handleRedirectUrl(ptr);
	  response.setRedirectUrl(ptr);
	}
      }
    } else {
      response.setResultCode(500);
      response.setErrorText(curl_easy_strerror(res));
    }

    if (headers) {
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, 0);
      curl_slist_free_all(headers);
    }

    curl_easy_setopt(curl, CURLOPT_HEADERDATA, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, 0);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, 0);

    return response;
  }

  void clearCookies() override {
    if (curl) {
      curl_easy_setopt(curl, CURLOPT_URL, "ALL"); // what does this do?
    }
  }

 protected:
  bool initialize() {
    if (curl) {
      curl_easy_reset(curl);
    } else {
      curl = curl_easy_init();
    }

    assert(curl);

    if (curl) {
#ifndef WIN32
      if (!interface_name.empty()) {
	int r = curl_easy_setopt(curl, CURLOPT_INTERFACE, interface_name.c_str());
	assert(r != CURLE_INTERFACE_FAILED);
      }
#endif
      curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
      curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_func);
      curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_func);
      curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headers_func);
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
      curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 600);
      // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
      if (!enable_keepalive) {
	curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
	curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
	// curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 10);
      }
      if (!cookie_jar.empty()) {
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar.c_str());
	curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar.c_str());
      } else if (enable_cookies) {
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
      }
    }

    return curl != 0;
  }

 private:
  static size_t write_data_func(void * buffer, size_t size, size_t nmemb, void *userp);
  static size_t headers_func(void * buffer, size_t size, size_t nmemb, void *userp);
  static int progress_func(void *  clientp, double dltotal, double dlnow, double ultotal, double ulnow);

  std::string interface_name;
  CURL * curl = 0;
};

size_t
CurlClient::write_data_func(void * buffer, size_t size, size_t nmemb, void * userp) {
  size_t s = size * nmemb;
  // Content-Type: multipart/x-mixed-replace; boundary=myboundary

  HTTPResponse * response = static_cast<HTTPResponse *>(userp);
  assert(response);
  if (response->getCallback()) {
    if (response->getCallback()->handleChunk(s, (const char *)buffer)) {
      return s;
    } else {
      return 0;
    }
  } else {
    response->appendContent(string((const char *)buffer, s));
    return s;
  }
}

size_t
CurlClient::headers_func(void * buffer, size_t size, size_t nmemb, void *userp) {
  HTTPResponse * response = static_cast<HTTPResponse *>(userp);

  int result = 0;
  if (buffer) {
    string s((const char*)buffer, size * nmemb);

    if (s.compare(0, 5, "HTTP/") == 0) {
      auto pos1 = s.find_first_of(' ');
      if (pos1 != -1) {
	auto pos2 = s.find_first_of(' ', pos1 + 1);
	if (pos2 != -1) {
	  auto s2 = s.substr(pos1, pos2 - pos1);
	  int code = atoi(s2.c_str());
	  cerr << "got result code: " << code << endl;
	  if (response->getCallback()) {
	    response->getCallback()->handleResultCode(code);
	  }
	}
      }
    } else {
      int pos1 = 0;
      for ( ; pos1 < s.size() && s[pos1] != ':'; pos1++) { }
      int pos2 = s[pos1] == ':' ? pos1 + 1 : pos1;
      for (; pos2 < s.size() && isspace(s[pos2]); pos2++) { }
      int pos3 = s.size();
      for (; pos3 > 0 && isspace(s[pos3 - 1]); pos3--) { }
      std::string key = s.substr(0, pos1);
      std::string value = s.substr(pos2, pos3 - pos2);

      if (response->getCallback() && key == "Location") {
	response->getCallback()->handleRedirectUrl(value);
      }

      if (response->getCallback()) {
	response->getCallback()->handleHeader(key, value);
      } else {
	response->addHeader(key, value);
      }
    }
    result = size * nmemb;
  }
  return result;
}

int
CurlClient::progress_func(void * clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
  HTTPResponse * response = static_cast<HTTPResponse *>(clientp);
  if (response->getCallback()) {
    return response->getCallback()->onIdle(true) ? 0 : 1;
  }
  return 0;
}

#ifndef __APPLE__
static pthread_mutex_t *lockarray;

#include <openssl/crypto.h>

static void lock_callback(int mode, int type, const char *file, int line) {
  (void)file;
  (void)line;
  if (mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&(lockarray[type]));
  } else {
    pthread_mutex_unlock(&(lockarray[type]));
  }
}

static unsigned long thread_id(void) {
  unsigned long ret;

#ifdef WIN32
  ret = (unsigned long)(pthread_self().p);
#else
  ret=(unsigned long)pthread_self();
#endif
  return(ret);
}

static void init_locks(void) {
  int i;

  lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
					      sizeof(pthread_mutex_t));
  for (i=0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_init(&(lockarray[i]),NULL);
  }

  CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  CRYPTO_set_locking_callback(lock_callback); // (void (*)())lock_callback);
}

static void kill_locks(void)
{
  int i;

  CRYPTO_set_locking_callback(NULL);
  for (i=0; i<CRYPTO_num_locks(); i++)
    pthread_mutex_destroy(&(lockarray[i]));

  OPENSSL_free(lockarray);
}
#endif

#if 0
#include <gcrypt.h>
#include <errno.h>
#include <gnutls/gnutls.h>

GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif

std::shared_ptr<HTTPClient>
CurlClientFactory::createClient(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::make_shared<CurlClient>("", _user_agent, _enable_cookies, _enable_keepalive);
}

void
CurlClientFactory::globalInit() {
#ifndef __APPLE__
#if 0
  gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
  gnutls_global_init();
#else
  init_locks();
#endif
#endif

  curl_global_init(CURL_GLOBAL_DEFAULT);

#if 0
  thread_setup();
#endif
#if 0
  gnutls_global_init();
#endif
}

void
CurlClientFactory::globalCleanup() {
  curl_global_cleanup();
#ifndef __APPLE__
  kill_locks();
#endif
}
<commit_msg>don't return HTTPResponse in request(), instead give all data to callback, refactor<commit_after>#include "CurlClient.h"

#include "BasicAuth.h"

#include <cstdio>
#include <cstring>
#include <cassert>
#include <cctype>
#include <iostream>
#include <pthread.h>

using namespace std;

#include <curl/curl.h>

static bool is_initialized = false;

class CurlClient : public HTTPClient {
 public:
  CurlClient(const std::string & _interface, const std::string & _user_agent, bool _enable_cookies = true, bool _enable_keepalive = true)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive),
      interface_name(_interface)
  {
    assert(is_initialized);
  }

  ~CurlClient() {
    if (curl) curl_easy_cleanup(curl);
  }

  void request(const HTTPRequest & req, const Authorization & auth, HTTPClientInterface & callback) override {
#if 0
    if (req.getURI().empty()) {
      return HTTPResponse(0, "empty URI");
    }
#endif
    if (!initialize()) {
      // return HTTPResponse(0, "Unable to initialize client");
      return;
    }

    // string ascii_uri = encodeIDN(uri);
    // if (ascii_uri.empty()) {
    //   cerr << "failed to convert url " << uri << endl;
    //   assert(0);
    // }

    struct curl_slist * headers = 0;
    if (req.getType() == HTTPRequest::POST) {
      if (!req.getContentType().empty()) {
	string h = "Content-type: ";
	h += req.getContentType();
	headers = curl_slist_append(headers, h.c_str());
      }
    }

    const BasicAuth * basic = dynamic_cast<const BasicAuth *>(&auth);
    if (basic) {
      string s = basic->getUsername();
      s += ':';
      s += basic->getPassword();
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
      curl_easy_setopt(curl, CURLOPT_USERPWD, s.c_str());
    } else {
      string auth_header = auth.createHeader();
      if (!auth_header.empty()) {
	string s = auth.getHeaderName();
	s += ": ";
	s += auth_header;
	headers = curl_slist_append(headers, s.c_str());
      }
    }

    map<string, string> combined_headers;
    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      string s = hd.first;
      s += ": ";
      s += hd.second;
      headers = curl_slist_append(headers, s.c_str());
    }

    if (req.getType() == HTTPRequest::POST) {
      curl_easy_setopt(curl, CURLOPT_POST, 1);
      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req.getContent().size());
      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req.getContent().data());
    } else {
      curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
    }
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, req.getFollowLocation());
    curl_easy_setopt(curl, CURLOPT_URL, req.getURI().c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, req.getTimeout());

    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &callback);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &callback);
    if (!cookie_jar.empty()) {
      curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar.c_str());
      curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar.c_str());
    }

    CURLcode res = curl_easy_perform(curl);
    // if (res != 0) {
    //   response.setResultCode(500);
    //   response.setErrorText(curl_easy_strerror(res));
    // }

    callback.handleDisconnect();

    if (headers) {
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, 0);
      curl_slist_free_all(headers);
    }

    curl_easy_setopt(curl, CURLOPT_HEADERDATA, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, 0);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, 0);

    // return response;
  }

  void clearCookies() override {
    if (curl) {
      curl_easy_setopt(curl, CURLOPT_URL, "ALL"); // what does this do?
    }
  }

 protected:
  bool initialize() {
    if (curl) {
      curl_easy_reset(curl);
    } else {
      curl = curl_easy_init();
    }

    assert(curl);

    if (curl) {
#ifndef WIN32
      if (!interface_name.empty()) {
	int r = curl_easy_setopt(curl, CURLOPT_INTERFACE, interface_name.c_str());
	assert(r != CURLE_INTERFACE_FAILED);
      }
#endif
      curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
      curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_func);
      curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_func);
      curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headers_func);
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
      curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 600);
      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
      if (!enable_keepalive) {
	curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
	curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
	// curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 10);
      }
      if (!cookie_jar.empty()) {
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar.c_str());
	curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar.c_str());
      } else if (enable_cookies) {
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
      }
    }

    return curl != 0;
  }

 private:
  static size_t write_data_func(void * buffer, size_t size, size_t nmemb, void *userp);
  static size_t headers_func(void * buffer, size_t size, size_t nmemb, void *userp);
  static int progress_func(void *  clientp, double dltotal, double dlnow, double ultotal, double ulnow);

  std::string interface_name;
  CURL * curl = 0;
};

size_t
CurlClient::write_data_func(void * buffer, size_t size, size_t nmemb, void * userp) {
  size_t s = size * nmemb;
  // Content-Type: multipart/x-mixed-replace; boundary=myboundary

  HTTPClientInterface * callback = (HTTPClientInterface *)(userp);
  assert(callback);
  return callback->handleChunk(s, (const char *)buffer) ? s : 0;
}

size_t
CurlClient::headers_func(void * buffer, size_t size, size_t nmemb, void *userp) {
  HTTPClientInterface * callback = (HTTPClientInterface *)(userp);

  int result = 0;
  if (buffer) {
    string s((const char*)buffer, size * nmemb);

    if (s.compare(0, 5, "HTTP/") == 0) {
      auto pos1 = s.find_first_of(' ');
      if (pos1 != string::npos) {
	auto pos2 = s.find_first_of(' ', pos1 + 1);
	if (pos2 != string::npos) {
	  auto s2 = s.substr(pos1, pos2 - pos1);
	  int code = atoi(s2.c_str());
	  callback->handleResultCode(code);
	}
      }
    } else {
      int pos1 = 0;
      for ( ; pos1 < s.size() && s[pos1] != ':'; pos1++) { }
      int pos2 = s[pos1] == ':' ? pos1 + 1 : pos1;
      for (; pos2 < s.size() && isspace(s[pos2]); pos2++) { }
      int pos3 = s.size();
      for (; pos3 > 0 && isspace(s[pos3 - 1]); pos3--) { }
      std::string key = s.substr(0, pos1);
      std::string value = s.substr(pos2, pos3 - pos2);

      if (key == "Location") {
	callback->handleRedirectUrl(value);
      }
      callback->handleHeader(key, value);
    }
  }

  return size * nmemb;
}

int
CurlClient::progress_func(void * clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
  HTTPClientInterface * callback = (HTTPClientInterface *)(clientp);
  assert(callback);
  return callback->onIdle(true) ? 0 : 1;
}

#ifndef __APPLE__
static pthread_mutex_t *lockarray;

#include <openssl/crypto.h>

static void lock_callback(int mode, int type, const char *file, int line) {
  (void)file;
  (void)line;
  if (mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&(lockarray[type]));
  } else {
    pthread_mutex_unlock(&(lockarray[type]));
  }
}

static unsigned long thread_id(void) {
  unsigned long ret;

#ifdef WIN32
  ret = (unsigned long)(pthread_self().p);
#else
  ret = (unsigned long)pthread_self();
#endif
  return(ret);
}

static void init_locks(void) {
  int i;

  lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
					      sizeof(pthread_mutex_t));
  for (i=0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_init(&(lockarray[i]),NULL);
  }

  CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  CRYPTO_set_locking_callback(lock_callback); // (void (*)())lock_callback);
}

static void kill_locks(void)
{
  int i;

  CRYPTO_set_locking_callback(NULL);
  for (i=0; i<CRYPTO_num_locks(); i++)
    pthread_mutex_destroy(&(lockarray[i]));

  OPENSSL_free(lockarray);
}
#endif

#if 0
#include <gcrypt.h>
#include <errno.h>
#include <gnutls/gnutls.h>

GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif

std::shared_ptr<HTTPClient>
CurlClientFactory::createClient(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::make_shared<CurlClient>("", _user_agent, _enable_cookies, _enable_keepalive);
}

void
CurlClientFactory::globalInit() {
  is_initialized = true;

#ifndef __APPLE__
#if 0
  gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
  gnutls_global_init();
#else
  init_locks();
#endif
#endif

  curl_global_init(CURL_GLOBAL_DEFAULT);

#if 0
  thread_setup();
#endif
#if 0
  gnutls_global_init();
#endif
}

void
CurlClientFactory::globalCleanup() {
  is_initialized = false;

  curl_global_cleanup();
#ifndef __APPLE__
  kill_locks();
#endif
}
<|endoftext|>


<commit_before>/**
 * \file GraphFrame.cpp
 * \brief Main Windows Class
 */

#include "GraphFrame.h"

BEGIN_EVENT_TABLE(GraphFrame,wxFrame)
    EVT_MENU(ID_NEWWINDOW, GraphFrame::NewStatusWindow)
    EVT_MENU(-1, GraphFrame::SelectDevice)
    EVT_CLOSE(GraphFrame::OnClose)
END_EVENT_TABLE()

GraphFrame::GraphFrame(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style) {
    /**
    *   Constructor for the Main frame.
    */
    deviceId = "Please select a device from the menu.";

    CreateGUIControls();
}

GraphFrame::~GraphFrame() {
    /**
    *   Destructor for the Main form.
    */
}

void GraphFrame::Update() {
    /**
     * Updates the GUI with new database information
     */
    wxMenuBar *menubar = new wxMenuBar;
    wxMenu *devices = new wxMenu;

    deviceIds = DB_getAllDevices();

    menubar->Append(devices, wxT("&Devices"));

    for(unsigned int i = 0; i < deviceIds.size(); i++) {
        devices->Append(10000+i, deviceIds[i]);
    }

    SetMenuBar(menubar);

	Plot speed = DB_getPlotData("gps","Spd",atoi(deviceId.c_str()));
	Plot altitude = DB_getPlotData("gps","Altitude",atoi(deviceId.c_str()));
	Plot climb = DB_getPlotData("gps","Rate",atoi(deviceId.c_str()));

	ReplaceGraph(&altitudeGraph, createGraphFromData(wxT("Time"),altitude.time,
	                                    wxT("Altitude"),altitude.data));

	ReplaceGraph(&speedGraph, createGraphFromData(wxT("Time"),speed.time,
	                                    wxT("Speed"),speed.data));

	ReplaceGraph(&climbGraph, createGraphFromData(wxT("Time"),climb.time,
	                                    wxT("Climb"),climb.data));

    mainSizer->Layout();
}

void GraphFrame::ReplaceGraph(mpWindow** old_graph, mpWindow* new_graph) {
	mainSizer->Replace(*old_graph, new_graph);
	delete *old_graph;
	*old_graph = new_graph;
}

void GraphFrame::CreateGUIControls() {
   /**
    *   Creates all of the GUI controls on the main form.
    */

    // Set window properties and title bar
    SetTitle(wxT("Device Status"));
    SetIcon(wxNullIcon);

    mainPanel = new wxPanel(this, wxID_ANY);
    mainSizer = new wxBoxSizer(wxVERTICAL);
    mainPanel->SetSizer(mainSizer);

	altitudeGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Altitude"),vector<double>());
    mainSizer->Add(altitudeGraph, 1, wxEXPAND | wxALL);

	speedGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Speed"),vector<double>());
    mainSizer->Add(speedGraph, 1, wxEXPAND | wxALL);

	climbGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Climb"),vector<double>());
    mainSizer->Add(climbGraph, 1, wxEXPAND | wxALL);

    Update();
}

mpWindow* GraphFrame::createGraphFromData(wxString x_label, vector<double> x_data,
                                  wxString y_label, vector<double> y_data) {
    mpWindow* graph;
	wxFont graphFont(11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);

    graph = new mpWindow( mainPanel, -1, wxPoint(0,0), wxSize(500,500), wxSUNKEN_BORDER );

	// Create a mpFXYVector layer
	mpFXYVector* vectorLayer = new mpFXYVector(_(""));
	vectorLayer->SetData(x_data, y_data);
	vectorLayer->SetContinuity(true);
	wxPen vectorpen(*wxBLUE, 2, wxSOLID);
	vectorLayer->SetPen(vectorpen);
	vectorLayer->SetDrawOutsideMargins(false);

    mpScaleX* xaxis = new mpScaleX(x_label, mpALIGN_BOTTOM, true, mpX_NORMAL);
    mpScaleY* yaxis = new mpScaleY(y_label, mpALIGN_LEFT, true);
    xaxis->SetFont(graphFont);
    yaxis->SetFont(graphFont);
    xaxis->SetDrawOutsideMargins(false);
    yaxis->SetDrawOutsideMargins(false);
	xaxis->SetLabelFormat(wxT("%.1f"));
	yaxis->SetLabelFormat(wxT("%.1f"));
    graph->SetMargins(30, 30, 50, 100);
    graph->AddLayer(     xaxis );
    graph->AddLayer(     yaxis );
	graph->AddLayer(     vectorLayer );
    graph->AddLayer(     new mpText(y_label + wxT(" vs ") + x_label, 60, 5) );
    mpInfoLegend* leg;
    graph->AddLayer( leg = new mpInfoLegend(wxRect(200,20,40,40), wxTRANSPARENT_BRUSH)); //&hatch2));
    leg->SetVisible(true);

    graph->Fit();
    return graph;
}

void GraphFrame::OnClose(wxCloseEvent& event) {
    /**
    *   Event handler for the form closing event
    *   Exit the ChaosConnect Program
    */
    Destroy();
}

void GraphFrame::SelectDevice( wxCommandEvent& event ) {
    /**
     * Selects a device from the menu
     *
     * This is a catchall menu event handler becasue I couldn't think
     * of a better way to do this because the menu is dynamic
     */

    int id = event.GetId();

    if(id > 10000) {
        /// We're selecting a device
        deviceId = deviceIds[id - 10000];
    }

    Update();
}

void GraphFrame::NewStatusWindow( wxCommandEvent& event ) {
    /**
     * Launches a new status window
     */

    GraphFrame* frame = new GraphFrame(NULL);
    frame->Show();
}

<commit_msg>- changed graphFrame title<commit_after>/**
 * \file GraphFrame.cpp
 * \brief Main Windows Class
 */

#include "GraphFrame.h"

BEGIN_EVENT_TABLE(GraphFrame,wxFrame)
    EVT_MENU(ID_NEWWINDOW, GraphFrame::NewStatusWindow)
    EVT_MENU(-1, GraphFrame::SelectDevice)
    EVT_CLOSE(GraphFrame::OnClose)
END_EVENT_TABLE()

GraphFrame::GraphFrame(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style) {
    /**
    *   Constructor for the Main frame.
    */
    deviceId = "Please select a device from the menu.";

    CreateGUIControls();
}

GraphFrame::~GraphFrame() {
    /**
    *   Destructor for the Main form.
    */
}

void GraphFrame::Update() {
    /**
     * Updates the GUI with new database information
     */
    wxMenuBar *menubar = new wxMenuBar;
    wxMenu *devices = new wxMenu;

    deviceIds = DB_getAllDevices();

    menubar->Append(devices, wxT("&Devices"));

    for(unsigned int i = 0; i < deviceIds.size(); i++) {
        devices->Append(10000+i, deviceIds[i]);
    }

    SetMenuBar(menubar);

	Plot speed = DB_getPlotData("gps","Spd",atoi(deviceId.c_str()));
	Plot altitude = DB_getPlotData("gps","Altitude",atoi(deviceId.c_str()));
	Plot climb = DB_getPlotData("gps","Rate",atoi(deviceId.c_str()));

	ReplaceGraph(&altitudeGraph, createGraphFromData(wxT("Time"),altitude.time,
	                                    wxT("Altitude"),altitude.data));

	ReplaceGraph(&speedGraph, createGraphFromData(wxT("Time"),speed.time,
	                                    wxT("Speed"),speed.data));

	ReplaceGraph(&climbGraph, createGraphFromData(wxT("Time"),climb.time,
	                                    wxT("Climb"),climb.data));

    mainSizer->Layout();
}

void GraphFrame::ReplaceGraph(mpWindow** old_graph, mpWindow* new_graph) {
	mainSizer->Replace(*old_graph, new_graph);
	delete *old_graph;
	*old_graph = new_graph;
}

void GraphFrame::CreateGUIControls() {
   /**
    *   Creates all of the GUI controls on the main form.
    */

    // Set window properties and title bar
    SetTitle(wxT("Device Graphs"));
    SetIcon(wxNullIcon);

    mainPanel = new wxPanel(this, wxID_ANY);
    mainSizer = new wxBoxSizer(wxVERTICAL);
    mainPanel->SetSizer(mainSizer);

	altitudeGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Altitude"),vector<double>());
    mainSizer->Add(altitudeGraph, 1, wxEXPAND | wxALL);

	speedGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Speed"),vector<double>());
    mainSizer->Add(speedGraph, 1, wxEXPAND | wxALL);

	climbGraph = createGraphFromData(wxT("Time"),vector<double>(),
	                                    wxT("Climb"),vector<double>());
    mainSizer->Add(climbGraph, 1, wxEXPAND | wxALL);

    Update();
}

mpWindow* GraphFrame::createGraphFromData(wxString x_label, vector<double> x_data,
                                  wxString y_label, vector<double> y_data) {
    mpWindow* graph;
	wxFont graphFont(11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);

    graph = new mpWindow( mainPanel, -1, wxPoint(0,0), wxSize(500,500), wxSUNKEN_BORDER );

	// Create a mpFXYVector layer
	mpFXYVector* vectorLayer = new mpFXYVector(_(""));
	vectorLayer->SetData(x_data, y_data);
	vectorLayer->SetContinuity(true);
	wxPen vectorpen(*wxBLUE, 2, wxSOLID);
	vectorLayer->SetPen(vectorpen);
	vectorLayer->SetDrawOutsideMargins(false);

    mpScaleX* xaxis = new mpScaleX(x_label, mpALIGN_BOTTOM, true, mpX_NORMAL);
    mpScaleY* yaxis = new mpScaleY(y_label, mpALIGN_LEFT, true);
    xaxis->SetFont(graphFont);
    yaxis->SetFont(graphFont);
    xaxis->SetDrawOutsideMargins(false);
    yaxis->SetDrawOutsideMargins(false);
	xaxis->SetLabelFormat(wxT("%.1f"));
	yaxis->SetLabelFormat(wxT("%.1f"));
    graph->SetMargins(30, 30, 50, 100);
    graph->AddLayer(     xaxis );
    graph->AddLayer(     yaxis );
	graph->AddLayer(     vectorLayer );
    graph->AddLayer(     new mpText(y_label + wxT(" vs ") + x_label, 60, 5) );
    mpInfoLegend* leg;
    graph->AddLayer( leg = new mpInfoLegend(wxRect(200,20,40,40), wxTRANSPARENT_BRUSH)); //&hatch2));
    leg->SetVisible(true);

    graph->Fit();
    return graph;
}

void GraphFrame::OnClose(wxCloseEvent& event) {
    /**
    *   Event handler for the form closing event
    *   Exit the ChaosConnect Program
    */
    Destroy();
}

void GraphFrame::SelectDevice( wxCommandEvent& event ) {
    /**
     * Selects a device from the menu
     *
     * This is a catchall menu event handler becasue I couldn't think
     * of a better way to do this because the menu is dynamic
     */

    int id = event.GetId();

    if(id > 10000) {
        /// We're selecting a device
        deviceId = deviceIds[id - 10000];
    }

    Update();
}

void GraphFrame::NewStatusWindow( wxCommandEvent& event ) {
    /**
     * Launches a new status window
     */

    GraphFrame* frame = new GraphFrame(NULL);
    frame->Show();
}

<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
*                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_ENGINE_BOXROI_INL
#define SOFA_COMPONENT_ENGINE_BOXROI_INL

#if !defined(__GNUC__) || (__GNUC__ > 3 || (_GNUC__ == 3 && __GNUC_MINOR__ > 3))
#pragma once
#endif

#include <sofa/component/engine/BoxROI.h>
#include <sofa/helper/gl/template.h>
#include <sofa/helper/gl/BasicShapes.h>

namespace sofa
{

namespace component
{

namespace engine
{

using namespace sofa::helper;
using namespace sofa::defaulttype;
using namespace core::objectmodel;

template <class DataTypes>
BoxROI<DataTypes>::BoxROI()
    : x0(new VecCoord)
    , boxes( initData( &boxes, "box", "DOFs in the box defined by xmin,ymin,zmin, xmax,ymax,zmax are fixed") )
    , f_X0( new XDataPtr<DataTypes>(&x0, "rest position coordinates of the degrees of freedom") )
    , f_indices( initData(&f_indices,"indices","Indices of the fixed points") )
    , _drawSize( initData(&_drawSize,0.0,"drawSize","0 -> point based rendering, >0 -> radius of spheres") )
{
    boxes.beginEdit()->push_back(Vec6(0,0,0,1,1,1));
    boxes.endEdit();

    addInput(f_X0);
    this->addField(f_X0,"rest_position");
    f_X0->init();

    addOutput(&f_indices);
    f_indices.beginEdit()->push_back(0);
    f_indices.endEdit();
}

template <class DataTypes>
void BoxROI<DataTypes>::init()
{
    if (x0->empty())
    {
        BaseData* parent = mstate->findField("rest_position");
        f_X0->setParentValue(parent);
        parent->addOutput(f_X0);
        f_X0->setReadOnly(true);
        *x0 = f_X0->getValue();
    }
}

template <class DataTypes>
void BoxROI<DataTypes>::update()
{
    dirty = false;
    helper::vector<Vec6>& vb = *(boxes.beginEdit());
    std::cout << "update()" << std::endl;
    for (unsigned int bi=0; bi<vb.size(); ++bi)
    {
        if (vb[bi][0] > vb[bi][3]) std::swap(vb[bi][0],vb[bi][3]);
        if (vb[bi][1] > vb[bi][4]) std::swap(vb[bi][1],vb[bi][4]);
        if (vb[bi][2] > vb[bi][5]) std::swap(vb[bi][2],vb[bi][5]);
    }

    SetIndex& indices = *(f_indices.beginEdit());

    indices.clear();
    for( unsigned i=0; i<x0->size(); ++i )
    {
        Real x=0.0,y=0.0,z=0.0;
        DataTypes::get(x,y,z,(*x0)[i]);
        for (unsigned int bi=0; bi<vb.size(); ++bi)
        {
            const Vec6& b=vb[bi];
            if( x >= b[0] && x <= b[3] && y >= b[1] && y <= b[4] && z >= b[2] && z <= b[5] )
            {
                indices.push_back(i);
                break;
            }
        }
    }

    f_indices.endEdit();
    boxes.endEdit();
}

template <class DataTypes>
BoxROI<DataTypes>::~BoxROI()
{}

template <class DataTypes>
void BoxROI<DataTypes>::draw()
{
    if (!this->getContext()->getShowBehaviorModels())
        return;
    //const VecCoord& x = *x0;

    if( _drawSize.getValue() == 0) // old classical drawing by points
    {
        //glColor4f (1,0.5,0.5,1);
        //glDisable (GL_LIGHTING);
        //glPointSize(10);

        //glBegin (GL_POINTS);
        //const SetIndex& indices = f_indices.getValue();
        //for (typename SetIndex::const_iterator it = indices.begin();
        //    it != indices.end();
        //    ++it)
        //{
        //    gl::glVertexT(x[*it]);
        //}
        //glEnd();

        ///draw the constraint boxes
        glBegin(GL_LINES);
        const helper::vector<Vec6>& vb=boxes.getValue();
        for (unsigned int bi=0; bi<vb.size(); ++bi)
        {
            const Vec6& b=vb[bi];
            //const Vec6& b=box.getValue();
            const Real& Xmin=b[0];
            const Real& Xmax=b[3];
            const Real& Ymin=b[1];
            const Real& Ymax=b[4];
            const Real& Zmin=b[2];
            const Real& Zmax=b[5];
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymax,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmax,Ymax,Zmax);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmax,Ymax,Zmax);
        }
        glEnd();
    }
    //else // new drawing by spheres
    //{
    //    glColor4f (1.0f,0.35f,0.35f,1.0f);
    //    glEnable(GL_LIGHTING);
    //    glEnable(GL_COLOR_MATERIAL);
    //    const SetIndex& indices = f_indices.getValue();
    //    for (typename SetIndex::const_iterator it = indices.begin();
    //        it != indices.end();
    //        ++it)
    //    {
    //        helper::gl::drawSphere( x[*it], (float)_drawSize.getValue() );
    //    }
    //    glDisable(GL_LIGHTING);
    //    glDisable(GL_COLOR_MATERIAL);
    //}
}

template <class DataTypes>
bool BoxROI<DataTypes>::addBBox(double* minBBox, double* maxBBox)
{
    const helper::vector<Vec6>& vb=boxes.getValue();
    for (unsigned int bi=0; bi<vb.size(); ++bi)
    {
        const Vec6& b=vb[bi];
        //const Vec6& b=box.getValue();
        if (b[0] < minBBox[0]) minBBox[0] = b[0];
        if (b[1] < minBBox[1]) minBBox[1] = b[1];
        if (b[2] < minBBox[2]) minBBox[2] = b[2];
        if (b[3] > maxBBox[0]) maxBBox[0] = b[3];
        if (b[4] > maxBBox[1]) maxBBox[1] = b[4];
        if (b[5] > maxBBox[2]) maxBBox[2] = b[5];
    }
    return true;
}

} // namespace engine

} // namespace component

} // namespace sofa

#endif
<commit_msg>r4326/sofa-dev : FIX: remove cout<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
*                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_ENGINE_BOXROI_INL
#define SOFA_COMPONENT_ENGINE_BOXROI_INL

#if !defined(__GNUC__) || (__GNUC__ > 3 || (_GNUC__ == 3 && __GNUC_MINOR__ > 3))
#pragma once
#endif

#include <sofa/component/engine/BoxROI.h>
#include <sofa/helper/gl/template.h>
#include <sofa/helper/gl/BasicShapes.h>

namespace sofa
{

namespace component
{

namespace engine
{

using namespace sofa::helper;
using namespace sofa::defaulttype;
using namespace core::objectmodel;

template <class DataTypes>
BoxROI<DataTypes>::BoxROI()
    : x0(new VecCoord)
    , boxes( initData( &boxes, "box", "DOFs in the box defined by xmin,ymin,zmin, xmax,ymax,zmax are fixed") )
    , f_X0( new XDataPtr<DataTypes>(&x0, "rest position coordinates of the degrees of freedom") )
    , f_indices( initData(&f_indices,"indices","Indices of the fixed points") )
    , _drawSize( initData(&_drawSize,0.0,"drawSize","0 -> point based rendering, >0 -> radius of spheres") )
{
    boxes.beginEdit()->push_back(Vec6(0,0,0,1,1,1));
    boxes.endEdit();

    addInput(f_X0);
    this->addField(f_X0,"rest_position");
    f_X0->init();

    addOutput(&f_indices);
    f_indices.beginEdit()->push_back(0);
    f_indices.endEdit();
}

template <class DataTypes>
void BoxROI<DataTypes>::init()
{
    if (x0->empty())
    {
        BaseData* parent = mstate->findField("rest_position");
        f_X0->setParentValue(parent);
        parent->addOutput(f_X0);
        f_X0->setReadOnly(true);
        *x0 = f_X0->getValue();
    }
}

template <class DataTypes>
void BoxROI<DataTypes>::update()
{
    dirty = false;
    helper::vector<Vec6>& vb = *(boxes.beginEdit());

    for (unsigned int bi=0; bi<vb.size(); ++bi)
    {
        if (vb[bi][0] > vb[bi][3]) std::swap(vb[bi][0],vb[bi][3]);
        if (vb[bi][1] > vb[bi][4]) std::swap(vb[bi][1],vb[bi][4]);
        if (vb[bi][2] > vb[bi][5]) std::swap(vb[bi][2],vb[bi][5]);
    }

    SetIndex& indices = *(f_indices.beginEdit());

    indices.clear();
    for( unsigned i=0; i<x0->size(); ++i )
    {
        Real x=0.0,y=0.0,z=0.0;
        DataTypes::get(x,y,z,(*x0)[i]);
        for (unsigned int bi=0; bi<vb.size(); ++bi)
        {
            const Vec6& b=vb[bi];
            if( x >= b[0] && x <= b[3] && y >= b[1] && y <= b[4] && z >= b[2] && z <= b[5] )
            {
                indices.push_back(i);
                break;
            }
        }
    }

    f_indices.endEdit();
    boxes.endEdit();
}

template <class DataTypes>
BoxROI<DataTypes>::~BoxROI()
{}

template <class DataTypes>
void BoxROI<DataTypes>::draw()
{
    if (!this->getContext()->getShowBehaviorModels())
        return;
    //const VecCoord& x = *x0;

    if( _drawSize.getValue() == 0) // old classical drawing by points
    {
        //glColor4f (1,0.5,0.5,1);
        //glDisable (GL_LIGHTING);
        //glPointSize(10);

        //glBegin (GL_POINTS);
        //const SetIndex& indices = f_indices.getValue();
        //for (typename SetIndex::const_iterator it = indices.begin();
        //    it != indices.end();
        //    ++it)
        //{
        //    gl::glVertexT(x[*it]);
        //}
        //glEnd();

        ///draw the constraint boxes
        glBegin(GL_LINES);
        const helper::vector<Vec6>& vb=boxes.getValue();
        for (unsigned int bi=0; bi<vb.size(); ++bi)
        {
            const Vec6& b=vb[bi];
            //const Vec6& b=box.getValue();
            const Real& Xmin=b[0];
            const Real& Xmax=b[3];
            const Real& Ymin=b[1];
            const Real& Ymax=b[4];
            const Real& Zmin=b[2];
            const Real& Zmax=b[5];
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmin,Ymin,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmin);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmin,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymax,Zmax);
            glVertex3d(Xmax,Ymin,Zmax);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmin,Ymax,Zmax);
            glVertex3d(Xmax,Ymax,Zmax);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmax,Ymin,Zmin);
            glVertex3d(Xmax,Ymax,Zmin);
            glVertex3d(Xmax,Ymax,Zmax);
        }
        glEnd();
    }
    //else // new drawing by spheres
    //{
    //    glColor4f (1.0f,0.35f,0.35f,1.0f);
    //    glEnable(GL_LIGHTING);
    //    glEnable(GL_COLOR_MATERIAL);
    //    const SetIndex& indices = f_indices.getValue();
    //    for (typename SetIndex::const_iterator it = indices.begin();
    //        it != indices.end();
    //        ++it)
    //    {
    //        helper::gl::drawSphere( x[*it], (float)_drawSize.getValue() );
    //    }
    //    glDisable(GL_LIGHTING);
    //    glDisable(GL_COLOR_MATERIAL);
    //}
}

template <class DataTypes>
bool BoxROI<DataTypes>::addBBox(double* minBBox, double* maxBBox)
{
    const helper::vector<Vec6>& vb=boxes.getValue();
    for (unsigned int bi=0; bi<vb.size(); ++bi)
    {
        const Vec6& b=vb[bi];
        //const Vec6& b=box.getValue();
        if (b[0] < minBBox[0]) minBBox[0] = b[0];
        if (b[1] < minBBox[1]) minBBox[1] = b[1];
        if (b[2] < minBBox[2]) minBBox[2] = b[2];
        if (b[3] > maxBBox[0]) maxBBox[0] = b[3];
        if (b[4] > maxBBox[1]) maxBBox[1] = b[4];
        if (b[5] > maxBBox[2]) maxBBox[2] = b[5];
    }
    return true;
}

} // namespace engine

} // namespace component

} // namespace sofa

#endif
<|endoftext|>