<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mthemedaemonprotocol.h"
#include <QHash>
#include <QtEndian>

using namespace M::MThemeDaemonProtocol;

const QString M::MThemeDaemonProtocol::ServerAddress = "m.mthemedaemon";
static const int SOCKET_DELAY_MS = 15000;

PacketData::~PacketData()
{}

PixmapIdentifier::~PixmapIdentifier()
{}

Number::~Number()
{}

String::~String()
{}

StringBool::~StringBool()
{}

PixmapHandle::~PixmapHandle()
{}

ClientList::~ClientList()
{}

ThemeChangeInfo::~ThemeChangeInfo()
{}

MostUsedPixmaps::~MostUsedPixmaps()
{}

RequestedPixmap::~RequestedPixmap()
{}

Packet::Packet(PacketType type, quint64 seq, PacketData *data)
:
    m_seq  (seq),
    m_data (data),
    m_type (type)
{}

Packet::~Packet()
{}

void Packet::setData(PacketData *data)
{
    m_data = QSharedPointer<PacketData>(data);
}

QDataStream &operator<<(QDataStream &stream, const Packet &packet)
{
    Q_ASSERT(packet.type() != Packet::Unknown);

    QByteArray serializedPackageData;
    QDataStream serializedPackageDataStream(&serializedPackageData, QIODevice::WriteOnly);
    writePacketData(serializedPackageDataStream, packet);
    stream.writeBytes(serializedPackageData.constData(), serializedPackageData.length());

    return stream;
}

void writePacketData(QDataStream &stream, const M::MThemeDaemonProtocol::Packet &packet)
{
    stream << quint32(packet.type());
    stream << packet.sequenceNumber();

    switch (packet.type()) {
    // NULL as data
    case Packet::RequestClearPixmapDirectoriesPacket:
    case Packet::QueryThemeDaemonStatusPacket:
        break;

    // string as data
    case Packet::ErrorPacket:
    case Packet::RequestRegistrationPacket: {
        stream << static_cast<const String *>(packet.data())->string;
    } break;

    // two string lists as data
    case Packet::ThemeChangedPacket: {
        const ThemeChangeInfo* info = static_cast<const ThemeChangeInfo*>(packet.data());
        stream << info->themeInheritance << info->themeLibraryNames;
    } break;

    case Packet::ProtocolVersionPacket:
    case Packet::ThemeChangeAppliedPacket: {
        stream << static_cast<const Number *>(packet.data())->value;
    } break;

    // stringbool as data
    case Packet::RequestNewPixmapDirectoryPacket: {
        const StringBool *sb = static_cast<const StringBool *>(packet.data());
        stream << sb->string << sb->b;
    } break;

    // pixmap identifier as data
    case Packet::PixmapUsedPacket:
    case Packet::ReleasePixmapPacket: {
        const PixmapIdentifier *id = static_cast<const PixmapIdentifier *>(packet.data());
        stream << *id;
    } break;

    case Packet::RequestPixmapPacket: {
        const RequestedPixmap *pixmap = static_cast<const RequestedPixmap *>(packet.data());
        stream << pixmap->priority;
        stream << pixmap->id;
    } break;

    // pixmap handle as data
    case Packet::PixmapUpdatedPacket: {
        const PixmapHandle *h = static_cast<const PixmapHandle *>(packet.data());
        stream << *h;
    } break;

    case Packet::MostUsedPixmapsPacket: {
        const MostUsedPixmaps *mostUsedPixmaps = static_cast<const MostUsedPixmaps *>(packet.data());

        stream << mostUsedPixmaps->addedHandles;
        stream << mostUsedPixmaps->removedIdentifiers;
    } break;

    // client list as data
    case Packet::ThemeDaemonStatusPacket: {
        const ClientList *cl = static_cast<const ClientList *>(packet.data());
        quint32 clientCount = cl->clients.count();
        stream << clientCount;
        for (uint i = 0; i < clientCount; ++i)
        {
            const ClientInfo &info = cl->clients.at(i);
            stream << info.name;
            quint32 pixmapCount = info.pixmaps.count();
            stream << pixmapCount;
            for (quint32 j = 0; j < pixmapCount; ++j) {
                stream << info.pixmaps.at(j);
            }
            quint32 requestedPixmapCount = info.requestedPixmaps.count();
            stream << requestedPixmapCount;
            for (quint32 j = 0; j < requestedPixmapCount; ++j) {
                stream << info.requestedPixmaps.at(j);
            }
            quint32 releasedPixmapCount = info.releasedPixmaps.count();
            stream << releasedPixmapCount;
            for (quint32 j = 0; j < releasedPixmapCount; ++j) {
                stream << info.releasedPixmaps.at(j);
            }
        }
    } break;

    default:
        // print out warning
        break;
    }
}

static bool waitForAvailableBytes(QDataStream &stream, quint32 count)
{
    while (stream.device()->bytesAvailable() < count) {
        if (!stream.device()->waitForReadyRead(SOCKET_DELAY_MS)) {
            return false;
        }
    }
    return true;
}

QDataStream &operator>>(QDataStream &stream, Packet &packet)
{
    if (!waitForAvailableBytes(stream, sizeof(quint32))) {
        return stream;
    }
    quint32 length;
    stream >> length;
    if (!waitForAvailableBytes(stream, length)) {
        return stream;
    }

    char *raw = new char[length];
    stream.readRawData(raw, length);
    QByteArray serializedPackageData = QByteArray::fromRawData(raw, length);
    QDataStream serializedPackageDataStream(serializedPackageData);
    readPacketData(serializedPackageDataStream, packet);

    delete[] raw;

    return stream;
}

void readPacketData(QDataStream &stream, M::MThemeDaemonProtocol::Packet &packet)
{
    quint32 type = 0;
    quint64 seq  = 0;

    stream >> type >> seq;

    packet.setType(Packet::PacketType(type));
    packet.setSequenceNumber(seq);

    switch (packet.type()) {

    // NULL as data
    case Packet::RequestClearPixmapDirectoriesPacket:
    case Packet::QueryThemeDaemonStatusPacket:
        break;

    // string as data
    case Packet::ErrorPacket:
    case Packet::RequestRegistrationPacket: {
        QString string;
        stream >> string;
        packet.setData(new String(string));
    } break;

    // two string lists as data
    case Packet::ThemeChangedPacket: {
        QStringList themeInheritance, themeLibraryNames;
        stream >> themeInheritance >> themeLibraryNames;
        packet.setData(new ThemeChangeInfo(themeInheritance, themeLibraryNames));
    } break;

    case Packet::ProtocolVersionPacket:
    case Packet::ThemeChangeAppliedPacket: {
        qint32  priority;
        stream >> priority;
        packet.setData(new Number(priority));
    } break;

    // stringbool as data
    case Packet::RequestNewPixmapDirectoryPacket: {
        QString string;
        stream >> string;
        bool b = false;
        stream >> b;
        packet.setData(new StringBool(string, b));
    } break;

    // pixmap identifier as data
    case Packet::PixmapUsedPacket:
    case Packet::ReleasePixmapPacket: {
        PixmapIdentifier id;
        stream >> id;
        packet.setData(new PixmapIdentifier(id));
    } break;

    case Packet::RequestPixmapPacket: {
        qint32 priority;
        stream >> priority;
        PixmapIdentifier id;
        stream >> id;
        packet.setData(new RequestedPixmap(id, priority));
    } break;

    // pixmap handle as data
    case Packet::PixmapUpdatedPacket: {
        PixmapHandle h;
        stream >> h;
        packet.setData(new PixmapHandle(h));
    } break;

    case Packet::MostUsedPixmapsPacket: {
        QList<PixmapHandle> addedHandles;
        stream >> addedHandles;

        QList<PixmapIdentifier> removedIdentifiers;
        stream >> removedIdentifiers;

        packet.setData(new MostUsedPixmaps(addedHandles, removedIdentifiers));
    } break;

    // client list as data
    case Packet::ThemeDaemonStatusPacket: {
        QList<ClientInfo> clients;
        quint32 clientCount = 0;
        stream >> clientCount;
        while (clientCount) {
            ClientInfo info;
            stream >> info.name;
            quint32 pixmapCount = 0;
            stream >> pixmapCount;
            while (pixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.pixmaps.append(id);
                --pixmapCount;
            }
            quint32 requestedPixmapCount = 0;
            stream >> requestedPixmapCount;
            while (requestedPixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.requestedPixmaps.append(id);
                --requestedPixmapCount;
            }
            quint32 releasedPixmapCount = 0;
            stream >> releasedPixmapCount;
            while (releasedPixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.releasedPixmaps.append(id);
                --releasedPixmapCount;
            }

            clients.append(info);
            --clientCount;
        }
        packet.setData(new ClientList(clients));
    } break;

    default:
        // print out warning
        break;
    }
}

QDataStream &operator<<(QDataStream &stream, const M::MThemeDaemonProtocol::PixmapHandle &handle)
{
    stream << handle.identifier;
    stream << quint64(quintptr(handle.pixmapHandle.xHandle));
    stream << quint64(quintptr(handle.pixmapHandle.eglHandle));
    stream << handle.pixmapHandle.shmHandle;
    stream << handle.pixmapHandle.size;
    stream << (quint64)handle.pixmapHandle.format;
    stream << handle.pixmapHandle.numBytes;
    stream << (bool)handle.pixmapHandle.directMap;
    return stream;
}

QDataStream &operator>>(QDataStream &stream, M::MThemeDaemonProtocol::PixmapHandle &handle)
{
    stream >> handle.identifier;

    quint64 h;
    stream >> h;
    handle.pixmapHandle.xHandle = (Qt::HANDLE) quintptr(h);
    stream >> h;
    handle.pixmapHandle.eglHandle = (Qt::HANDLE) quintptr(h);
    stream >> handle.pixmapHandle.shmHandle;
    stream >> handle.pixmapHandle.size;
    stream >> h;
    handle.pixmapHandle.format = QImage::Format(h);
    stream >> handle.pixmapHandle.numBytes;
    stream >> handle.pixmapHandle.directMap;
    return stream;
}

QDataStream &operator<<(QDataStream &stream, const M::MThemeDaemonProtocol::PixmapIdentifier &id)
{
    stream << id.imageId;
    stream << id.size;
    return stream;
}

QDataStream &operator>>(QDataStream &stream, M::MThemeDaemonProtocol::PixmapIdentifier &id)
{
    QString imageId;
    stream >> imageId;
    QSize size;
    stream >> size;
    id.imageId = imageId;
    id.size = size;
    return stream;
}

uint M::MThemeDaemonProtocol::qHash(const PixmapIdentifier &id)
{
    using ::qHash;

    const uint idHash     = qHash(id.imageId);
    const uint widthHash  = qHash(id.size.width());
    const uint heightHash = qHash(id.size.height());

    // Twiddle the bits a little, taking a cue from Qt's own qHash() overloads
    return idHash ^ (widthHash << 8) ^ (widthHash >> 24) ^ (heightHash << 24) ^ (heightHash >> 8);
}
<commit_msg>Revert "Changes: fix mismatched free() / delete / delete []"<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mthemedaemonprotocol.h"
#include <QHash>
#include <QtEndian>

using namespace M::MThemeDaemonProtocol;

const QString M::MThemeDaemonProtocol::ServerAddress = "m.mthemedaemon";
static const int SOCKET_DELAY_MS = 15000;

PacketData::~PacketData()
{}

PixmapIdentifier::~PixmapIdentifier()
{}

Number::~Number()
{}

String::~String()
{}

StringBool::~StringBool()
{}

PixmapHandle::~PixmapHandle()
{}

ClientList::~ClientList()
{}

ThemeChangeInfo::~ThemeChangeInfo()
{}

MostUsedPixmaps::~MostUsedPixmaps()
{}

RequestedPixmap::~RequestedPixmap()
{}

Packet::Packet(PacketType type, quint64 seq, PacketData *data)
:
    m_seq  (seq),
    m_data (data),
    m_type (type)
{}

Packet::~Packet()
{}

void Packet::setData(PacketData *data)
{
    m_data = QSharedPointer<PacketData>(data);
}

QDataStream &operator<<(QDataStream &stream, const Packet &packet)
{
    Q_ASSERT(packet.type() != Packet::Unknown);

    QByteArray serializedPackageData;
    QDataStream serializedPackageDataStream(&serializedPackageData, QIODevice::WriteOnly);
    writePacketData(serializedPackageDataStream, packet);
    stream.writeBytes(serializedPackageData.constData(), serializedPackageData.length());

    return stream;
}

void writePacketData(QDataStream &stream, const M::MThemeDaemonProtocol::Packet &packet)
{
    stream << quint32(packet.type());
    stream << packet.sequenceNumber();

    switch (packet.type()) {
    // NULL as data
    case Packet::RequestClearPixmapDirectoriesPacket:
    case Packet::QueryThemeDaemonStatusPacket:
        break;

    // string as data
    case Packet::ErrorPacket:
    case Packet::RequestRegistrationPacket: {
        stream << static_cast<const String *>(packet.data())->string;
    } break;

    // two string lists as data
    case Packet::ThemeChangedPacket: {
        const ThemeChangeInfo* info = static_cast<const ThemeChangeInfo*>(packet.data());
        stream << info->themeInheritance << info->themeLibraryNames;
    } break;

    case Packet::ProtocolVersionPacket:
    case Packet::ThemeChangeAppliedPacket: {
        stream << static_cast<const Number *>(packet.data())->value;
    } break;

    // stringbool as data
    case Packet::RequestNewPixmapDirectoryPacket: {
        const StringBool *sb = static_cast<const StringBool *>(packet.data());
        stream << sb->string << sb->b;
    } break;

    // pixmap identifier as data
    case Packet::PixmapUsedPacket:
    case Packet::ReleasePixmapPacket: {
        const PixmapIdentifier *id = static_cast<const PixmapIdentifier *>(packet.data());
        stream << *id;
    } break;

    case Packet::RequestPixmapPacket: {
        const RequestedPixmap *pixmap = static_cast<const RequestedPixmap *>(packet.data());
        stream << pixmap->priority;
        stream << pixmap->id;
    } break;

    // pixmap handle as data
    case Packet::PixmapUpdatedPacket: {
        const PixmapHandle *h = static_cast<const PixmapHandle *>(packet.data());
        stream << *h;
    } break;

    case Packet::MostUsedPixmapsPacket: {
        const MostUsedPixmaps *mostUsedPixmaps = static_cast<const MostUsedPixmaps *>(packet.data());

        stream << mostUsedPixmaps->addedHandles;
        stream << mostUsedPixmaps->removedIdentifiers;
    } break;

    // client list as data
    case Packet::ThemeDaemonStatusPacket: {
        const ClientList *cl = static_cast<const ClientList *>(packet.data());
        quint32 clientCount = cl->clients.count();
        stream << clientCount;
        for (uint i = 0; i < clientCount; ++i)
        {
            const ClientInfo &info = cl->clients.at(i);
            stream << info.name;
            quint32 pixmapCount = info.pixmaps.count();
            stream << pixmapCount;
            for (quint32 j = 0; j < pixmapCount; ++j) {
                stream << info.pixmaps.at(j);
            }
            quint32 requestedPixmapCount = info.requestedPixmaps.count();
            stream << requestedPixmapCount;
            for (quint32 j = 0; j < requestedPixmapCount; ++j) {
                stream << info.requestedPixmaps.at(j);
            }
            quint32 releasedPixmapCount = info.releasedPixmaps.count();
            stream << releasedPixmapCount;
            for (quint32 j = 0; j < releasedPixmapCount; ++j) {
                stream << info.releasedPixmaps.at(j);
            }
        }
    } break;

    default:
        // print out warning
        break;
    }
}

static bool waitForAvailableBytes(QDataStream &stream, quint32 count)
{
    while (stream.device()->bytesAvailable() < count) {
        if (!stream.device()->waitForReadyRead(SOCKET_DELAY_MS)) {
            return false;
        }
    }
    return true;
}

QDataStream &operator>>(QDataStream &stream, Packet &packet)
{
    if (!waitForAvailableBytes(stream, sizeof(quint32))) {
        return stream;
    }
    quint32 length;
    stream >> length;
    if (!waitForAvailableBytes(stream, length)) {
        return stream;
    }

    char *raw = new char[length];
    stream.readRawData(raw, length);
    QByteArray serializedPackageData = QByteArray::fromRawData(raw, length);
    QDataStream serializedPackageDataStream(serializedPackageData);
    readPacketData(serializedPackageDataStream, packet);

    delete raw;

    return stream;
}

void readPacketData(QDataStream &stream, M::MThemeDaemonProtocol::Packet &packet)
{
    quint32 type = 0;
    quint64 seq  = 0;

    stream >> type >> seq;

    packet.setType(Packet::PacketType(type));
    packet.setSequenceNumber(seq);

    switch (packet.type()) {

    // NULL as data
    case Packet::RequestClearPixmapDirectoriesPacket:
    case Packet::QueryThemeDaemonStatusPacket:
        break;

    // string as data
    case Packet::ErrorPacket:
    case Packet::RequestRegistrationPacket: {
        QString string;
        stream >> string;
        packet.setData(new String(string));
    } break;

    // two string lists as data
    case Packet::ThemeChangedPacket: {
        QStringList themeInheritance, themeLibraryNames;
        stream >> themeInheritance >> themeLibraryNames;
        packet.setData(new ThemeChangeInfo(themeInheritance, themeLibraryNames));
    } break;

    case Packet::ProtocolVersionPacket:
    case Packet::ThemeChangeAppliedPacket: {
        qint32  priority;
        stream >> priority;
        packet.setData(new Number(priority));
    } break;

    // stringbool as data
    case Packet::RequestNewPixmapDirectoryPacket: {
        QString string;
        stream >> string;
        bool b = false;
        stream >> b;
        packet.setData(new StringBool(string, b));
    } break;

    // pixmap identifier as data
    case Packet::PixmapUsedPacket:
    case Packet::ReleasePixmapPacket: {
        PixmapIdentifier id;
        stream >> id;
        packet.setData(new PixmapIdentifier(id));
    } break;

    case Packet::RequestPixmapPacket: {
        qint32 priority;
        stream >> priority;
        PixmapIdentifier id;
        stream >> id;
        packet.setData(new RequestedPixmap(id, priority));
    } break;

    // pixmap handle as data
    case Packet::PixmapUpdatedPacket: {
        PixmapHandle h;
        stream >> h;
        packet.setData(new PixmapHandle(h));
    } break;

    case Packet::MostUsedPixmapsPacket: {
        QList<PixmapHandle> addedHandles;
        stream >> addedHandles;

        QList<PixmapIdentifier> removedIdentifiers;
        stream >> removedIdentifiers;

        packet.setData(new MostUsedPixmaps(addedHandles, removedIdentifiers));
    } break;

    // client list as data
    case Packet::ThemeDaemonStatusPacket: {
        QList<ClientInfo> clients;
        quint32 clientCount = 0;
        stream >> clientCount;
        while (clientCount) {
            ClientInfo info;
            stream >> info.name;
            quint32 pixmapCount = 0;
            stream >> pixmapCount;
            while (pixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.pixmaps.append(id);
                --pixmapCount;
            }
            quint32 requestedPixmapCount = 0;
            stream >> requestedPixmapCount;
            while (requestedPixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.requestedPixmaps.append(id);
                --requestedPixmapCount;
            }
            quint32 releasedPixmapCount = 0;
            stream >> releasedPixmapCount;
            while (releasedPixmapCount) {
                PixmapIdentifier id;
                stream >> id;
                info.releasedPixmaps.append(id);
                --releasedPixmapCount;
            }

            clients.append(info);
            --clientCount;
        }
        packet.setData(new ClientList(clients));
    } break;

    default:
        // print out warning
        break;
    }
}

QDataStream &operator<<(QDataStream &stream, const M::MThemeDaemonProtocol::PixmapHandle &handle)
{
    stream << handle.identifier;
    stream << quint64(quintptr(handle.pixmapHandle.xHandle));
    stream << quint64(quintptr(handle.pixmapHandle.eglHandle));
    stream << handle.pixmapHandle.shmHandle;
    stream << handle.pixmapHandle.size;
    stream << (quint64)handle.pixmapHandle.format;
    stream << handle.pixmapHandle.numBytes;
    stream << (bool)handle.pixmapHandle.directMap;
    return stream;
}

QDataStream &operator>>(QDataStream &stream, M::MThemeDaemonProtocol::PixmapHandle &handle)
{
    stream >> handle.identifier;

    quint64 h;
    stream >> h;
    handle.pixmapHandle.xHandle = (Qt::HANDLE) quintptr(h);
    stream >> h;
    handle.pixmapHandle.eglHandle = (Qt::HANDLE) quintptr(h);
    stream >> handle.pixmapHandle.shmHandle;
    stream >> handle.pixmapHandle.size;
    stream >> h;
    handle.pixmapHandle.format = QImage::Format(h);
    stream >> handle.pixmapHandle.numBytes;
    stream >> handle.pixmapHandle.directMap;
    return stream;
}

QDataStream &operator<<(QDataStream &stream, const M::MThemeDaemonProtocol::PixmapIdentifier &id)
{
    stream << id.imageId;
    stream << id.size;
    return stream;
}

QDataStream &operator>>(QDataStream &stream, M::MThemeDaemonProtocol::PixmapIdentifier &id)
{
    QString imageId;
    stream >> imageId;
    QSize size;
    stream >> size;
    id.imageId = imageId;
    id.size = size;
    return stream;
}

uint M::MThemeDaemonProtocol::qHash(const PixmapIdentifier &id)
{
    using ::qHash;

    const uint idHash     = qHash(id.imageId);
    const uint widthHash  = qHash(id.size.width());
    const uint heightHash = qHash(id.size.height());

    // Twiddle the bits a little, taking a cue from Qt's own qHash() overloads
    return idHash ^ (widthHash << 8) ^ (widthHash >> 24) ^ (heightHash << 24) ^ (heightHash >> 8);
}
<|endoftext|>


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

#include <shared_core/FileLogDestination.hpp>

#include <boost/thread.hpp>

#include <vector>

#include <shared_core/Error.hpp>
#include <shared_core/Logger.hpp>

namespace rstudio {
namespace core {
namespace log {

// FileLogOptions ======================================================================================================
FileLogOptions::FileLogOptions(FilePath in_directory) :
   m_directory(std::move(in_directory)),
   m_fileMode(s_defaultFileMode),
   m_maxSizeMb(s_defaultMaxSizeMb),
   m_doRotation(s_defaultDoRotation),
   m_includePid(s_defaultIncludePid)
{
}

FileLogOptions::FileLogOptions(
   FilePath in_directory,
   std::string in_fileMode,
   double in_maxSizeMb,
   bool in_doRotation,
   bool in_includePid) :
      m_directory(std::move(in_directory)),
      m_fileMode(std::move(in_fileMode)),
      m_maxSizeMb(in_maxSizeMb),
      m_doRotation(in_doRotation),
      m_includePid(in_includePid)
{
}

const FilePath& FileLogOptions::getDirectory() const
{
   return m_directory;
}

const std::string& FileLogOptions::getFileMode() const
{
   return m_fileMode;
}

double FileLogOptions::getMaxSizeMb() const
{
   return m_maxSizeMb;
}

bool FileLogOptions::doRotation() const
{
   return m_doRotation;
}

bool FileLogOptions::includePid() const
{
   return m_includePid;
}

// FileLogDestination ==================================================================================================
struct FileLogDestination::Impl
{
   Impl(unsigned int in_id, const std::string& in_name, FileLogOptions in_options) :
      LogOptions(std::move(in_options)),
      LogName(in_name + ".log"),
      RotatedLogName(in_name + ".old.log"),
      Id(in_id)
   {
      LogOptions.getDirectory().ensureDirectory();
   };

   ~Impl()
   {
      closeLogFile();
   }

   void closeLogFile()
   {
      if (LogOutputStream)
      {
         LogOutputStream->flush();
         LogOutputStream.reset();
      }
   }

   // Returns true if the log file was opened, false otherwise.
   bool openLogFile()
   {
      // We can't safely log in this function.
      Error error = LogOptions.getDirectory().completeChildPath(LogName, LogFile);
      if (error)
         return false;

      error = LogFile.ensureFile();
      if (error)
         return false;

      error = LogFile.openForWrite(LogOutputStream, false);
      if (error)
         return false;

      return true;
   }

   // Returns true if it is safe to log; false otherwise.
   bool rotateLogFile()
   {
      // Calculate the maximum size in bytes.
      const uintmax_t maxSize = 1048576.0 * LogOptions.getMaxSizeMb();

      // Only rotate if we're configured to rotate.
      if (LogOptions.doRotation())
      {
         // Convert MB to B for comparison.
         if (LogFile.getSize() >= maxSize)
         {
            FilePath rotatedLogFile = FilePath(LogOptions.getDirectory()).completeChildPath(RotatedLogName);

            // We can't safely log errors in this function because we'll end up in an infinitely recursive
            // rotateLogFile() call.
            Error error = rotatedLogFile.remove();
            if (error)
               return false;

            // Close the existing log file and then move it.
            closeLogFile();
            error = LogFile.move(rotatedLogFile);
            if (error)
               return false;

            // Now re-open the log file.
            openLogFile();
         }
      }

      return LogFile.getSize() < maxSize;
   }

   FileLogOptions LogOptions;
   FilePath LogFile;
   std::string LogName;
   std::string RotatedLogName;
   boost::mutex Mutex;
   unsigned int Id;
   std::shared_ptr<std::ostream> LogOutputStream;
};

FileLogDestination::FileLogDestination(
   unsigned int in_id,
   LogLevel in_logLevel,
   const std::string& in_programId,
   FileLogOptions in_logOptions) :
      ILogDestination(in_logLevel),
      m_impl(new Impl(in_id, in_programId, std::move(in_logOptions)))
{
}

FileLogDestination::~FileLogDestination()
{
   if (m_impl->LogOutputStream.get())
      m_impl->LogOutputStream->flush();
}

unsigned int FileLogDestination::getId() const
{
   return m_impl->Id;
}

void FileLogDestination::writeLog(LogLevel in_logLevel, const std::string& in_message)
{
   // Don't write logs that are more detailed than the configured maximum.
   if (in_logLevel > m_logLevel)
      return;

   // Lock the mutex before attempting to write.
   boost::unique_lock<boost::mutex> lock(m_impl->Mutex);

   // Open the log file if it's not open. If it fails to open, log nothing.
   if (!m_impl->LogOutputStream && !m_impl->openLogFile())
      return;

   // Rotate the log file if necessary.
   m_impl->rotateLogFile();
   (*m_impl->LogOutputStream) << in_message;
   m_impl->LogOutputStream->flush();
}

} // namespace log
} // namespace core
} // namespace rstudio

<commit_msg>Fix bug where failure to rotate a log file could cause a segfault. Fixes https://github.com/rstudio/rstudio-pro/issues/1779<commit_after>/*
 * FileLogDestination.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant to the terms of a commercial license agreement
 * with RStudio, then this program is licensed to you under the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <shared_core/FileLogDestination.hpp>

#include <boost/thread.hpp>

#include <vector>

#include <shared_core/Error.hpp>
#include <shared_core/Logger.hpp>

namespace rstudio {
namespace core {
namespace log {

// FileLogOptions ======================================================================================================
FileLogOptions::FileLogOptions(FilePath in_directory) :
   m_directory(std::move(in_directory)),
   m_fileMode(s_defaultFileMode),
   m_maxSizeMb(s_defaultMaxSizeMb),
   m_doRotation(s_defaultDoRotation),
   m_includePid(s_defaultIncludePid)
{
}

FileLogOptions::FileLogOptions(
   FilePath in_directory,
   std::string in_fileMode,
   double in_maxSizeMb,
   bool in_doRotation,
   bool in_includePid) :
      m_directory(std::move(in_directory)),
      m_fileMode(std::move(in_fileMode)),
      m_maxSizeMb(in_maxSizeMb),
      m_doRotation(in_doRotation),
      m_includePid(in_includePid)
{
}

const FilePath& FileLogOptions::getDirectory() const
{
   return m_directory;
}

const std::string& FileLogOptions::getFileMode() const
{
   return m_fileMode;
}

double FileLogOptions::getMaxSizeMb() const
{
   return m_maxSizeMb;
}

bool FileLogOptions::doRotation() const
{
   return m_doRotation;
}

bool FileLogOptions::includePid() const
{
   return m_includePid;
}

// FileLogDestination ==================================================================================================
struct FileLogDestination::Impl
{
   Impl(unsigned int in_id, const std::string& in_name, FileLogOptions in_options) :
      LogOptions(std::move(in_options)),
      LogName(in_name + ".log"),
      RotatedLogName(in_name + ".old.log"),
      Id(in_id)
   {
      LogOptions.getDirectory().ensureDirectory();
   };

   ~Impl()
   {
      closeLogFile();
   }

   void closeLogFile()
   {
      if (LogOutputStream)
      {
         LogOutputStream->flush();
         LogOutputStream.reset();
      }
   }

   // Returns true if the log file was opened, false otherwise.
   bool openLogFile()
   {
      // We can't safely log in this function.
      Error error = LogOptions.getDirectory().completeChildPath(LogName, LogFile);
      if (error)
         return false;

      error = LogFile.ensureFile();
      if (error)
         return false;

      error = LogFile.openForWrite(LogOutputStream, false);
      if (error)
         return false;

      return true;
   }

   // Returns true if it is safe to log; false otherwise.
   bool rotateLogFile()
   {
      // Calculate the maximum size in bytes.
      const uintmax_t maxSize = 1048576.0 * LogOptions.getMaxSizeMb();

      // Only rotate if we're configured to rotate.
      if (LogOptions.doRotation())
      {
         // Convert MB to B for comparison.
         if (LogFile.getSize() >= maxSize)
         {
            FilePath rotatedLogFile = FilePath(LogOptions.getDirectory()).completeChildPath(RotatedLogName);

            // We can't safely log errors in this function because we'll end up in an infinitely recursive
            // rotateLogFile() call.
            Error error = rotatedLogFile.remove();
            if (error)
               return false;

            // Close the existing log file and then move it.
            closeLogFile();
            error = LogFile.move(rotatedLogFile);
            if (error)
               return false;

            // Now re-open the log file.
            if (!openLogFile())
               return false;
         }

         // we only sucessfully rotated (and thus are safe to log) if the
         // file size is now lower than the limit
         return LogFile.getSize() < maxSize;
      }
      else
      {
         // we are configured not to rotate logs, which means the log file can grow unboundedly large
         // thus, we are safe to log
         return true;
      }
   }

   FileLogOptions LogOptions;
   FilePath LogFile;
   std::string LogName;
   std::string RotatedLogName;
   boost::mutex Mutex;
   unsigned int Id;
   std::shared_ptr<std::ostream> LogOutputStream;
};

FileLogDestination::FileLogDestination(
   unsigned int in_id,
   LogLevel in_logLevel,
   const std::string& in_programId,
   FileLogOptions in_logOptions) :
      ILogDestination(in_logLevel),
      m_impl(new Impl(in_id, in_programId, std::move(in_logOptions)))
{
}

FileLogDestination::~FileLogDestination()
{
   if (m_impl->LogOutputStream.get())
      m_impl->LogOutputStream->flush();
}

unsigned int FileLogDestination::getId() const
{
   return m_impl->Id;
}

void FileLogDestination::writeLog(LogLevel in_logLevel, const std::string& in_message)
{
   // Don't write logs that are more detailed than the configured maximum.
   if (in_logLevel > m_logLevel)
      return;

   // Lock the mutex before attempting to write.
   boost::unique_lock<boost::mutex> lock(m_impl->Mutex);

   // Open the log file if it's not open. If it fails to open, log nothing.
   if (!m_impl->LogOutputStream && !m_impl->openLogFile())
      return;

   // Rotate the log file if necessary. If it fails to rotate, log nothing.
   if (!m_impl->rotateLogFile())
      return;

   (*m_impl->LogOutputStream) << in_message;
   m_impl->LogOutputStream->flush();
}

} // namespace log
} // namespace core
} // namespace rstudio

<|endoftext|>


<commit_before>#include <iostream>
#include "RelativeDetector.h"

#include <list>

#include <opencv_workbench/utils/ColorMaps.h>
#include <opencv_workbench/wb/WB.h>
#include <opencv_workbench/wb/Cluster.h>
#include <opencv_workbench/wb/ClusterProcess.h>
#include <opencv_workbench/wb/NDT.h>
#include <opencv_workbench/utils/OpenCV_Helpers.h>

using std::cout;
using std::endl;

RelativeDetector::RelativeDetector()
{
     cout << "RelativeDetector Constructor" << endl;
     thresh_value_ = 255;
     grad_thresh_value_ = 255;

     cluster_process_.set_threshold(0);
     cluster_process_.set_gate(25); // 15, 50, 100
     cluster_process_.set_min_cluster_size(30);

     int erosionElem = cv::MORPH_ELLIPSE;
     int erosionSize = 1;
     int dilationElem = cv::MORPH_ELLIPSE; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
     int dilationSize = 1;

     erosionConfig_ = cv::getStructuringElement( erosionElem,
                                                 cv::Size(2*erosionSize+1, 2*erosionSize+1),
                                                 cv::Point(erosionSize, erosionSize) );

     dilationConfig_ = cv::getStructuringElement( dilationElem,
                                                  cv::Size(2*dilationSize+1, 2*dilationSize+1),
                                                  cv::Point(dilationSize, dilationSize) );
}

RelativeDetector::~RelativeDetector()
{
     cout << "RelativeDetector Destructor" << endl;
}

void RelativeDetector::print()
{
     cout << "I am the Relative Detector" << endl;
}

void RelativeDetector::set_stream(syllo::Stream *stream)
{
     stream_ = stream;
}

double RelativeDetector::trajectory_diff(std::list<cv::Point2d> &t1,
                                         std::list<cv::Point2d> &t2)
{
     // Calculate differences in trajectories
     double total_diff = 0;
     std::vector<cv::Point2d> diffs;
     int frame = 0;
     std::list<cv::Point2d>::iterator it1 = t1.begin();
     std::list<cv::Point2d>::iterator it2 = t2.begin();
     for(; it1 != t1.end() && it2 != t2.end();
         it1++, it2++) {

          double diff = pow(it1->x - it2->x, 2) + pow(it1->y - it2->y, 2);
          diffs.push_back(cv::Point2d(frame,diff));
          total_diff += diff;
          frame++;
     }
     //vectors.push_back(diffs);
     //labels.push_back("Diff");
     //styles.push_back("linespoints");

     //vectors.push_back(costs);
     //labels.push_back("Cost");
     //styles.push_back("linespoints");
     //plot.plot(vectors, title2, labels, styles);

     double mean = total_diff / (double)diffs.size();
     double RMSE = sqrt(mean);
     return RMSE;
}

void RelativeDetector::trajectory_polar_diff(std::list<wb::Entity> &traj,
                                             std::list<cv::Point2d> &diffs)
{
     std::list<wb::Entity>::reverse_iterator it = traj.rbegin();
     cv::Point2d prev;
     for(; it != traj.rend(); it++) {
          if (it == traj.rbegin()) {
               prev = it->undistorted_centroid();
               continue;
          }

          cv::Point2d p = it->undistorted_centroid();

          // Convert to polar
          double range = sqrt( pow(p.x,2) + pow(p.y,2) );
          double range_prev = sqrt( pow(prev.x,2) + pow(prev.y,2) );
          double theta = atan(p.y / p.x);
          double theta_prev = atan(prev.y / prev.x);
          //
          cv::Point2d polar(range,theta);
          cv::Point2d polar_prev(range_prev, theta_prev);

          double range_diff = range - range_prev;
          double theta_diff = theta - theta_prev;

          cv::Point2d temp;
          temp.x = range_diff;
          temp.y = theta_diff;

          diffs.push_back(temp);

          prev = it->undistorted_centroid();
     }
}

struct TrajRMSE {
     int ID1;
     int ID2;
     double RMSE;
};

void RelativeDetector::trajectory_similarity(int frame_number, cv::Mat &img)
{
     //cout << "==========================================" << endl;
     std::map<int, std::list<cv::Point2d> > trajectories;
     for (std::map<int, std::list<wb::Entity> >::iterator
               it = tracks_history_.begin(); it != tracks_history_.end(); ) {
          if (it->second.back().frame() < frame_number) {
               // Clear out track IDs that are dead
               tracks_history_.erase(it++);
          } else {
               if (it->second.back().is_tracked()) {
                    //cout << "Tracked: " << it->first << endl;
                    // Compute derivative of each current track's trajectory
                    trajectory_polar_diff(it->second, trajectories[it->first]);
               }
               it++;
          }
     }

     std::map<std::string, struct TrajRMSE> RMSEs;
     // Store RMSE between each trajectory in a map/hash. A string will be used
     // to hash the values. The string is of the form "n:m", where n and m are
     // the trajectory IDs and n is less than m.

     // Calculate differences between trajectory derivatives
     std::map<int, std::list<cv::Point2d> >::iterator it_1 = trajectories.begin();
     for(; it_1 != trajectories.end(); it_1++) {
          std::map<int, std::list<cv::Point2d> >::iterator it_2 = trajectories.begin();
          for(; it_2 != trajectories.end(); it_2++) {
               // Determine if this trajectory difference has already been
               // calculated
               std::string key;
               struct TrajRMSE traj;
               if (it_1->first == it_2->first) {
                    // Don't calculate trajectory diff between two trajectories
                    // with the same ID. This is the same trajectory.
                    continue;
               } else if (it_1->first < it_2->first) {
                    key = syllo::int2str(it_1->first) + ":" + syllo::int2str(it_2->first);
                    traj.ID1 = it_1->first;
                    traj.ID2 = it_2->first;
               } else {
                    key = syllo::int2str(it_2->first) + ":" + syllo::int2str(it_1->first);
                    traj.ID1 = it_2->first;
                    traj.ID2 = it_1->first;
               }

               if (RMSEs.count(key) == 0) {
                    double RMSE = trajectory_diff(it_1->second, it_2->second);
                    traj.RMSE = RMSE;
                    RMSEs[key] = traj;
                    //cout << "--------------" << endl;
                    //cout << it_1->first << " - " << it_2->first << " : " << RMSE << endl;
               }
          }
     }

     // Print out the RMSEs for this frame:
     //cout << "-----------------" << endl;
     for(std::map<std::string, struct TrajRMSE>::iterator it = RMSEs.begin();
         it != RMSEs.end(); it++) {
          //cout << it->first << ": " << it->second.RMSE << endl;

          // If the RMSE between two trajectories is less than a threshold,
          // circle the trajectories
          if (it->second.RMSE < 0.017) {
               // Get the two IDs in the track history and circle them
               cv::Point p1 = tracks_history_[it->second.ID1].back().centroid();
               cv::Point p2 = tracks_history_[it->second.ID2].back().centroid();

               //cv::circle(img, p1, 10, cv::Scalar(0,255,255), 1, 8, 0);
               //cv::circle(img, p2, 10, cv::Scalar(0,255,255), 1, 8, 0);
               cv::line(img, p1, p2, cv::Scalar(0,255,255), 1, 8, 0);
          }
     }

     cv::imshow("SimTraj", img);
}

int RelativeDetector::set_frame(int frame_number, const cv::Mat &original)
{
      cv::Mat original_w_tracks, original_copy;
      original_w_tracks = original;
      original_copy = original;

      //cv::cvtColor(original_copy, original_copy, CV_RGBA2BGR);
      //wb::show_nonzero(original_copy);

      //cv::Mat bad_gray;
      //cv::applyColorMap(original, bad_gray, CV_BGR2GRAY);
      //cv::cvtColor(original, bad_gray, CV_BGR2GRAY);
      //cv::imshow("bad", bad_gray);

      cv::Mat gray;
      if (original.channels() != 1) {
           Jet2Gray_matlab(original,gray);
      } else {
           gray = original.clone();
      }
      cv::imshow("Gray", gray);

      //cv::Mat ndt_img;
      //ndt_.set_frame(gray, ndt_img);
      //cv::imshow("ndt", ndt_img);

      // Compute median
      cv::Mat median;
      cv::medianBlur(gray, median,5);
      cv::imshow("median", median);

      /// // Compute estimated gradient
      /// cv::Mat grad;
      /// wb::gradient_sobel(median, grad);
      /// cv::imshow("gradient", grad);
      ///
      ///cv::Mat thresh_grad;
      ///wb::adaptive_threshold(grad, thresh_grad, grad_thresh_value_, 0.001, 0.002, 10, 5);
      /// cv::imshow("grad thresh", thresh_grad);

      cv::Mat thresh_amp;
#if 1
      wb::adaptive_threshold(median, thresh_amp, thresh_value_, 0.001, 0.002, 10, 5);

#else
      // TODO: For some reason, using this static threshold kills regular sonar
      // images, (vs. simulated sonar images), it might have to do with the
      // number of detected blobs Used for thresholding simulated sonar data
      // from Gazebo
      cv::threshold(median, thresh_amp, 100, 255, cv::THRESH_TOZERO);
#endif
      cv::imshow("thresh amp", thresh_amp);

      /// cv::Mat thresh_and_grad = thresh_amp + thresh_grad;
      /// cv::imshow("thresh and grad", thresh_and_grad);
      cv::Mat erode;
      cv::erode(thresh_amp, erode, erosionConfig_);
      //cv::imshow("erode", erode);

      cv::Mat dilate;
      cv::dilate(erode, dilate, dilationConfig_);
      cv::imshow("Erode/Dilate", dilate);
      //dilate = thresh_amp;

      cv::Mat blob_consolidate;
      blob_process_.consolidate_tracks(gray, blob_consolidate);
      cv::imshow("Consolidate", blob_consolidate);
      //if (found_overlap) {
      //     cv::waitKey(0);
      //}

      blob_process_.process_frame(dilate, median, thresh_value_);

      cv::Mat blob_img;
      blob_process_.overlay_blobs(gray, blob_img);

      blob_process_.overlay_tracks(blob_img, blob_img);
      cv::imshow("Blobs", blob_img);

      //////////////////////////////////////////////////////////////
      /// Tracking
      ////////////////////////////////////////////////////
      tracks_.clear(); // clear out the tracks from previous loop

      std::vector<wb::Blob> blobs = blob_process_.blobs();
      std::vector<wb::Blob>::iterator it = blobs.begin();
      for (; it != blobs.end(); it++) {

           // Have to transform tracks from distorted cartesian
           // to polar, then to undistorted cartesian
           cv::Point p = it->estimated_centroid();

           double x, y;
           if (stream_->type() == syllo::SonarType) {
                double range = stream_->pixel_range(p.y, p.x); //row, col
                double bearing = stream_->pixel_bearing(p.y, p.x) * 0.017453293; // pi/180
                y = -range*cos(bearing);
                x = range*sin(bearing);
           } else {
                x = p.x;
                y = p.y;
           }

           //it->set_undistorted_centroid(cv::Point2f(p.x,p.y));
           it->set_undistorted_centroid(cv::Point2f(x,y));
           it->set_frame(frame_number);

           tracks_history_[it->id()].push_back((wb::Entity)*it);

           tracks_.push_back((wb::Entity)*it);
      }

      // Calculate Similarity between current tracks
      this->trajectory_similarity(frame_number, blob_img);

      ///////////////////////////////////////////////////
      // Display images
      ///////////////////////////////////////////////////
      if (!hide_windows_) {
      }

     return 0;
}

extern "C" {
     Detector *maker(){
          return new RelativeDetector;
     }

     class proxy {
     public:
          proxy(){
               // register the maker with the factory
               // causes static initialization error plugin_manager_.factory["blank_detector"] = maker;
               plugin_manager_.factory["relative_detector"] = maker;
          }
     };
     // our one instance of the proxy
     proxy p;
}

/// Color map tests
///cv::Mat grad;
///create_gradient(grad, 100, 255);
///cv::imshow("gradient", grad);
///
///cv::Mat jet_matlab;
///Gray2Jet_matlab(grad,jet_matlab);
///cv::imshow("jet matlab", jet_matlab);
///
///cv::Mat gray_2;
///Jet2Gray_matlab(jet_matlab,gray_2);
///cv::imshow("gray_2",gray_2);
///
///cv::Mat diff = gray_2 - grad;
///cv::imshow("diff",diff);
///
///if (!equal(gray_2, grad)) {
///     cout << "Grays are unequal" << endl;
///}
<commit_msg>moved track consolidation after assignment algorithm<commit_after>#include <iostream>
#include "RelativeDetector.h"

#include <list>

#include <opencv_workbench/utils/ColorMaps.h>
#include <opencv_workbench/wb/WB.h>
#include <opencv_workbench/wb/Cluster.h>
#include <opencv_workbench/wb/ClusterProcess.h>
#include <opencv_workbench/wb/NDT.h>
#include <opencv_workbench/utils/OpenCV_Helpers.h>

using std::cout;
using std::endl;

RelativeDetector::RelativeDetector()
{
     cout << "RelativeDetector Constructor" << endl;
     thresh_value_ = 255;
     grad_thresh_value_ = 255;

     cluster_process_.set_threshold(0);
     cluster_process_.set_gate(25); // 15, 50, 100
     cluster_process_.set_min_cluster_size(30);

     int erosionElem = cv::MORPH_ELLIPSE;
     int erosionSize = 1;
     int dilationElem = cv::MORPH_ELLIPSE; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
     int dilationSize = 1;

     erosionConfig_ = cv::getStructuringElement( erosionElem,
                                                 cv::Size(2*erosionSize+1, 2*erosionSize+1),
                                                 cv::Point(erosionSize, erosionSize) );

     dilationConfig_ = cv::getStructuringElement( dilationElem,
                                                  cv::Size(2*dilationSize+1, 2*dilationSize+1),
                                                  cv::Point(dilationSize, dilationSize) );
}

RelativeDetector::~RelativeDetector()
{
     cout << "RelativeDetector Destructor" << endl;
}

void RelativeDetector::print()
{
     cout << "I am the Relative Detector" << endl;
}

void RelativeDetector::set_stream(syllo::Stream *stream)
{
     stream_ = stream;
}

double RelativeDetector::trajectory_diff(std::list<cv::Point2d> &t1,
                                         std::list<cv::Point2d> &t2)
{
     // Calculate differences in trajectories
     double total_diff = 0;
     std::vector<cv::Point2d> diffs;
     int frame = 0;
     std::list<cv::Point2d>::iterator it1 = t1.begin();
     std::list<cv::Point2d>::iterator it2 = t2.begin();
     for(; it1 != t1.end() && it2 != t2.end();
         it1++, it2++) {

          double diff = pow(it1->x - it2->x, 2) + pow(it1->y - it2->y, 2);
          diffs.push_back(cv::Point2d(frame,diff));
          total_diff += diff;
          frame++;
     }
     //vectors.push_back(diffs);
     //labels.push_back("Diff");
     //styles.push_back("linespoints");

     //vectors.push_back(costs);
     //labels.push_back("Cost");
     //styles.push_back("linespoints");
     //plot.plot(vectors, title2, labels, styles);

     double mean = total_diff / (double)diffs.size();
     double RMSE = sqrt(mean);
     return RMSE;
}

void RelativeDetector::trajectory_polar_diff(std::list<wb::Entity> &traj,
                                             std::list<cv::Point2d> &diffs)
{
     std::list<wb::Entity>::reverse_iterator it = traj.rbegin();
     cv::Point2d prev;
     for(; it != traj.rend(); it++) {
          if (it == traj.rbegin()) {
               prev = it->undistorted_centroid();
               continue;
          }

          cv::Point2d p = it->undistorted_centroid();

          // Convert to polar
          double range = sqrt( pow(p.x,2) + pow(p.y,2) );
          double range_prev = sqrt( pow(prev.x,2) + pow(prev.y,2) );
          double theta = atan(p.y / p.x);
          double theta_prev = atan(prev.y / prev.x);
          //
          cv::Point2d polar(range,theta);
          cv::Point2d polar_prev(range_prev, theta_prev);

          double range_diff = range - range_prev;
          double theta_diff = theta - theta_prev;

          cv::Point2d temp;
          temp.x = range_diff;
          temp.y = theta_diff;

          diffs.push_back(temp);

          prev = it->undistorted_centroid();
     }
}

struct TrajRMSE {
     int ID1;
     int ID2;
     double RMSE;
};

void RelativeDetector::trajectory_similarity(int frame_number, cv::Mat &img)
{
     //cout << "==========================================" << endl;
     std::map<int, std::list<cv::Point2d> > trajectories;
     for (std::map<int, std::list<wb::Entity> >::iterator
               it = tracks_history_.begin(); it != tracks_history_.end(); ) {
          if (it->second.back().frame() < frame_number) {
               // Clear out track IDs that are dead
               tracks_history_.erase(it++);
          } else {
               if (it->second.back().is_tracked()) {
                    //cout << "Tracked: " << it->first << endl;
                    // Compute derivative of each current track's trajectory
                    trajectory_polar_diff(it->second, trajectories[it->first]);
               }
               it++;
          }
     }

     std::map<std::string, struct TrajRMSE> RMSEs;
     // Store RMSE between each trajectory in a map/hash. A string will be used
     // to hash the values. The string is of the form "n:m", where n and m are
     // the trajectory IDs and n is less than m.

     // Calculate differences between trajectory derivatives
     std::map<int, std::list<cv::Point2d> >::iterator it_1 = trajectories.begin();
     for(; it_1 != trajectories.end(); it_1++) {
          std::map<int, std::list<cv::Point2d> >::iterator it_2 = trajectories.begin();
          for(; it_2 != trajectories.end(); it_2++) {
               // Determine if this trajectory difference has already been
               // calculated
               std::string key;
               struct TrajRMSE traj;
               if (it_1->first == it_2->first) {
                    // Don't calculate trajectory diff between two trajectories
                    // with the same ID. This is the same trajectory.
                    continue;
               } else if (it_1->first < it_2->first) {
                    key = syllo::int2str(it_1->first) + ":" + syllo::int2str(it_2->first);
                    traj.ID1 = it_1->first;
                    traj.ID2 = it_2->first;
               } else {
                    key = syllo::int2str(it_2->first) + ":" + syllo::int2str(it_1->first);
                    traj.ID1 = it_2->first;
                    traj.ID2 = it_1->first;
               }

               if (RMSEs.count(key) == 0) {
                    double RMSE = trajectory_diff(it_1->second, it_2->second);
                    traj.RMSE = RMSE;
                    RMSEs[key] = traj;
                    //cout << "--------------" << endl;
                    //cout << it_1->first << " - " << it_2->first << " : " << RMSE << endl;
               }
          }
     }

     // Print out the RMSEs for this frame:
     //cout << "-----------------" << endl;
     for(std::map<std::string, struct TrajRMSE>::iterator it = RMSEs.begin();
         it != RMSEs.end(); it++) {
          //cout << it->first << ": " << it->second.RMSE << endl;

          // If the RMSE between two trajectories is less than a threshold,
          // circle the trajectories
          if (it->second.RMSE < 0.017) {
               // Get the two IDs in the track history and circle them
               cv::Point p1 = tracks_history_[it->second.ID1].back().centroid();
               cv::Point p2 = tracks_history_[it->second.ID2].back().centroid();

               //cv::circle(img, p1, 10, cv::Scalar(0,255,255), 1, 8, 0);
               //cv::circle(img, p2, 10, cv::Scalar(0,255,255), 1, 8, 0);
               cv::line(img, p1, p2, cv::Scalar(0,255,255), 1, 8, 0);
          }
     }

     cv::imshow("SimTraj", img);
}

int RelativeDetector::set_frame(int frame_number, const cv::Mat &original)
{
      cv::Mat original_w_tracks, original_copy;
      original_w_tracks = original;
      original_copy = original;

      //cv::cvtColor(original_copy, original_copy, CV_RGBA2BGR);
      //wb::show_nonzero(original_copy);

      //cv::Mat bad_gray;
      //cv::applyColorMap(original, bad_gray, CV_BGR2GRAY);
      //cv::cvtColor(original, bad_gray, CV_BGR2GRAY);
      //cv::imshow("bad", bad_gray);

      cv::Mat gray;
      if (original.channels() != 1) {
           Jet2Gray_matlab(original,gray);
      } else {
           gray = original.clone();
      }
      cv::imshow("Gray", gray);

      //cv::Mat ndt_img;
      //ndt_.set_frame(gray, ndt_img);
      //cv::imshow("ndt", ndt_img);

      // Compute median
      cv::Mat median;
      cv::medianBlur(gray, median,5);
      cv::imshow("median", median);

      /// // Compute estimated gradient
      /// cv::Mat grad;
      /// wb::gradient_sobel(median, grad);
      /// cv::imshow("gradient", grad);
      ///
      ///cv::Mat thresh_grad;
      ///wb::adaptive_threshold(grad, thresh_grad, grad_thresh_value_, 0.001, 0.002, 10, 5);
      /// cv::imshow("grad thresh", thresh_grad);

      cv::Mat thresh_amp;
#if 1
      wb::adaptive_threshold(median, thresh_amp, thresh_value_, 0.001, 0.002, 10, 5);

#else
      // TODO: For some reason, using this static threshold kills regular sonar
      // images, (vs. simulated sonar images), it might have to do with the
      // number of detected blobs Used for thresholding simulated sonar data
      // from Gazebo
      cv::threshold(median, thresh_amp, 100, 255, cv::THRESH_TOZERO);
#endif
      cv::imshow("thresh amp", thresh_amp);

      /// cv::Mat thresh_and_grad = thresh_amp + thresh_grad;
      /// cv::imshow("thresh and grad", thresh_and_grad);
      cv::Mat erode;
      cv::erode(thresh_amp, erode, erosionConfig_);
      //cv::imshow("erode", erode);

      cv::Mat dilate;
      cv::dilate(erode, dilate, dilationConfig_);
      cv::imshow("Erode/Dilate", dilate);

      blob_process_.process_frame(dilate, median, thresh_value_);

      cv::Mat blob_img;
      blob_process_.overlay_blobs(gray, blob_img);

      blob_process_.overlay_tracks(blob_img, blob_img);
      cv::imshow("Blobs", blob_img);

      cv::Mat blob_consolidate;
      blob_process_.consolidate_tracks(gray, blob_consolidate);
      cv::imshow("Consolidate", blob_consolidate);

      //////////////////////////////////////////////////////////////
      /// Tracking
      ////////////////////////////////////////////////////
      tracks_.clear(); // clear out the tracks from previous loop

      std::vector<wb::Blob> blobs = blob_process_.blobs();
      std::vector<wb::Blob>::iterator it = blobs.begin();
      for (; it != blobs.end(); it++) {

           // Have to transform tracks from distorted cartesian
           // to polar, then to undistorted cartesian
           cv::Point p = it->estimated_centroid();

           double x, y;
           if (stream_->type() == syllo::SonarType) {
                double range = stream_->pixel_range(p.y, p.x); //row, col
                double bearing = stream_->pixel_bearing(p.y, p.x) * 0.017453293; // pi/180
                y = -range*cos(bearing);
                x = range*sin(bearing);
           } else {
                x = p.x;
                y = p.y;
           }

           //it->set_undistorted_centroid(cv::Point2f(p.x,p.y));
           it->set_undistorted_centroid(cv::Point2f(x,y));
           it->set_frame(frame_number);

           tracks_history_[it->id()].push_back((wb::Entity)*it);

           tracks_.push_back((wb::Entity)*it);
      }

      // Calculate Similarity between current tracks
      this->trajectory_similarity(frame_number, blob_img);

      ///////////////////////////////////////////////////
      // Display images
      ///////////////////////////////////////////////////
      if (!hide_windows_) {
      }

     return 0;
}

extern "C" {
     Detector *maker(){
          return new RelativeDetector;
     }

     class proxy {
     public:
          proxy(){
               // register the maker with the factory
               // causes static initialization error plugin_manager_.factory["blank_detector"] = maker;
               plugin_manager_.factory["relative_detector"] = maker;
          }
     };
     // our one instance of the proxy
     proxy p;
}

/// Color map tests
///cv::Mat grad;
///create_gradient(grad, 100, 255);
///cv::imshow("gradient", grad);
///
///cv::Mat jet_matlab;
///Gray2Jet_matlab(grad,jet_matlab);
///cv::imshow("jet matlab", jet_matlab);
///
///cv::Mat gray_2;
///Jet2Gray_matlab(jet_matlab,gray_2);
///cv::imshow("gray_2",gray_2);
///
///cv::Mat diff = gray_2 - grad;
///cv::imshow("diff",diff);
///
///if (!equal(gray_2, grad)) {
///     cout << "Grays are unequal" << endl;
///}
<|endoftext|>


<commit_before>#include <iostream>
#include "RelativeDetector.h"

#include <list>

#include <opencv_workbench/utils/ColorMaps.h>
#include <opencv_workbench/wb/WB.h>
#include <opencv_workbench/wb/Cluster.h>
#include <opencv_workbench/wb/ClusterProcess.h>
#include <opencv_workbench/wb/NDT.h>
#include <opencv_workbench/utils/OpenCV_Helpers.h>

using std::cout;
using std::endl;

RelativeDetector::RelativeDetector()
{
     cout << "RelativeDetector Constructor" << endl;
     thresh_value_ = 255;
     grad_thresh_value_ = 255;

     cluster_process_.set_threshold(0);
     cluster_process_.set_gate(25); // 15, 50, 100
     cluster_process_.set_min_cluster_size(30);

     int erosionElem = cv::MORPH_ELLIPSE;
     int erosionSize = 2;
     int dilationElem = cv::MORPH_ELLIPSE; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
     int dilationSize = 1;

     erosionConfig_ = cv::getStructuringElement( erosionElem,
                                                 cv::Size(2*erosionSize+1, 2*erosionSize+1),
                                                 cv::Point(erosionSize, erosionSize) );

     dilationConfig_ = cv::getStructuringElement( dilationElem,
                                                  cv::Size(2*dilationSize+1, 2*dilationSize+1),
                                                  cv::Point(dilationSize, dilationSize) );
}

RelativeDetector::~RelativeDetector()
{
     cout << "RelativeDetector Destructor" << endl;
}

void RelativeDetector::print()
{
     cout << "I am the Relative Detector" << endl;
}

void RelativeDetector::set_stream(syllo::Stream *stream)
{
     stream_ = stream;
}

int RelativeDetector::set_frame(int frame_number, const cv::Mat &original)
{
      cv::Mat original_w_tracks, original_copy;
      original_w_tracks = original;
      original_copy = original;

      //cv::cvtColor(original_copy, original_copy, CV_RGBA2BGR);
      //wb::show_nonzero(original_copy);

      //cv::Mat bad_gray;
      //cv::applyColorMap(original, bad_gray, CV_BGR2GRAY);
      //cv::cvtColor(original, bad_gray, CV_BGR2GRAY);
      //cv::imshow("bad", bad_gray);

      cv::Mat gray;
      if (original.channels() != 1) {
           Jet2Gray_matlab(original,gray);
      } else {
           gray = original.clone();
      }
      cv::imshow("Gray", gray);

      //cv::Mat ndt_img;
      //ndt_.set_frame(gray, ndt_img);
      //cv::imshow("ndt", ndt_img);

      // Compute median
      cv::Mat median;
      cv::medianBlur(gray, median,5);
      cv::imshow("median", median);

      /// // Compute estimated gradient
      /// cv::Mat grad;
      /// wb::gradient_sobel(median, grad);
      /// cv::imshow("gradient", grad);
      ///
      ///cv::Mat thresh_grad;
      ///wb::adaptive_threshold(grad, thresh_grad, grad_thresh_value_, 0.001, 0.002, 10, 5);
      /// cv::imshow("grad thresh", thresh_grad);

      cv::Mat thresh_amp;
#if 0
      wb::adaptive_threshold(median, thresh_amp, thresh_value_, 0.001, 0.002, 10, 5);

#else
      // Used for thresholding simulated sonar data from Gazebo
      cv::threshold(median, thresh_amp, 100, 255, cv::THRESH_TOZERO);
#endif
      cv::imshow("thresh amp", thresh_amp);

      /// cv::Mat thresh_and_grad = thresh_amp + thresh_grad;
      /// cv::imshow("thresh and grad", thresh_and_grad);
      /// cv::Mat erode;
      /// cv::erode(thresh_amp, erode, erosionConfig_);
      /// cv::imshow("erode", erode);
      ///
      //cv::Mat dilate;
      /// cv::dilate(erode, dilate, dilationConfig_);
      /// cv::imshow("dilate", dilate);
      //dilate = thresh_amp;

      blob_process_.process_frame(thresh_amp, median, thresh_value_);

      cv::Mat blob_img;
      blob_process_.overlay_blobs(gray, blob_img);

      blob_process_.overlay_tracks(blob_img, blob_img);
      cv::imshow("Blobs", blob_img);

      //////////////////////////////////////////////////////////////
      /// Tracking
      ////////////////////////////////////////////////////
      tracks_.clear(); // clear out the tracks from previous loop

      std::vector<wb::Blob> blobs = blob_process_.blobs();
      std::vector<wb::Blob>::iterator it = blobs.begin();
      for (; it != blobs.end(); it++) {

           // Have to transform tracks from distorted cartesian
           // to polar, then to undistorted cartesian
           cv::Point p = it->estimated_centroid();

           double x, y;
           if (stream_->type() == syllo::SonarType) {
                double range = stream_->pixel_range(p.y, p.x); //row, col
                double bearing = stream_->pixel_bearing(p.y, p.x) * 0.017453293; // pi/180
                y = -range*cos(bearing);
                x = range*sin(bearing);
           } else {
                x = p.x;
                y = p.y;
           }

           //it->set_undistorted_centroid(cv::Point2f(p.x,p.y));
           it->set_undistorted_centroid(cv::Point2f(x,y));

           tracks_.push_back((wb::Entity)*it);
      }

      ///////////////////////////////////////////////////
      // Display images
      ///////////////////////////////////////////////////
      if (!hide_windows_) {
      }

     return 0;
}

extern "C" {
     Detector *maker(){
          return new RelativeDetector;
     }

     class proxy {
     public:
          proxy(){
               // register the maker with the factory
               // causes static initialization error plugin_manager_.factory["blank_detector"] = maker;
               plugin_manager_.factory["relative_detector"] = maker;
          }
     };
     // our one instance of the proxy
     proxy p;
}

/// Color map tests
///cv::Mat grad;
///create_gradient(grad, 100, 255);
///cv::imshow("gradient", grad);
///
///cv::Mat jet_matlab;
///Gray2Jet_matlab(grad,jet_matlab);
///cv::imshow("jet matlab", jet_matlab);
///
///cv::Mat gray_2;
///Jet2Gray_matlab(jet_matlab,gray_2);
///cv::imshow("gray_2",gray_2);
///
///cv::Mat diff = gray_2 - grad;
///cv::imshow("diff",diff);
///
///if (!equal(gray_2, grad)) {
///     cout << "Grays are unequal" << endl;
///}
<commit_msg>changed sim/real switch<commit_after>#include <iostream>
#include "RelativeDetector.h"

#include <list>

#include <opencv_workbench/utils/ColorMaps.h>
#include <opencv_workbench/wb/WB.h>
#include <opencv_workbench/wb/Cluster.h>
#include <opencv_workbench/wb/ClusterProcess.h>
#include <opencv_workbench/wb/NDT.h>
#include <opencv_workbench/utils/OpenCV_Helpers.h>

using std::cout;
using std::endl;

RelativeDetector::RelativeDetector()
{
     cout << "RelativeDetector Constructor" << endl;
     thresh_value_ = 255;
     grad_thresh_value_ = 255;

     cluster_process_.set_threshold(0);
     cluster_process_.set_gate(25); // 15, 50, 100
     cluster_process_.set_min_cluster_size(30);

     int erosionElem = cv::MORPH_ELLIPSE;
     int erosionSize = 2;
     int dilationElem = cv::MORPH_ELLIPSE; // MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE
     int dilationSize = 1;

     erosionConfig_ = cv::getStructuringElement( erosionElem,
                                                 cv::Size(2*erosionSize+1, 2*erosionSize+1),
                                                 cv::Point(erosionSize, erosionSize) );

     dilationConfig_ = cv::getStructuringElement( dilationElem,
                                                  cv::Size(2*dilationSize+1, 2*dilationSize+1),
                                                  cv::Point(dilationSize, dilationSize) );
}

RelativeDetector::~RelativeDetector()
{
     cout << "RelativeDetector Destructor" << endl;
}

void RelativeDetector::print()
{
     cout << "I am the Relative Detector" << endl;
}

void RelativeDetector::set_stream(syllo::Stream *stream)
{
     stream_ = stream;
}

int RelativeDetector::set_frame(int frame_number, const cv::Mat &original)
{
      cv::Mat original_w_tracks, original_copy;
      original_w_tracks = original;
      original_copy = original;

      //cv::cvtColor(original_copy, original_copy, CV_RGBA2BGR);
      //wb::show_nonzero(original_copy);

      //cv::Mat bad_gray;
      //cv::applyColorMap(original, bad_gray, CV_BGR2GRAY);
      //cv::cvtColor(original, bad_gray, CV_BGR2GRAY);
      //cv::imshow("bad", bad_gray);

      cv::Mat gray;
      if (original.channels() != 1) {
           Jet2Gray_matlab(original,gray);
      } else {
           gray = original.clone();
      }
      cv::imshow("Gray", gray);

      //cv::Mat ndt_img;
      //ndt_.set_frame(gray, ndt_img);
      //cv::imshow("ndt", ndt_img);

      // Compute median
      cv::Mat median;
      cv::medianBlur(gray, median,5);
      cv::imshow("median", median);

      /// // Compute estimated gradient
      /// cv::Mat grad;
      /// wb::gradient_sobel(median, grad);
      /// cv::imshow("gradient", grad);
      ///
      ///cv::Mat thresh_grad;
      ///wb::adaptive_threshold(grad, thresh_grad, grad_thresh_value_, 0.001, 0.002, 10, 5);
      /// cv::imshow("grad thresh", thresh_grad);

      cv::Mat thresh_amp;
#if 1
      wb::adaptive_threshold(median, thresh_amp, thresh_value_, 0.001, 0.002, 10, 5);

#else
      // TODO: For some reason, using this static threshold kills regular sonar
      // images, (vs. simulated sonar images), it might have to do with the
      // number of detected blobs Used for thresholding simulated sonar data
      // from Gazebo
      cv::threshold(median, thresh_amp, 100, 255, cv::THRESH_TOZERO);
#endif
      cv::imshow("thresh amp", thresh_amp);

      /// cv::Mat thresh_and_grad = thresh_amp + thresh_grad;
      /// cv::imshow("thresh and grad", thresh_and_grad);
      /// cv::Mat erode;
      /// cv::erode(thresh_amp, erode, erosionConfig_);
      /// cv::imshow("erode", erode);
      ///
      //cv::Mat dilate;
      /// cv::dilate(erode, dilate, dilationConfig_);
      /// cv::imshow("dilate", dilate);
      //dilate = thresh_amp;

      blob_process_.process_frame(thresh_amp, median, thresh_value_);

      cv::Mat blob_img;
      blob_process_.overlay_blobs(gray, blob_img);

      blob_process_.overlay_tracks(blob_img, blob_img);
      cv::imshow("Blobs", blob_img);

      //////////////////////////////////////////////////////////////
      /// Tracking
      ////////////////////////////////////////////////////
      tracks_.clear(); // clear out the tracks from previous loop

      std::vector<wb::Blob> blobs = blob_process_.blobs();
      std::vector<wb::Blob>::iterator it = blobs.begin();
      for (; it != blobs.end(); it++) {

           // Have to transform tracks from distorted cartesian
           // to polar, then to undistorted cartesian
           cv::Point p = it->estimated_centroid();

           double x, y;
           if (stream_->type() == syllo::SonarType) {
                double range = stream_->pixel_range(p.y, p.x); //row, col
                double bearing = stream_->pixel_bearing(p.y, p.x) * 0.017453293; // pi/180
                y = -range*cos(bearing);
                x = range*sin(bearing);
           } else {
                x = p.x;
                y = p.y;
           }

           //it->set_undistorted_centroid(cv::Point2f(p.x,p.y));
           it->set_undistorted_centroid(cv::Point2f(x,y));

           tracks_.push_back((wb::Entity)*it);
      }

      ///////////////////////////////////////////////////
      // Display images
      ///////////////////////////////////////////////////
      if (!hide_windows_) {
      }

     return 0;
}

extern "C" {
     Detector *maker(){
          return new RelativeDetector;
     }

     class proxy {
     public:
          proxy(){
               // register the maker with the factory
               // causes static initialization error plugin_manager_.factory["blank_detector"] = maker;
               plugin_manager_.factory["relative_detector"] = maker;
          }
     };
     // our one instance of the proxy
     proxy p;
}

/// Color map tests
///cv::Mat grad;
///create_gradient(grad, 100, 255);
///cv::imshow("gradient", grad);
///
///cv::Mat jet_matlab;
///Gray2Jet_matlab(grad,jet_matlab);
///cv::imshow("jet matlab", jet_matlab);
///
///cv::Mat gray_2;
///Jet2Gray_matlab(jet_matlab,gray_2);
///cv::imshow("gray_2",gray_2);
///
///cv::Mat diff = gray_2 - grad;
///cv::imshow("diff",diff);
///
///if (!equal(gray_2, grad)) {
///     cout << "Grays are unequal" << endl;
///}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: mapnik_python.cc 27 2005-03-30 21:45:40Z pavlenko $

#include <boost/python.hpp>
#include <boost/get_pointer.hpp>
#include <boost/python/detail/api_placeholder.hpp>
#include <boost/python/exception_translator.hpp>

void register_cairo();
void export_color();
void export_coord();
void export_layer();
void export_parameters();
void export_envelope();
void export_query();
void export_geometry();
void export_image();
void export_image_view();
void export_map();
void export_python();
void export_filter();
void export_rule();
void export_style();
void export_stroke();
void export_feature();
void export_featureset();
void export_datasource();
void export_datasource_cache();
void export_point_symbolizer();
void export_line_symbolizer();
void export_line_pattern_symbolizer();
void export_polygon_symbolizer();
void export_polygon_pattern_symbolizer();
void export_raster_symbolizer();
void export_text_symbolizer();
void export_shield_symbolizer();
void export_font_engine();
void export_projection();
void export_proj_transform();
void export_view_transform();

#include <mapnik/version.hpp>
#include <mapnik/map.hpp>
#include <mapnik/agg_renderer.hpp>
#ifdef HAVE_CAIRO
#include <mapnik/cairo_renderer.hpp>
#endif
#include <mapnik/graphics.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/save_map.hpp>

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h>
#endif

void render(const mapnik::Map& map,mapnik::Image32& image, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        mapnik::agg_renderer<mapnik::Image32> ren(map,image,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render2(const mapnik::Map& map,mapnik::Image32& image)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        mapnik::agg_renderer<mapnik::Image32> ren(map,image);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)

void render3(const mapnik::Map& map,PycairoSurface* surface, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
        mapnik::cairo_renderer<Cairo::Surface> ren(map,s,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render4(const mapnik::Map& map,PycairoSurface* surface)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
        mapnik::cairo_renderer<Cairo::Surface> ren(map,s);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render5(const mapnik::Map& map,PycairoContext* context, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
        mapnik::cairo_renderer<Cairo::Context> ren(map,c,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render6(const mapnik::Map& map,PycairoContext* context)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
        mapnik::cairo_renderer<Cairo::Context> ren(map,c);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

#endif

void render_tile_to_file(const mapnik::Map& map,
                         unsigned offset_x, unsigned offset_y,
                         unsigned width, unsigned height,
                         const std::string& file,
                         const std::string& format)
{
    mapnik::Image32 image(width,height);
    render(map,image,offset_x, offset_y);
    mapnik::save_to_file(image.data(),file,format);
}

void render_to_file1(const mapnik::Map& map,
                    const std::string& filename,
                    const std::string& format)
{
    mapnik::Image32 image(map.getWidth(),map.getHeight());
    render(map,image,0,0);
    mapnik::save_to_file(image,filename,format);
}

void render_to_file2(const mapnik::Map& map,
                    const std::string& filename)
{
    mapnik::Image32 image(map.getWidth(),map.getHeight());
    render(map,image,0,0);
    mapnik::save_to_file(image,filename);
}

double scale_denominator(mapnik::Map const &map, bool geographic)
{
    return mapnik::scale_denominator(map, geographic);
}

void translator(mapnik::config_error const & ex) {
    PyErr_SetString(PyExc_UserWarning, ex.what());
}

unsigned mapnik_version()
{
    return MAPNIK_VERSION;
}

BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_overloads, load_map, 2, 3);
BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_string_overloads, load_map_string, 2, 3);

BOOST_PYTHON_MODULE(_mapnik)
{

    using namespace boost::python;

    using mapnik::load_map;
    using mapnik::load_map_string;
    using mapnik::save_map;

    register_exception_translator<mapnik::config_error>(translator);
    register_cairo();
    export_query();
    export_geometry();
    export_feature();
    export_featureset();
    export_datasource();
    export_parameters();
    export_color();
    export_envelope();
    export_image();
    export_image_view();
    export_filter();
    export_rule();
    export_style();
    export_layer();
    export_stroke();
    export_datasource_cache();
    export_point_symbolizer();
    export_line_symbolizer();
    export_line_pattern_symbolizer();
    export_polygon_symbolizer();
    export_polygon_pattern_symbolizer();
    export_raster_symbolizer();
    export_text_symbolizer();
    export_shield_symbolizer();
    export_font_engine();
    export_projection();
    export_proj_transform();
    export_view_transform();
    export_coord();
    export_map();

    def("render_to_file",&render_to_file1,
        "\n"
        "Render Map to file using explicit image type\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render_to_file, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render_to_file(m,'image32bit.png','png')\n"
        "\n"
        "Format Options:\n"
        "\n"
        "8 bit (paletted) PNG can be requested with 'png256':\n"
        ">>> render_to_file(m,'image8bit.png','png256')\n"
        "JPEG quality can be controlled by adding a suffix to\n"
        "'jpeg' between 0 and 100 (default is 85):\n"
        ">>> render_to_file(m,'top_quality.jpeg','jpeg100')\n"
        ">>> render_to_file(m,'medium_quality.jpeg','jpeg50')\n"
        );

    def("render_to_file",&render_to_file2,
        "\n"
        "Render Map to file (type taken from file extension)\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render_to_file, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> render_to_file(m,'image.jpeg')\n"
        "\n"
        );

    def("render_tile_to_file",&render_tile_to_file,
        "\n"
        "TODO\n"
        "\n"
        );

    def("render",&render,
        "\n"
        "Render Map to an AGG Image32 using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, Image, render, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> im = Image(m.width,m.height)\n"
        ">>> render(m,im,1,1)\n"
        "\n"
        );

    def("render",&render2,
        "\n"
        "Render Map to an AGG Image32\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, Image, render, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> im = Image(m.width,m.height)\n"
        ">>> render(m,im)\n"
        "\n"
        );

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
    def("render",&render3,
        "\n"
        "Render Map to Cairo Surface using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> render(m,surface,1,1)\n"
        "\n"
        );

    def("render",&render4,
        "\n"
        "Render Map to Cairo Surface\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> render(m,surface)\n"
        "\n"
        );

    def("render",&render5,
        "\n"
        "Render Map to Cairo Context using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface, Context\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> ctx = Context(surface)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render(m,context,1,1)\n"
        "\n"
        );

    def("render",&render6,
        "\n"
        "Render Map to Cairo Context\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface, Context\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> ctx = Context(surface)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render(m,context)\n"
        "\n"
        );
#endif

    def("scale_denominator", &scale_denominator,
        "\n"
        "Return the Map Scale Denominator.\n"
        "Also available as Map.scale_denominator()\n"
        "\n"
        "Usage:\n"
        "\n"
        ">>> from mapnik import Map, Projection, scale_denominator, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> scale_denominator(m,Projection(m.srs).geographic)\n"
        "\n"
        );

    def("load_map", & load_map, load_map_overloads());

    def("load_map_from_string", & load_map_string, load_map_string_overloads());

    def("save_map", & save_map,
        "\n"
        "Save Map object to XML file\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, load_map, save_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile_wgs84.xml')\n"
        ">>> m.srs\n"
        "'+proj=latlong +datum=WGS84'\n"
        ">>> m.srs = '+init=espg:3395'\n"
        ">>> save_map(m,'mapfile_mercator.xml')\n"
        "\n"
        );

    def("mapnik_version", &mapnik_version,"Get the Mapnik version number");

    using mapnik::symbolizer;
    class_<symbolizer>("Symbolizer",no_init)
       ;

    register_ptr_to_python<mapnik::filter_ptr>();
}
<commit_msg>minor formatting to render_to_file docstring<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: mapnik_python.cc 27 2005-03-30 21:45:40Z pavlenko $

#include <boost/python.hpp>
#include <boost/get_pointer.hpp>
#include <boost/python/detail/api_placeholder.hpp>
#include <boost/python/exception_translator.hpp>

void register_cairo();
void export_color();
void export_coord();
void export_layer();
void export_parameters();
void export_envelope();
void export_query();
void export_geometry();
void export_image();
void export_image_view();
void export_map();
void export_python();
void export_filter();
void export_rule();
void export_style();
void export_stroke();
void export_feature();
void export_featureset();
void export_datasource();
void export_datasource_cache();
void export_point_symbolizer();
void export_line_symbolizer();
void export_line_pattern_symbolizer();
void export_polygon_symbolizer();
void export_polygon_pattern_symbolizer();
void export_raster_symbolizer();
void export_text_symbolizer();
void export_shield_symbolizer();
void export_font_engine();
void export_projection();
void export_proj_transform();
void export_view_transform();

#include <mapnik/version.hpp>
#include <mapnik/map.hpp>
#include <mapnik/agg_renderer.hpp>
#ifdef HAVE_CAIRO
#include <mapnik/cairo_renderer.hpp>
#endif
#include <mapnik/graphics.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/save_map.hpp>

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h>
#endif

void render(const mapnik::Map& map,mapnik::Image32& image, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        mapnik::agg_renderer<mapnik::Image32> ren(map,image,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render2(const mapnik::Map& map,mapnik::Image32& image)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        mapnik::agg_renderer<mapnik::Image32> ren(map,image);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)

void render3(const mapnik::Map& map,PycairoSurface* surface, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
        mapnik::cairo_renderer<Cairo::Surface> ren(map,s,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render4(const mapnik::Map& map,PycairoSurface* surface)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
        mapnik::cairo_renderer<Cairo::Surface> ren(map,s);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render5(const mapnik::Map& map,PycairoContext* context, unsigned offset_x = 0, unsigned offset_y = 0)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
        mapnik::cairo_renderer<Cairo::Context> ren(map,c,offset_x, offset_y);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

void render6(const mapnik::Map& map,PycairoContext* context)
{
    Py_BEGIN_ALLOW_THREADS
    try
    {
        Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
        mapnik::cairo_renderer<Cairo::Context> ren(map,c);
        ren.apply();
    }
    catch (...)
    {
        Py_BLOCK_THREADS
        throw;
    }
    Py_END_ALLOW_THREADS
}

#endif

void render_tile_to_file(const mapnik::Map& map,
                         unsigned offset_x, unsigned offset_y,
                         unsigned width, unsigned height,
                         const std::string& file,
                         const std::string& format)
{
    mapnik::Image32 image(width,height);
    render(map,image,offset_x, offset_y);
    mapnik::save_to_file(image.data(),file,format);
}

void render_to_file1(const mapnik::Map& map,
                    const std::string& filename,
                    const std::string& format)
{
    mapnik::Image32 image(map.getWidth(),map.getHeight());
    render(map,image,0,0);
    mapnik::save_to_file(image,filename,format);
}

void render_to_file2(const mapnik::Map& map,
                    const std::string& filename)
{
    mapnik::Image32 image(map.getWidth(),map.getHeight());
    render(map,image,0,0);
    mapnik::save_to_file(image,filename);
}

double scale_denominator(mapnik::Map const &map, bool geographic)
{
    return mapnik::scale_denominator(map, geographic);
}

void translator(mapnik::config_error const & ex) {
    PyErr_SetString(PyExc_UserWarning, ex.what());
}

unsigned mapnik_version()
{
    return MAPNIK_VERSION;
}

BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_overloads, load_map, 2, 3);
BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_string_overloads, load_map_string, 2, 3);

BOOST_PYTHON_MODULE(_mapnik)
{

    using namespace boost::python;

    using mapnik::load_map;
    using mapnik::load_map_string;
    using mapnik::save_map;

    register_exception_translator<mapnik::config_error>(translator);
    register_cairo();
    export_query();
    export_geometry();
    export_feature();
    export_featureset();
    export_datasource();
    export_parameters();
    export_color();
    export_envelope();
    export_image();
    export_image_view();
    export_filter();
    export_rule();
    export_style();
    export_layer();
    export_stroke();
    export_datasource_cache();
    export_point_symbolizer();
    export_line_symbolizer();
    export_line_pattern_symbolizer();
    export_polygon_symbolizer();
    export_polygon_pattern_symbolizer();
    export_raster_symbolizer();
    export_text_symbolizer();
    export_shield_symbolizer();
    export_font_engine();
    export_projection();
    export_proj_transform();
    export_view_transform();
    export_coord();
    export_map();

    def("render_to_file",&render_to_file1,
        "\n"
        "Render Map to file using explicit image type.\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render_to_file, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render_to_file(m,'image32bit.png','png')\n"
        "\n"
        "8 bit (paletted) PNG can be requested with 'png256':\n"
        ">>> render_to_file(m,'8bit_image.png','png256')\n"
        "\n"
        "JPEG quality can be controlled by adding a suffix to\n"
        "'jpeg' between 0 and 100 (default is 85):\n"
        ">>> render_to_file(m,'top_quality.jpeg','jpeg100')\n"
        ">>> render_to_file(m,'medium_quality.jpeg','jpeg50')\n"
        );

    def("render_to_file",&render_to_file2,
        "\n"
        "Render Map to file (type taken from file extension)\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render_to_file, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> render_to_file(m,'image.jpeg')\n"
        "\n"
        );

    def("render_tile_to_file",&render_tile_to_file,
        "\n"
        "TODO\n"
        "\n"
        );

    def("render",&render,
        "\n"
        "Render Map to an AGG Image32 using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, Image, render, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> im = Image(m.width,m.height)\n"
        ">>> render(m,im,1,1)\n"
        "\n"
        );

    def("render",&render2,
        "\n"
        "Render Map to an AGG Image32\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, Image, render, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> im = Image(m.width,m.height)\n"
        ">>> render(m,im)\n"
        "\n"
        );

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
    def("render",&render3,
        "\n"
        "Render Map to Cairo Surface using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> render(m,surface,1,1)\n"
        "\n"
        );

    def("render",&render4,
        "\n"
        "Render Map to Cairo Surface\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> render(m,surface)\n"
        "\n"
        );

    def("render",&render5,
        "\n"
        "Render Map to Cairo Context using offsets\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface, Context\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> ctx = Context(surface)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render(m,context,1,1)\n"
        "\n"
        );

    def("render",&render6,
        "\n"
        "Render Map to Cairo Context\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, render, load_map\n"
        ">>> from cairo import SVGSurface, Context\n"
        ">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
        ">>> ctx = Context(surface)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> render(m,context)\n"
        "\n"
        );
#endif

    def("scale_denominator", &scale_denominator,
        "\n"
        "Return the Map Scale Denominator.\n"
        "Also available as Map.scale_denominator()\n"
        "\n"
        "Usage:\n"
        "\n"
        ">>> from mapnik import Map, Projection, scale_denominator, load_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile.xml')\n"
        ">>> scale_denominator(m,Projection(m.srs).geographic)\n"
        "\n"
        );

    def("load_map", & load_map, load_map_overloads());

    def("load_map_from_string", & load_map_string, load_map_string_overloads());

    def("save_map", & save_map,
        "\n"
        "Save Map object to XML file\n"
        "\n"
        "Usage:\n"
        ">>> from mapnik import Map, load_map, save_map\n"
        ">>> m = Map(256,256)\n"
        ">>> load_map(m,'mapfile_wgs84.xml')\n"
        ">>> m.srs\n"
        "'+proj=latlong +datum=WGS84'\n"
        ">>> m.srs = '+init=espg:3395'\n"
        ">>> save_map(m,'mapfile_mercator.xml')\n"
        "\n"
        );

    def("mapnik_version", &mapnik_version,"Get the Mapnik version number");

    using mapnik::symbolizer;
    class_<symbolizer>("Symbolizer",no_init)
       ;

    register_ptr_to_python<mapnik::filter_ptr>();
}
<|endoftext|>