<commit_before>/*
UselessMine
    Copyright (C) 2013-2017 Vladimir "allejo" Jimenez

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

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

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <memory>
#include <stdlib.h>

#include "bzfsAPI.h"
#include "bztoolkit/bzToolkitAPI.h"

// Define plugin name
const std::string PLUGIN_NAME = "Useless Mine";

// Define plugin version numbering
const int MAJOR = 1;
const int MINOR = 1;
const int REV = 0;
const int BUILD = 52;

// A function to replace substrings in a string with another substring
std::string ReplaceString(std::string subject, const std::string& search, const std::string& replace)
{
    size_t pos = 0;

    while ((pos = subject.find(search, pos)) != std::string::npos)
    {
        subject.replace(pos, search.length(), replace);
        pos += replace.length();
    }

    return subject;
}

class UselessMine : public bz_Plugin, public bz_CustomSlashCommandHandler
{
public:
    virtual const char* Name ();
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);

    virtual bool SlashCommand (int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);

    // The information each mine will contain
    struct Mine
    {
        bz_ApiString uid;      // A unique ID for mine

        int owner;             // The owner of the mine
        int defuserID;         // The player who defused this mine
        int detonationID;      // The shot ID of the world weapon that exploded when this mine was defused/detonated
        float x, y, z;         // The coordinates of where the mine was placed
        bz_eTeamType team;     // The team of the mine owner
        bool defused;          // True if the mine was defused with a Bomb Defusal flag
        bool detonated;        // True if the mine was detonated by a player
        double detonationTime; // The time the mine was detonated

        Mine (int _owner, float _pos[3], bz_eTeamType _team) :
            owner(_owner),
            defuserID(-1),
            detonationID(-1),
            x(_pos[0]),
            y(_pos[1]),
            z(_pos[2]),
            team(_team),
            defused(false),
            detonated(false),
            detonationTime(-1)
        {
            uid.format("%d_%d", owner, bz_getCurrentTime());
        }

        // Should a given player trigger this mine?
        // This function checks mine ownership, team loyalty, and player's alive-ness
        bool canPlayerTriggerMine(bz_BasePlayerRecord *pr, float pos[3])
        {
            if (owner != pr->playerID && (pr->team == eRogueTeam || pr->team != team || bz_getGameType() == eOpenFFAGame) && pr->spawned)
            {
                float  playerPos[3] = {pos[0], pos[1], pos[2]};
                double shockRange   = bz_getBZDBDouble("_shockOutRadius") * 0.75;

                // Check if the player is in the detonation range
                bool inDetonationRange = ((playerPos[0] > x - shockRange && playerPos[0] < x + shockRange) &&
                                          (playerPos[1] > y - shockRange && playerPos[1] < y + shockRange) &&
                                          (playerPos[2] > z - shockRange && playerPos[2] < z + shockRange));

                return inDetonationRange;
            }

            return false;
        }

        bool defuse(int playerID)
        {
            if (bztk_isValidPlayerID(owner) && bz_getPlayerTeam(owner) != eObservers)
            {
                bz_BasePlayerRecord *pr = bz_getPlayerByIndex(owner);

                bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s defused", uid.c_str());

                defused = true;
                defuserID = playerID;
                detonationTime = bz_getCurrentTime();

                bz_fireWorldWep("SW", 2.0, BZ_SERVER, pr->lastKnownState.pos, 0, 0, 0, &detonationID, 0, bz_getPlayerTeam(playerID));

                bz_freePlayerRecord(pr);

                return true;
            }

            return false;
        }

        bool detonate()
        {
            // Check that the mine owner exists and is not an observer
            if (bztk_isValidPlayerID(owner) && bz_getPlayerTeam(owner) != eObservers)
            {
                float minePos[3] = {x, y, z};

                // Only detonate a mine once
                if (!detonated)
                {
                    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s detonated", uid.c_str());

                    detonated = true;
                    detonationTime = bz_getCurrentTime();

                    bz_fireWorldWep("SW", 2.0, BZ_SERVER, minePos, 0, 0, 0, &detonationID, 0, team);

                    return true;
                }
            }

            return false;
        }
    };

private:
    int  getMineCount (bool offset);
    void reloadDeathMessages (),
         removePlayerMines (int playerID),
         removeMine (Mine &mine),
         setMine (int owner, float pos[3], bz_eTeamType team);
    std::string formatDeathMessage (std::string msg, std::string victim, std::string owner);

    std::vector<std::string> deathMessages; // A vector that will store all of the witty death messages
    std::vector<Mine> activeMines; // A vector that will store all of the mines currently on the field
    std::string deathMessagesFile; // The path to the file containing death messages

    double playerSpawnTime[256]; // The time a player spawned last; used for _mineSafetyTime calculations
};

BZ_PLUGIN(UselessMine)

const char* UselessMine::Name (void)
{
    static std::string pluginName;

    if (pluginName.empty())
        pluginName = bztk_pluginName(PLUGIN_NAME, MAJOR, MINOR, REV, BUILD);

    return pluginName.c_str();
}

void UselessMine::Init (const char* commandLine)
{
    Register(bz_eFlagGrabbedEvent);
    Register(bz_ePlayerDieEvent);
    Register(bz_ePlayerPartEvent);
    Register(bz_ePlayerSpawnEvent);
    Register(bz_ePlayerUpdateEvent);

    bz_registerCustomSlashCommand("mine", this);
    bz_registerCustomSlashCommand("reload", this);

    bz_RegisterCustomFlag("BD", "Bomb Defusal", "Safely defuse enemy mines while killing the mine owners", 0, eGoodFlag);

    bztk_registerCustomDoubleBZDB("_mineSafetyTime", 5.0);

    // Save the location of the file so we can reload after
    deathMessagesFile = commandLine;

    reloadDeathMessages();

    if (deathMessages.empty())
    {
        bz_debugMessage(2, "WARNING :: Useless Mine :: No witty death messages were loaded");
    }
    else
    {
        bz_debugMessagef(2, "DEBUG :: Useless Mine :: %d witty messages were loaded", deathMessages.size());
    }
}

void UselessMine::Cleanup (void)
{
    Flush();

    bz_removeCustomSlashCommand("mine");
    bz_removeCustomSlashCommand("reload");
}

void UselessMine::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eFlagGrabbedEvent:
        {
            bz_FlagGrabbedEventData_V1* flagGrabData = (bz_FlagGrabbedEventData_V1*)eventData;

            // If the user grabbed the Useless flag, let them know they can place a mine
            if (strcmp(flagGrabData->flagType, "US") == 0)
            {
                bz_sendTextMessage(BZ_SERVER, flagGrabData->playerID, "You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
            }
        }
        break;

        case bz_ePlayerDieEvent:
        {
            bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData;

            int playerID = dieData->playerID;

            for (Mine &mine : activeMines)
            {
                // This isn't the mine we're looking for since it hasn't been touched
                if (!mine.detonated && !mine.defused)
                {
                    continue;
                }

                // If the shot IDs don't match, this mine wasn't the killer
                if (dieData->shotID != mine.detonationID)
                {
                    continue;
                }

                // Get the callsigns of the players
                const char* owner  = bz_getPlayerCallsign(mine.owner);
                const char* victim = bz_getPlayerCallsign(playerID);

                if (mine.detonated)
                {
                    dieData->killerID = mine.owner;

                    if (!deathMessages.empty() && playerID != mine.owner)
                    {
                        // The random number used to fetch a random taunting death message
                        int randomNumber = rand() % deathMessages.size();

                        // Get a random death message
                        std::string deathMessage = deathMessages.at(randomNumber);
                        bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, formatDeathMessage(deathMessage, victim, owner).c_str());
                    }
                }
                else if (mine.defused)
                {
                    dieData->killerID = mine.defuserID;

                    bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "%s successfully defused %s's mine! [%d]", bz_getPlayerCallsign(mine.defuserID), owner, getMineCount(true));
                }

                removeMine(mine);

                break;
            }
        }
        break;

        case bz_ePlayerPartEvent:
        {
            bz_PlayerJoinPartEventData_V1* partData = (bz_PlayerJoinPartEventData_V1*)eventData;

            int playerID = partData->playerID;

            // Remove all the mines belonging to the player who just left
            removePlayerMines(playerID);
            playerSpawnTime[playerID] = -1;
        }
        break;

        case bz_ePlayerSpawnEvent:
        {
            bz_PlayerSpawnEventData_V1* spawnData = (bz_PlayerSpawnEventData_V1*)eventData;

            int playerID = spawnData->playerID;

            // Save the time the player spawned last
            playerSpawnTime[playerID] = bz_getCurrentTime();
        }
        break;

        case bz_ePlayerUpdateEvent:
        {
            bz_PlayerUpdateEventData_V1* updateData = (bz_PlayerUpdateEventData_V1*)eventData;

            int playerID = updateData->playerID;
            bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);

            for (Mine &mine : activeMines)
            {
                bool bypassSafetyTime = (playerSpawnTime[pr->playerID] + bz_getBZDBDouble("_mineSafetyTime") <= bz_getCurrentTime());

                if (mine.canPlayerTriggerMine(pr, updateData->state.pos) && bypassSafetyTime)
                {
                    (pr->currentFlag == "Bomb Defusal (+BD)") ? mine.defuse(playerID) : mine.detonate();
                }
            }

            bz_freePlayerRecord(pr);
        }
        break;

        default:
            break;
    }
}

bool UselessMine::SlashCommand(int playerID, bz_ApiString command, bz_ApiString /*message*/, bz_APIStringList *params)
{
    if (command == "mine")
    {
        bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);

        if (pr->team != eObservers)
        {
            // Check if the player has the Useless flag
            if (pr->currentFlag == "USeless (+US)")
            {
                // Store their current position
                float currentPosition[3] = {pr->lastKnownState.pos[0], pr->lastKnownState.pos[1], pr->lastKnownState.pos[2]};

                setMine(playerID, currentPosition, pr->team);
            }
            else
            {
                bz_sendTextMessage(BZ_SERVER, playerID, "You can't place a mine without the Useless flag!");
            }
        }
        else
        {
            bz_sendTextMessage(BZ_SERVER, playerID, "Silly observer, you can't place a mine.");
        }

        bz_freePlayerRecord(pr);

        return true;
    }
    else if (command == "reload" && bz_hasPerm(playerID, "setAll"))
    {
        if (params->get(0) == "deathmessages")
        {
            reloadDeathMessages();
            bz_sendTextMessage(BZ_SERVER, playerID, "Death messages reloaded");
            return true;
        }
        else if (params->size() == 0)
        {
            reloadDeathMessages();
        }
    }

    return false;
}

// A function to format death messages in order to replace placeholders with callsigns and values
std::string UselessMine::formatDeathMessage(std::string msg, std::string victim, std::string owner)
{
    // Replace the %victim% and %owner% placeholders
    std::string formattedMessage = ReplaceString(ReplaceString(msg, "%victim%", victim), "%owner%", owner);

    // If the message has a %minecount%, then replace it
    if (formattedMessage.find("%minecount%") != std::string::npos)
    {
        formattedMessage = ReplaceString(formattedMessage, "%minecount%", std::to_string(getMineCount(true)));
    }

    return formattedMessage;
}

void UselessMine::reloadDeathMessages()
{
    deathMessages.clear();

    if (!deathMessagesFile.empty())
    {
        bztk_fileToVector(deathMessagesFile.c_str(), deathMessages);
    }
}

// Get the amount of active mines that exist
// Setting `offset` to true will subtract the current detonated/defused mine that's queued for removal
int UselessMine::getMineCount(bool offset = false)
{
    if (offset && activeMines.size() == 0)
    {
        return 0;
    }

    return (int)activeMines.size() - (offset ? 1 : 0);
}

// Remove a specific mine
void UselessMine::removeMine(Mine &mine)
{
    const char* uid = mine.uid.c_str();

    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Removing mine UID: %s", mine.uid.c_str());
    bz_debugMessagef(4, "DEBUG :: Useless Mine ::  mine count: %d", getMineCount());

    activeMines.erase(
        std::remove_if(
            activeMines.begin(),
            activeMines.end(),
            [uid](Mine &m) { return m.uid == uid; }
        ),
        activeMines.end()
    );

    bz_debugMessagef(4, "DEBUG :: Useless Mine ::  new mine count: %d", getMineCount());
}

// Remove all of the mines of a specific player
void UselessMine::removePlayerMines(int playerID)
{
    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Removing all mines for player %d", playerID);

    activeMines.erase(
        std::remove_if(
            activeMines.begin(),
            activeMines.end(),
            [playerID](Mine &m) { return m.owner == playerID; }
        ),
        activeMines.end()
    );
}

// A shortcut to set a mine
void UselessMine::setMine(int owner, float pos[3], bz_eTeamType team)
{
    // Remove their flag because they "converted" it into a mine
    bz_removePlayerFlag(owner);

    Mine newMine(owner, pos, team);

    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s created by %d", newMine.uid.c_str(), owner);
    bz_debugMessagef(4, "DEBUG :: Useless Mine ::   x, y, z => %0.2f, %0.2f, %0.2f", pos[0], pos[1], pos[2]);

    activeMines.push_back(newMine);
}
<commit_msg>Fix incorrect license header in source file<commit_after>/*
    Copyright (C) 2013-2017 Vladimir "allejo" Jimenez

    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 <algorithm>
#include <memory>
#include <stdlib.h>

#include "bzfsAPI.h"
#include "bztoolkit/bzToolkitAPI.h"

// Define plugin name
const std::string PLUGIN_NAME = "Useless Mine";

// Define plugin version numbering
const int MAJOR = 1;
const int MINOR = 1;
const int REV = 0;
const int BUILD = 59;

// A function to replace substrings in a string with another substring
std::string ReplaceString(std::string subject, const std::string& search, const std::string& replace)
{
    size_t pos = 0;

    while ((pos = subject.find(search, pos)) != std::string::npos)
    {
        subject.replace(pos, search.length(), replace);
        pos += replace.length();
    }

    return subject;
}

class UselessMine : public bz_Plugin, public bz_CustomSlashCommandHandler
{
public:
    virtual const char* Name ();
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);

    virtual bool SlashCommand (int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);

    // The information each mine will contain
    struct Mine
    {
        bz_ApiString uid;      // A unique ID for mine

        int owner;             // The owner of the mine
        int defuserID;         // The player who defused this mine
        int detonationID;      // The shot ID of the world weapon that exploded when this mine was defused/detonated
        float x, y, z;         // The coordinates of where the mine was placed
        bz_eTeamType team;     // The team of the mine owner
        bool defused;          // True if the mine was defused with a Bomb Defusal flag
        bool detonated;        // True if the mine was detonated by a player
        double detonationTime; // The time the mine was detonated

        Mine (int _owner, float _pos[3], bz_eTeamType _team) :
            owner(_owner),
            defuserID(-1),
            detonationID(-1),
            x(_pos[0]),
            y(_pos[1]),
            z(_pos[2]),
            team(_team),
            defused(false),
            detonated(false),
            detonationTime(-1)
        {
            uid.format("%d_%d", owner, bz_getCurrentTime());
        }

        // Should a given player trigger this mine?
        // This function checks mine ownership, team loyalty, and player's alive-ness
        bool canPlayerTriggerMine(bz_BasePlayerRecord *pr, float pos[3])
        {
            if (owner != pr->playerID && (pr->team == eRogueTeam || pr->team != team || bz_getGameType() == eOpenFFAGame) && pr->spawned)
            {
                float  playerPos[3] = {pos[0], pos[1], pos[2]};
                double shockRange   = bz_getBZDBDouble("_shockOutRadius") * 0.75;

                // Check if the player is in the detonation range
                bool inDetonationRange = ((playerPos[0] > x - shockRange && playerPos[0] < x + shockRange) &&
                                          (playerPos[1] > y - shockRange && playerPos[1] < y + shockRange) &&
                                          (playerPos[2] > z - shockRange && playerPos[2] < z + shockRange));

                return inDetonationRange;
            }

            return false;
        }

        bool defuse(int playerID)
        {
            if (bztk_isValidPlayerID(owner) && bz_getPlayerTeam(owner) != eObservers)
            {
                bz_BasePlayerRecord *pr = bz_getPlayerByIndex(owner);

                bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s defused", uid.c_str());

                defused = true;
                defuserID = playerID;
                detonationTime = bz_getCurrentTime();

                bz_fireWorldWep("SW", 2.0, BZ_SERVER, pr->lastKnownState.pos, 0, 0, 0, &detonationID, 0, bz_getPlayerTeam(playerID));

                bz_freePlayerRecord(pr);

                return true;
            }

            return false;
        }

        bool detonate()
        {
            // Check that the mine owner exists and is not an observer
            if (bztk_isValidPlayerID(owner) && bz_getPlayerTeam(owner) != eObservers)
            {
                float minePos[3] = {x, y, z};

                // Only detonate a mine once
                if (!detonated)
                {
                    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s detonated", uid.c_str());

                    detonated = true;
                    detonationTime = bz_getCurrentTime();

                    bz_fireWorldWep("SW", 2.0, BZ_SERVER, minePos, 0, 0, 0, &detonationID, 0, team);

                    return true;
                }
            }

            return false;
        }
    };

private:
    int  getMineCount (bool offset);
    void reloadDeathMessages (),
         removePlayerMines (int playerID),
         removeMine (Mine &mine),
         setMine (int owner, float pos[3], bz_eTeamType team);
    std::string formatDeathMessage (std::string msg, std::string victim, std::string owner);

    std::vector<std::string> deathMessages; // A vector that will store all of the witty death messages
    std::vector<Mine> activeMines; // A vector that will store all of the mines currently on the field
    std::string deathMessagesFile; // The path to the file containing death messages

    double playerSpawnTime[256]; // The time a player spawned last; used for _mineSafetyTime calculations
};

BZ_PLUGIN(UselessMine)

const char* UselessMine::Name (void)
{
    static std::string pluginName;

    if (pluginName.empty())
        pluginName = bztk_pluginName(PLUGIN_NAME, MAJOR, MINOR, REV, BUILD);

    return pluginName.c_str();
}

void UselessMine::Init (const char* commandLine)
{
    Register(bz_eFlagGrabbedEvent);
    Register(bz_ePlayerDieEvent);
    Register(bz_ePlayerPartEvent);
    Register(bz_ePlayerSpawnEvent);
    Register(bz_ePlayerUpdateEvent);

    bz_registerCustomSlashCommand("mine", this);
    bz_registerCustomSlashCommand("reload", this);

    bz_RegisterCustomFlag("BD", "Bomb Defusal", "Safely defuse enemy mines while killing the mine owners", 0, eGoodFlag);

    bztk_registerCustomDoubleBZDB("_mineSafetyTime", 5.0);

    // Save the location of the file so we can reload after
    deathMessagesFile = commandLine;

    reloadDeathMessages();

    if (deathMessages.empty())
    {
        bz_debugMessage(2, "WARNING :: Useless Mine :: No witty death messages were loaded");
    }
    else
    {
        bz_debugMessagef(2, "DEBUG :: Useless Mine :: %d witty messages were loaded", deathMessages.size());
    }
}

void UselessMine::Cleanup (void)
{
    Flush();

    bz_removeCustomSlashCommand("mine");
    bz_removeCustomSlashCommand("reload");
}

void UselessMine::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eFlagGrabbedEvent:
        {
            bz_FlagGrabbedEventData_V1* flagGrabData = (bz_FlagGrabbedEventData_V1*)eventData;

            // If the user grabbed the Useless flag, let them know they can place a mine
            if (strcmp(flagGrabData->flagType, "US") == 0)
            {
                bz_sendTextMessage(BZ_SERVER, flagGrabData->playerID, "You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
            }
        }
        break;

        case bz_ePlayerDieEvent:
        {
            bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData;

            int playerID = dieData->playerID;

            for (Mine &mine : activeMines)
            {
                // This isn't the mine we're looking for since it hasn't been touched
                if (!mine.detonated && !mine.defused)
                {
                    continue;
                }

                // If the shot IDs don't match, this mine wasn't the killer
                if (dieData->shotID != mine.detonationID)
                {
                    continue;
                }

                // Get the callsigns of the players
                const char* owner  = bz_getPlayerCallsign(mine.owner);
                const char* victim = bz_getPlayerCallsign(playerID);

                if (mine.detonated)
                {
                    dieData->killerID = mine.owner;

                    if (!deathMessages.empty() && playerID != mine.owner)
                    {
                        // The random number used to fetch a random taunting death message
                        int randomNumber = rand() % deathMessages.size();

                        // Get a random death message
                        std::string deathMessage = deathMessages.at(randomNumber);
                        bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, formatDeathMessage(deathMessage, victim, owner).c_str());
                    }
                }
                else if (mine.defused)
                {
                    dieData->killerID = mine.defuserID;

                    bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "%s successfully defused %s's mine! [%d]", bz_getPlayerCallsign(mine.defuserID), owner, getMineCount(true));
                }

                removeMine(mine);

                break;
            }
        }
        break;

        case bz_ePlayerPartEvent:
        {
            bz_PlayerJoinPartEventData_V1* partData = (bz_PlayerJoinPartEventData_V1*)eventData;

            int playerID = partData->playerID;

            // Remove all the mines belonging to the player who just left
            removePlayerMines(playerID);
            playerSpawnTime[playerID] = -1;
        }
        break;

        case bz_ePlayerSpawnEvent:
        {
            bz_PlayerSpawnEventData_V1* spawnData = (bz_PlayerSpawnEventData_V1*)eventData;

            int playerID = spawnData->playerID;

            // Save the time the player spawned last
            playerSpawnTime[playerID] = bz_getCurrentTime();
        }
        break;

        case bz_ePlayerUpdateEvent:
        {
            bz_PlayerUpdateEventData_V1* updateData = (bz_PlayerUpdateEventData_V1*)eventData;

            int playerID = updateData->playerID;
            bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);

            for (Mine &mine : activeMines)
            {
                bool bypassSafetyTime = (playerSpawnTime[pr->playerID] + bz_getBZDBDouble("_mineSafetyTime") <= bz_getCurrentTime());

                if (mine.canPlayerTriggerMine(pr, updateData->state.pos) && bypassSafetyTime)
                {
                    (pr->currentFlag == "Bomb Defusal (+BD)") ? mine.defuse(playerID) : mine.detonate();
                }
            }

            bz_freePlayerRecord(pr);
        }
        break;

        default:
            break;
    }
}

bool UselessMine::SlashCommand(int playerID, bz_ApiString command, bz_ApiString /*message*/, bz_APIStringList *params)
{
    if (command == "mine")
    {
        bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);

        if (pr->team != eObservers)
        {
            // Check if the player has the Useless flag
            if (pr->currentFlag == "USeless (+US)")
            {
                // Store their current position
                float currentPosition[3] = {pr->lastKnownState.pos[0], pr->lastKnownState.pos[1], pr->lastKnownState.pos[2]};

                setMine(playerID, currentPosition, pr->team);
            }
            else
            {
                bz_sendTextMessage(BZ_SERVER, playerID, "You can't place a mine without the Useless flag!");
            }
        }
        else
        {
            bz_sendTextMessage(BZ_SERVER, playerID, "Silly observer, you can't place a mine.");
        }

        bz_freePlayerRecord(pr);

        return true;
    }
    else if (command == "reload" && bz_hasPerm(playerID, "setAll"))
    {
        if (params->get(0) == "deathmessages")
        {
            reloadDeathMessages();
            bz_sendTextMessage(BZ_SERVER, playerID, "Death messages reloaded");
            return true;
        }
        else if (params->size() == 0)
        {
            reloadDeathMessages();
        }
    }

    return false;
}

// A function to format death messages in order to replace placeholders with callsigns and values
std::string UselessMine::formatDeathMessage(std::string msg, std::string victim, std::string owner)
{
    // Replace the %victim% and %owner% placeholders
    std::string formattedMessage = ReplaceString(ReplaceString(msg, "%victim%", victim), "%owner%", owner);

    // If the message has a %minecount%, then replace it
    if (formattedMessage.find("%minecount%") != std::string::npos)
    {
        formattedMessage = ReplaceString(formattedMessage, "%minecount%", std::to_string(getMineCount(true)));
    }

    return formattedMessage;
}

void UselessMine::reloadDeathMessages()
{
    deathMessages.clear();

    if (!deathMessagesFile.empty())
    {
        bztk_fileToVector(deathMessagesFile.c_str(), deathMessages);
    }
}

// Get the amount of active mines that exist
// Setting `offset` to true will subtract the current detonated/defused mine that's queued for removal
int UselessMine::getMineCount(bool offset = false)
{
    if (offset && activeMines.size() == 0)
    {
        return 0;
    }

    return (int)activeMines.size() - (offset ? 1 : 0);
}

// Remove a specific mine
void UselessMine::removeMine(Mine &mine)
{
    const char* uid = mine.uid.c_str();

    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Removing mine UID: %s", mine.uid.c_str());
    bz_debugMessagef(4, "DEBUG :: Useless Mine ::  mine count: %d", getMineCount());

    activeMines.erase(
        std::remove_if(
            activeMines.begin(),
            activeMines.end(),
            [uid](Mine &m) { return m.uid == uid; }
        ),
        activeMines.end()
    );

    bz_debugMessagef(4, "DEBUG :: Useless Mine ::  new mine count: %d", getMineCount());
}

// Remove all of the mines of a specific player
void UselessMine::removePlayerMines(int playerID)
{
    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Removing all mines for player %d", playerID);

    activeMines.erase(
        std::remove_if(
            activeMines.begin(),
            activeMines.end(),
            [playerID](Mine &m) { return m.owner == playerID; }
        ),
        activeMines.end()
    );
}

// A shortcut to set a mine
void UselessMine::setMine(int owner, float pos[3], bz_eTeamType team)
{
    // Remove their flag because they "converted" it into a mine
    bz_removePlayerFlag(owner);

    Mine newMine(owner, pos, team);

    bz_debugMessagef(4, "DEBUG :: Useless Mine :: Mine UID %s created by %d", newMine.uid.c_str(), owner);
    bz_debugMessagef(4, "DEBUG :: Useless Mine ::   x, y, z => %0.2f, %0.2f, %0.2f", pos[0], pos[1], pos[2]);

    activeMines.push_back(newMine);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: volume3d.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: ihi $ $Date: 2006-11-14 13:23:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _VOLUME3D_HXX
#include "volume3d.hxx"
#endif

#ifndef _BGFX_POLYGON_B3DPOLYGON_HXX
#include <basegfx/polygon/b3dpolygon.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

/*************************************************************************
|*
|* Konstruktor 1:                                               |
|* rPos: Zentrum oder minimale Koordinate links, unten, hinten  |__
|*       (abhaengig von bPosIsCenter)                          /
|*
\************************************************************************/

Volume3D::Volume3D(const basegfx::B3DPoint& rPos, const basegfx::B3DPoint& r3DSize, bool bPosIsCenter)
:   basegfx::B3DRange()
{
    if(bPosIsCenter)
    {
        expand(rPos - r3DSize / 2.0);
    }
    else
    {
        expand(rPos);
    }

    expand(getMinimum() + r3DSize);
}

Volume3D::Volume3D(const basegfx::B3DRange& rVol)
:   basegfx::B3DRange(rVol)
{
}

/*************************************************************************
|*
|* Konstruktor 2 - leeres Volumen, Werte als ungueltig markieren
|*
\************************************************************************/

Volume3D::Volume3D()
:   basegfx::B3DRange()
{
}

/*************************************************************************
|*
|* Transformation des Volumens berechnen und als neues Volumen
|* zurueckgeben
|*
\************************************************************************/

Volume3D Volume3D::GetTransformVolume(const basegfx::B3DHomMatrix& rTfMatrix) const
{
    Volume3D aTfVol;

    if(!isEmpty())
    {
        basegfx::B3DPoint aTfVec;
        Vol3DPointIterator aIter(*this, &rTfMatrix);

        while(aIter.Next(aTfVec))
        {
            aTfVol.expand(aTfVec);
        }
    }
    return aTfVol;
}

/*************************************************************************
|*
|* Drahtgitter-Linien fuer das Volumen berechnen und in rPoly3D ablegen
|*
\************************************************************************/

void Volume3D::CreateWireframe(basegfx::B3DPolygon& rPoly3D, const basegfx::B3DHomMatrix* pTf) const
{
    if(isEmpty())
        return;

    basegfx::B3DVector aDiff(getRange());
    basegfx::B3DPolygon aVolPnts;
    sal_uInt32 nZeroCnt(0L);

    // Alle Punkte holen
    Vol3DPointIterator aIter(*this, pTf);
    basegfx::B3DPoint aTfVec;

    while(aIter.Next(aTfVec))
    {
        aVolPnts.append(aTfVec);
    }

    // 0-Ausmasse des BoundVolumes zaehlen
    if(0.0 == aDiff.getX())
        nZeroCnt++;
    if(0.0 == aDiff.getY())
        nZeroCnt++;
    if(0.0 == aDiff.getZ())
        nZeroCnt++;

    // Die drei Ecksegemente des Volumens mit je drei Linien ausgeben;
    // falls Koordinatenanteile 0 sind, nicht alle Segmente verwenden,
    // um das gegenseitige Ausloeschen bei XOR-Ausgabe zu verhindern
    //   4
    //   |     Dieses Segment immer
    //   |
    //   0---1
    //  /
    // 3
    // Die Liniensegmente eines Segments werden immer in der Reihenfolge
    // X-, Y- und dann Z-Richtung ausgegeben (gilt natuerlich nur fuer
    // untransformierte Koordinaten)

    rPoly3D.append(aVolPnts.getB3DPoint(0));

    if(nZeroCnt < 3L)
    {
        // wenn keine Ausdehnung, dann nur den ersten Punkt einfuegen
        rPoly3D.append(aVolPnts.getB3DPoint(1L));
        rPoly3D.append(aVolPnts.getB3DPoint(0L));
        rPoly3D.append(aVolPnts.getB3DPoint(4L));
        rPoly3D.append(aVolPnts.getB3DPoint(0L));
        rPoly3D.append(aVolPnts.getB3DPoint(3L));
    }
    if(nZeroCnt < 2L)
    {
        if(nZeroCnt == 0L || aDiff.getX() == 0.0)
        {
            //   4
            //  /
            // 7---6
            // |
            // |
            // 3
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(3L));
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(4L));
        }
        if(nZeroCnt == 0L || (aDiff.getY() == 0.0))
        {
            //     6
            //     | 1
            //     |/
            // 3---2
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(3L));
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(1L));
        }
        if(nZeroCnt == 0L || (aDiff.getZ() == 0.0))
        {
            //   4---5
            //      /|
            //     6 |
            //       1
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(4L));
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(1L));
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
        }
    }
}

/*************************************************************************
|*
|* Konstruktor des Point-Iterators
|*
\************************************************************************/

Vol3DPointIterator::Vol3DPointIterator(const basegfx::B3DRange& rVol, const basegfx::B3DHomMatrix* pTf)
:   rVolume(rVol),
    pTransform(pTf),
    nIndex(0)
{
    DBG_ASSERT(!rVol.isEmpty(), "Vol3DPointIterator-Aufruf mit ungueltigem Volume3D!");
    a3DExtent = rVolume.getMaximum() - rVolume.getMinimum();
}

/*************************************************************************
|*
|* Gibt die einzelnen Punkte des (ggf. transformierten) Volumens zurueck
|*
|*    4---5  -> Reihenfolge der Punktausgabe (untransformiert)
|*   /|  /|
|*  7---6 |
|*  | 0-|-1
|*  |/  |/
|*  3---2
|*
\************************************************************************/

bool Vol3DPointIterator::Next(basegfx::B3DPoint& rVec)
{
    if(nIndex > 7)
    {
        return false;
    }
    else
    {
        rVec = rVolume.getMinimum();

        if(nIndex >= 4)
        {
            rVec.setY(rVec.getY() + a3DExtent.getY());
        }

        switch(nIndex)
        {
            case 6:
            case 2: rVec.setZ(rVec.getZ() + a3DExtent.getZ());
            case 5:
            case 1: rVec.setX(rVec.getX() + a3DExtent.getX());
                    break;
            case 7:
            case 3: rVec.setZ(rVec.getZ() + a3DExtent.getZ());
                    break;
        }
        nIndex++;

        if(pTransform)
        {
            rVec *= *pTransform;
        }

        return true;
    }
}

// eof
<commit_msg>INTEGRATION: CWS vgbugs07 (1.4.256); FILE MERGED 2007/06/04 13:26:53 vg 1.4.256.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: volume3d.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 18:07:20 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _VOLUME3D_HXX
#include <svx/volume3d.hxx>
#endif

#ifndef _BGFX_POLYGON_B3DPOLYGON_HXX
#include <basegfx/polygon/b3dpolygon.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

/*************************************************************************
|*
|* Konstruktor 1:                                               |
|* rPos: Zentrum oder minimale Koordinate links, unten, hinten  |__
|*       (abhaengig von bPosIsCenter)                          /
|*
\************************************************************************/

Volume3D::Volume3D(const basegfx::B3DPoint& rPos, const basegfx::B3DPoint& r3DSize, bool bPosIsCenter)
:   basegfx::B3DRange()
{
    if(bPosIsCenter)
    {
        expand(rPos - r3DSize / 2.0);
    }
    else
    {
        expand(rPos);
    }

    expand(getMinimum() + r3DSize);
}

Volume3D::Volume3D(const basegfx::B3DRange& rVol)
:   basegfx::B3DRange(rVol)
{
}

/*************************************************************************
|*
|* Konstruktor 2 - leeres Volumen, Werte als ungueltig markieren
|*
\************************************************************************/

Volume3D::Volume3D()
:   basegfx::B3DRange()
{
}

/*************************************************************************
|*
|* Transformation des Volumens berechnen und als neues Volumen
|* zurueckgeben
|*
\************************************************************************/

Volume3D Volume3D::GetTransformVolume(const basegfx::B3DHomMatrix& rTfMatrix) const
{
    Volume3D aTfVol;

    if(!isEmpty())
    {
        basegfx::B3DPoint aTfVec;
        Vol3DPointIterator aIter(*this, &rTfMatrix);

        while(aIter.Next(aTfVec))
        {
            aTfVol.expand(aTfVec);
        }
    }
    return aTfVol;
}

/*************************************************************************
|*
|* Drahtgitter-Linien fuer das Volumen berechnen und in rPoly3D ablegen
|*
\************************************************************************/

void Volume3D::CreateWireframe(basegfx::B3DPolygon& rPoly3D, const basegfx::B3DHomMatrix* pTf) const
{
    if(isEmpty())
        return;

    basegfx::B3DVector aDiff(getRange());
    basegfx::B3DPolygon aVolPnts;
    sal_uInt32 nZeroCnt(0L);

    // Alle Punkte holen
    Vol3DPointIterator aIter(*this, pTf);
    basegfx::B3DPoint aTfVec;

    while(aIter.Next(aTfVec))
    {
        aVolPnts.append(aTfVec);
    }

    // 0-Ausmasse des BoundVolumes zaehlen
    if(0.0 == aDiff.getX())
        nZeroCnt++;
    if(0.0 == aDiff.getY())
        nZeroCnt++;
    if(0.0 == aDiff.getZ())
        nZeroCnt++;

    // Die drei Ecksegemente des Volumens mit je drei Linien ausgeben;
    // falls Koordinatenanteile 0 sind, nicht alle Segmente verwenden,
    // um das gegenseitige Ausloeschen bei XOR-Ausgabe zu verhindern
    //   4
    //   |     Dieses Segment immer
    //   |
    //   0---1
    //  /
    // 3
    // Die Liniensegmente eines Segments werden immer in der Reihenfolge
    // X-, Y- und dann Z-Richtung ausgegeben (gilt natuerlich nur fuer
    // untransformierte Koordinaten)

    rPoly3D.append(aVolPnts.getB3DPoint(0));

    if(nZeroCnt < 3L)
    {
        // wenn keine Ausdehnung, dann nur den ersten Punkt einfuegen
        rPoly3D.append(aVolPnts.getB3DPoint(1L));
        rPoly3D.append(aVolPnts.getB3DPoint(0L));
        rPoly3D.append(aVolPnts.getB3DPoint(4L));
        rPoly3D.append(aVolPnts.getB3DPoint(0L));
        rPoly3D.append(aVolPnts.getB3DPoint(3L));
    }
    if(nZeroCnt < 2L)
    {
        if(nZeroCnt == 0L || aDiff.getX() == 0.0)
        {
            //   4
            //  /
            // 7---6
            // |
            // |
            // 3
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(3L));
            rPoly3D.append(aVolPnts.getB3DPoint(7L));
            rPoly3D.append(aVolPnts.getB3DPoint(4L));
        }
        if(nZeroCnt == 0L || (aDiff.getY() == 0.0))
        {
            //     6
            //     | 1
            //     |/
            // 3---2
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(3L));
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
            rPoly3D.append(aVolPnts.getB3DPoint(2L));
            rPoly3D.append(aVolPnts.getB3DPoint(1L));
        }
        if(nZeroCnt == 0L || (aDiff.getZ() == 0.0))
        {
            //   4---5
            //      /|
            //     6 |
            //       1
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(4L));
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(1L));
            rPoly3D.append(aVolPnts.getB3DPoint(5L));
            rPoly3D.append(aVolPnts.getB3DPoint(6L));
        }
    }
}

/*************************************************************************
|*
|* Konstruktor des Point-Iterators
|*
\************************************************************************/

Vol3DPointIterator::Vol3DPointIterator(const basegfx::B3DRange& rVol, const basegfx::B3DHomMatrix* pTf)
:   rVolume(rVol),
    pTransform(pTf),
    nIndex(0)
{
    DBG_ASSERT(!rVol.isEmpty(), "Vol3DPointIterator-Aufruf mit ungueltigem Volume3D!");
    a3DExtent = rVolume.getMaximum() - rVolume.getMinimum();
}

/*************************************************************************
|*
|* Gibt die einzelnen Punkte des (ggf. transformierten) Volumens zurueck
|*
|*    4---5  -> Reihenfolge der Punktausgabe (untransformiert)
|*   /|  /|
|*  7---6 |
|*  | 0-|-1
|*  |/  |/
|*  3---2
|*
\************************************************************************/

bool Vol3DPointIterator::Next(basegfx::B3DPoint& rVec)
{
    if(nIndex > 7)
    {
        return false;
    }
    else
    {
        rVec = rVolume.getMinimum();

        if(nIndex >= 4)
        {
            rVec.setY(rVec.getY() + a3DExtent.getY());
        }

        switch(nIndex)
        {
            case 6:
            case 2: rVec.setZ(rVec.getZ() + a3DExtent.getZ());
            case 5:
            case 1: rVec.setX(rVec.getX() + a3DExtent.getX());
                    break;
            case 7:
            case 3: rVec.setZ(rVec.getZ() + a3DExtent.getZ());
                    break;
        }
        nIndex++;

        if(pTransform)
        {
            rVec *= *pTransform;
        }

        return true;
    }
}

// eof
<|endoftext|>


<commit_before>#include "mandelbrot.hpp"

int iter_for_point(const std::complex<double> &c, const int MAX_ITER) {

    const double abs_c = abs(c - 0.25);
    if (abs_c * 2 < 1 - (real(c) - 0.25) / abs_c) {
        return MAX_ITER;
    }

    int i = 1;
    std::complex<double> z_i = c;
    double sqr_abs = pow(real(z_i), 2) + pow(imag(z_i), 2);

    while ((i < MAX_ITER) && (sqr_abs < 4)) {
        std::complex<double> sqr = z_i * z_i;
        z_i = sqr + c;
        ++i;
        sqr_abs = pow(real(z_i), 2) + pow(imag(z_i), 2);
    }

    return i;
}

double norm_iter_for_point(const double Re, const double Im, const int MAX_ITER) {

    std::complex<double> z(Re, Im);
    return static_cast<double>(iter_for_point(z, MAX_ITER)) / MAX_ITER;
}

void painting(const double x1, const double x2,
        const double y1, const double y2,
        const int32_t width, const int32_t height,
        const char* file_name, const bool progress_bar) {

    cimg_library::CImg<unsigned char> img(width, height, 1, 3);

    const double dy = (y2 - y1) / height;
    const double dx = (x2 - x1) / width;

    const size_t horiz_steps = 60;
    const size_t line_for_one_step = width / horiz_steps * 4 / 3;
    const double pr_bar_dx = (x2 - x1) / horiz_steps;

    double y = y2;

    for (int32_t i = 0; i < height; ++i) {
        double x = x1;

        if (progress_bar && ((i + 1) % line_for_one_step == 0)) {
            double pr_bar_x = x1;
            for (size_t j = 0; j < horiz_steps; ++j) {
                if (norm_iter_for_point(pr_bar_x, y) > 0.95)
                     { std::cout << '#'; }
                else { std::cout << ' '; }
                pr_bar_x += pr_bar_dx;
            }
            std::cout << std::endl;
        }

        for (int32_t j = 0; j < width; ++j) {
            const double norm_pnt = norm_iter_for_point(x, y);
            x += dx;

            const double clr = pow(1 - norm_pnt, 3);
            const unsigned char color = (unsigned char)(clr * 255);
            img(j, i, 0) = color;           //red
            img(j, i, 1) = color;           //green
            img(j, i, 2) = color;           //blue

        }

        y -= dy;
    }

    img.save_png(file_name);
}<commit_msg>Optimization (added check circle)<commit_after>#include "mandelbrot.hpp"

int iter_for_point(const std::complex<double> &c, const int MAX_ITER) {

    const double abs_c = abs(c - 0.25);
    if (abs_c * 2 < 1 - (real(c) - 0.25) / abs_c) {
        return MAX_ITER;
    }
    if (real(c + 1.) * real(c + 1.) + imag(c) * imag(c) < 1/16.) {
        return MAX_ITER;
    }

    int i = 1;
    std::complex<double> z_i = c;
    double sqr_abs = pow(real(z_i), 2) + pow(imag(z_i), 2);

    while ((i < MAX_ITER) && (sqr_abs < 4)) {
        std::complex<double> sqr = z_i * z_i;
        z_i = sqr + c;
        ++i;
        sqr_abs = pow(real(z_i), 2) + pow(imag(z_i), 2);
    }

    return i;
}

double norm_iter_for_point(const double Re, const double Im, const int MAX_ITER) {

    std::complex<double> z(Re, Im);
    return static_cast<double>(iter_for_point(z, MAX_ITER)) / MAX_ITER;
}

void painting(const double x1, const double x2,
        const double y1, const double y2,
        const int32_t width, const int32_t height,
        const char* file_name, const bool progress_bar) {

    cimg_library::CImg<unsigned char> img(width, height, 1, 3);

    const double dy = (y2 - y1) / height;
    const double dx = (x2 - x1) / width;

    const size_t horiz_steps = 60;
    const size_t line_for_one_step = width / horiz_steps * 4 / 3;
    const double pr_bar_dx = (x2 - x1) / horiz_steps;

    double y = y2;

    for (int32_t i = 0; i < height; ++i) {
        double x = x1;

        if (progress_bar && ((i + 1) % line_for_one_step == 0)) {
            double pr_bar_x = x1;
            for (size_t j = 0; j < horiz_steps; ++j) {
                if (norm_iter_for_point(pr_bar_x, y) > 0.95)
                     { std::cout << '#'; }
                else { std::cout << ' '; }
                pr_bar_x += pr_bar_dx;
            }
            std::cout << std::endl;
        }

        for (int32_t j = 0; j < width; ++j) {
            const double norm_pnt = norm_iter_for_point(x, y);
            x += dx;

            const double clr = pow(1 - norm_pnt, 3);
            const unsigned char color = (unsigned char)(clr * 255);
            img(j, i, 0) = color;           //red
            img(j, i, 1) = color;           //green
            img(j, i, 2) = color;           //blue

        }

        y -= dy;
    }

    img.save_png(file_name);
}<|endoftext|>


<commit_before>#include <stdio.h>
#include <sys/select.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <dlfcn.h>
#include "nvml_stub.h"

typedef nvmlReturn_t (*nvml_void)(void);
typedef nvmlReturn_t (*nvml_dghbi)(unsigned int, nvmlDevice_t *);
typedef nvmlReturn_t (*nvml_unsigned_int)(unsigned int *);
typedef nvmlReturn_t (*nvml_dgs)( nvmlDevice_t, nvmlSamplingType_t, unsigned long long, nvmlValueType_t *, unsigned int *, nvmlSample_t * );
typedef const char * (*cc_nvml)( nvmlReturn_t );

nvml_dgs nvmlDeviceGetSamples = NULL;
nvml_unsigned_int nvmlDeviceGetCount = NULL;
nvml_dghbi nvmlDeviceGetHandleByIndex = NULL;
cc_nvml nvmlErrorString = NULL;

unsigned debug = 0;
unsigned reportInterval = 10;

int compareSamples( const void * vpA, const void * vpB ) {
	const nvmlSample_t * a = (const nvmlSample_t *)vpA;
	const nvmlSample_t * b = (const nvmlSample_t *)vpB;
	if( a->timeStamp < b->timeStamp ) {
		return -1;
	} else if( a->timeStamp == b->timeStamp ) {
		return 0;
	} else {
		return 1;
	}
}

void fail() {
	fprintf( stderr, "Hanging to prevent process churn.\n" );
	while( 1 ) { sleep( 1204 ); }
}

nvmlReturn_t getElapsedTimeForDevice( nvmlDevice_t d, unsigned long long * lastSample, unsigned long long * elapsedTime, unsigned maxSampleCount ) {
	if( elapsedTime == NULL || lastSample == NULL ) {
		return NVML_ERROR_INVALID_ARGUMENT;
	}

	unsigned sampleCount = maxSampleCount;
	nvmlSample_t samples[maxSampleCount];
	nvmlValueType_t sampleValueType;

	nvmlReturn_t r = nvmlDeviceGetSamples( d, NVML_GPU_UTILIZATION_SAMPLES, * lastSample, & sampleValueType, & sampleCount, samples );
	switch( r ) {
		case NVML_ERROR_NOT_FOUND:
			return NVML_SUCCESS;
		case NVML_SUCCESS:
			break;
		default:
			return r;
	}

	// Samples are usually but not always in order.
	qsort( samples, sampleCount, sizeof( nvmlSample_t ), compareSamples );

	// Convert the percentage to elapsed time, since that's what we
	// actually care about (and the data representation is simpler).
	if( (*lastSample) == 0 && sampleCount > 0 ) {
		(*lastSample) = samples[0].timeStamp;
	}
	for( unsigned i = 0; i < sampleCount; ++i ) {
		/* debug fprintf( stderr, "%llu + (%llu - %llu) * %f = ",
			* elapsedTime, samples[i].timeStamp, * lastSample,
			(double)(samples[i].sampleValue.uiVal)/100.0 ); */

		(*elapsedTime) += (unsigned long long)(
			(samples[i].timeStamp - (*lastSample)) *
			((double)(samples[i].sampleValue.uiVal)/100.0)
		);

		/* debug fprintf( stderr, "%llu\n", * elapsedTime ); */

		(*lastSample) = samples[i].timeStamp;
	}

	return NVML_SUCCESS;
}

// int main( int argc, char ** argv ) {
int main() {
	nvml_void nvmlInit = NULL;
	nvml_void nvmlShutdown = NULL;

	void * nvml_handle = NULL;

	const char * nvml_library = "libnvidia-ml.so";
	nvml_handle = dlopen( nvml_library, RTLD_LAZY );
	if(! nvml_handle) {
		fprintf( stderr, "Unable to load %s, aborting.\n", nvml_library );
		fail();
	}
	dlerror();

	nvmlInit		           = (nvml_void)dlsym( nvml_handle, "nvmlInit" );
	nvmlShutdown	           = (nvml_void)dlsym( nvml_handle, "nvmlShutdown" );
	nvmlDeviceGetSamples       = (nvml_dgs)dlsym( nvml_handle, "nvmlDeviceGetSamples" );
	nvmlDeviceGetCount         = (nvml_unsigned_int)dlsym( nvml_handle, "nvmlDeviceGetCount" );
	nvmlDeviceGetHandleByIndex = (nvml_dghbi)dlsym( nvml_handle, "nvmlDeviceGetHandleByIndex" );
	nvmlErrorString            = (cc_nvml)dlsym( nvml_handle, "nvmlErrorString" );

	nvmlReturn_t r = nvmlInit();
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlInit() failed, aborting.\n" );
		fail();
	}

	unsigned int deviceCount;
	r = nvmlDeviceGetCount( &deviceCount );
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlDeviceGetCount() failed, aborting.\n" );
		fail();
	}
	if( deviceCount <= 0 ) {
		fprintf( stderr, "Found 0 or fewer devices, aborting.\n" );
		fail();
	}

	nvmlDevice_t devices[deviceCount];
	unsigned maxSampleCounts[deviceCount];
	unsigned long long lastSamples[deviceCount];
	unsigned long long firstSamples[deviceCount];
	unsigned long long elapsedTimes[deviceCount];
	for( unsigned i = 0; i < deviceCount; ++i ) {
		r = nvmlDeviceGetHandleByIndex( i, &(devices[i]) );
		if( r != NVML_SUCCESS ) {
			fprintf( stderr, "nvmlGetDeviceHandleByIndex(%u) failed (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
			fail();
		}

		lastSamples[i] = 0;
		firstSamples[i] = 0;
		elapsedTimes[i] = 0;

		nvmlValueType_t sampleValueType;
		r = nvmlDeviceGetSamples( devices[i], NVML_GPU_UTILIZATION_SAMPLES, 0, & sampleValueType, & maxSampleCounts[i], NULL );
		if( r != NVML_SUCCESS ) {
			fprintf( stderr, "nvmlDeviceGetSamples(%u) failed while querying for the max sample count (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
			fail();
		}
		if( sampleValueType != NVML_VALUE_TYPE_UNSIGNED_INT ) {
			fprintf( stderr, "nvmlDeviceGetSamples(%u) returned an unexpected type (%d) of sample when querying for the max sample count, aborting.\n", i, sampleValueType );
			fail();
		}
	}

	// We deliberately ignore the first set of samples.  Partly, I think we
	// can claim that they're from before we started monitoring.  More
	// importantly, at least on a Tesla K40c (driver 384.81), initializing
	// the NVML library causes a one-second 99% usage spike on an other-
	// wise idle GPU.  So we'll ignore as much of that as we easily can.
	for( unsigned i = 0; i < deviceCount; ++i ) {
		r = getElapsedTimeForDevice( devices[i], &lastSamples[i], &elapsedTimes[i], maxSampleCounts[i] );
		firstSamples[i] = lastSamples[i];
		elapsedTimes[i] = 0;
	}

	time_t lastReport = time( NULL );
	while( 1 ) {
		usleep( 100000 );

		for( unsigned i = 0; i < deviceCount; ++i ) {
			r = getElapsedTimeForDevice( devices[i], &lastSamples[i], &elapsedTimes[i], maxSampleCounts[i] );
			if( r != NVML_SUCCESS ) {
				fprintf( stderr, "getElapsedTimeForDevice(%u) failed (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
				fail();
			}

			if( debug ) {
				fprintf( stdout, "device %u: %llu / %llu = %u%%.\n",
					i, elapsedTimes[i], lastSamples[i] - firstSamples[i],
					(unsigned)(((double)elapsedTimes[i]) / (lastSamples[i] - firstSamples[i]) * 100)
				);
			}
		}

		if( time( NULL ) - lastReport >= reportInterval ) {
			for( unsigned i = 0; i < deviceCount; ++i ) {
				fprintf( stdout, "SlotMergeConstraint = StringListMember( \"CUDA%u\", AssignedGPUs )\n", i );
				fprintf( stdout, "UptimeGPUsSeconds = %.6f\n", elapsedTimes[i] / 1000000.0 );
				fprintf( stdout, "- GPUsSlot%u\n", i );
				fflush( stdout );

				// Report only the usage for each reporting period.
				elapsedTimes[i] = 0;
				firstSamples[i] = lastSamples[i];
			}
			lastReport = time( NULL );
		}
	}

	r = nvmlShutdown();
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlShutdown() failed (%d: %s), aborting.\n", r, nvmlErrorString( r ) );
		return 1;
	}

	dlclose( nvml_handle );
	return 0;
}
<commit_msg>Fix small coverity kvetches #6345<commit_after>#include <stdio.h>
#include <sys/select.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <dlfcn.h>
#include "nvml_stub.h"

typedef nvmlReturn_t (*nvml_void)(void);
typedef nvmlReturn_t (*nvml_dghbi)(unsigned int, nvmlDevice_t *);
typedef nvmlReturn_t (*nvml_unsigned_int)(unsigned int *);
typedef nvmlReturn_t (*nvml_dgs)( nvmlDevice_t, nvmlSamplingType_t, unsigned long long, nvmlValueType_t *, unsigned int *, nvmlSample_t * );
typedef const char * (*cc_nvml)( nvmlReturn_t );

nvml_dgs nvmlDeviceGetSamples = NULL;
nvml_unsigned_int nvmlDeviceGetCount = NULL;
nvml_dghbi nvmlDeviceGetHandleByIndex = NULL;
cc_nvml nvmlErrorString = NULL;

unsigned debug = 0;
unsigned reportInterval = 10;

int compareSamples( const void * vpA, const void * vpB ) {
	const nvmlSample_t * a = (const nvmlSample_t *)vpA;
	const nvmlSample_t * b = (const nvmlSample_t *)vpB;
	if( a->timeStamp < b->timeStamp ) {
		return -1;
	} else if( a->timeStamp == b->timeStamp ) {
		return 0;
	} else {
		return 1;
	}
}

void fail() __attribute__((__noreturn__));

void fail() {
	fprintf( stderr, "Hanging to prevent process churn.\n" );
	while( 1 ) { sleep( 1204 ); }
}

nvmlReturn_t getElapsedTimeForDevice( nvmlDevice_t d, unsigned long long * lastSample, unsigned long long * elapsedTime, unsigned maxSampleCount ) {
	if( elapsedTime == NULL || lastSample == NULL ) {
		return NVML_ERROR_INVALID_ARGUMENT;
	}

	unsigned sampleCount = maxSampleCount;
	nvmlSample_t samples[maxSampleCount];
	nvmlValueType_t sampleValueType;

	nvmlReturn_t r = nvmlDeviceGetSamples( d, NVML_GPU_UTILIZATION_SAMPLES, * lastSample, & sampleValueType, & sampleCount, samples );
	switch( r ) {
		case NVML_ERROR_NOT_FOUND:
			return NVML_SUCCESS;
		case NVML_SUCCESS:
			break;
		default:
			return r;
	}

	// Samples are usually but not always in order.
	qsort( samples, sampleCount, sizeof( nvmlSample_t ), compareSamples );

	// Convert the percentage to elapsed time, since that's what we
	// actually care about (and the data representation is simpler).
	if( (*lastSample) == 0 && sampleCount > 0 ) {
		(*lastSample) = samples[0].timeStamp;
	}
	for( unsigned i = 0; i < sampleCount; ++i ) {
		/* debug fprintf( stderr, "%llu + (%llu - %llu) * %f = ",
			* elapsedTime, samples[i].timeStamp, * lastSample,
			(double)(samples[i].sampleValue.uiVal)/100.0 ); */

		(*elapsedTime) += (unsigned long long)(
			(samples[i].timeStamp - (*lastSample)) *
			((double)(samples[i].sampleValue.uiVal)/100.0)
		);

		/* debug fprintf( stderr, "%llu\n", * elapsedTime ); */

		(*lastSample) = samples[i].timeStamp;
	}

	return NVML_SUCCESS;
}

// int main( int argc, char ** argv ) {
int main() {
	nvml_void nvmlInit = NULL;
	nvml_void nvmlShutdown = NULL;

	void * nvml_handle = NULL;

	const char * nvml_library = "libnvidia-ml.so";
	nvml_handle = dlopen( nvml_library, RTLD_LAZY );
	if(! nvml_handle) {
		fprintf( stderr, "Unable to load %s, aborting.\n", nvml_library );
		fail();
	}
	dlerror();

	nvmlInit		           = (nvml_void)dlsym( nvml_handle, "nvmlInit" );
	nvmlShutdown	           = (nvml_void)dlsym( nvml_handle, "nvmlShutdown" );
	nvmlDeviceGetSamples       = (nvml_dgs)dlsym( nvml_handle, "nvmlDeviceGetSamples" );
	nvmlDeviceGetCount         = (nvml_unsigned_int)dlsym( nvml_handle, "nvmlDeviceGetCount" );
	nvmlDeviceGetHandleByIndex = (nvml_dghbi)dlsym( nvml_handle, "nvmlDeviceGetHandleByIndex" );
	nvmlErrorString            = (cc_nvml)dlsym( nvml_handle, "nvmlErrorString" );

	nvmlReturn_t r = nvmlInit();
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlInit() failed, aborting.\n" );
		fail();
	}

	unsigned int deviceCount;
	r = nvmlDeviceGetCount( &deviceCount );
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlDeviceGetCount() failed, aborting.\n" );
		fail();
	}
	if( deviceCount <= 0 ) {
		fprintf( stderr, "Found 0 or fewer devices, aborting.\n" );
		fail();
	}

	nvmlDevice_t devices[deviceCount];
	unsigned maxSampleCounts[deviceCount];
	unsigned long long lastSamples[deviceCount];
	unsigned long long firstSamples[deviceCount];
	unsigned long long elapsedTimes[deviceCount];
	for( unsigned i = 0; i < deviceCount; ++i ) {
		r = nvmlDeviceGetHandleByIndex( i, &(devices[i]) );
		if( r != NVML_SUCCESS ) {
			fprintf( stderr, "nvmlGetDeviceHandleByIndex(%u) failed (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
			fail();
		}

		lastSamples[i] = 0;
		firstSamples[i] = 0;
		elapsedTimes[i] = 0;

		nvmlValueType_t sampleValueType;
		r = nvmlDeviceGetSamples( devices[i], NVML_GPU_UTILIZATION_SAMPLES, 0, & sampleValueType, & maxSampleCounts[i], NULL );
		if( r != NVML_SUCCESS ) {
			fprintf( stderr, "nvmlDeviceGetSamples(%u) failed while querying for the max sample count (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
			fail();
		}
		if( sampleValueType != NVML_VALUE_TYPE_UNSIGNED_INT ) {
			fprintf( stderr, "nvmlDeviceGetSamples(%u) returned an unexpected type (%d) of sample when querying for the max sample count, aborting.\n", i, sampleValueType );
			fail();
		}
	}

	// We deliberately ignore the first set of samples.  Partly, I think we
	// can claim that they're from before we started monitoring.  More
	// importantly, at least on a Tesla K40c (driver 384.81), initializing
	// the NVML library causes a one-second 99% usage spike on an other-
	// wise idle GPU.  So we'll ignore as much of that as we easily can.
	for( unsigned i = 0; i < deviceCount; ++i ) {
		getElapsedTimeForDevice( devices[i], &lastSamples[i], &elapsedTimes[i], maxSampleCounts[i] );
		firstSamples[i] = lastSamples[i];
		elapsedTimes[i] = 0;
	}

	time_t lastReport = time( NULL );
	while( 1 ) {
		usleep( 100000 );

		for( unsigned i = 0; i < deviceCount; ++i ) {
			r = getElapsedTimeForDevice( devices[i], &lastSamples[i], &elapsedTimes[i], maxSampleCounts[i] );
			if( r != NVML_SUCCESS ) {
				fprintf( stderr, "getElapsedTimeForDevice(%u) failed (%d: %s), aborting.\n", i, r, nvmlErrorString( r ) );
				fail();
			}

			if( debug ) {
				fprintf( stdout, "device %u: %llu / %llu = %u%%.\n",
					i, elapsedTimes[i], lastSamples[i] - firstSamples[i],
					(unsigned)(((double)elapsedTimes[i]) / (lastSamples[i] - firstSamples[i]) * 100)
				);
			}
		}

		if( time( NULL ) - lastReport >= reportInterval ) {
			for( unsigned i = 0; i < deviceCount; ++i ) {
				fprintf( stdout, "SlotMergeConstraint = StringListMember( \"CUDA%u\", AssignedGPUs )\n", i );
				fprintf( stdout, "UptimeGPUsSeconds = %.6f\n", elapsedTimes[i] / 1000000.0 );
				fprintf( stdout, "- GPUsSlot%u\n", i );
				fflush( stdout );

				// Report only the usage for each reporting period.
				elapsedTimes[i] = 0;
				firstSamples[i] = lastSamples[i];
			}
			lastReport = time( NULL );
		}
	}

	r = nvmlShutdown();
	if( r != NVML_SUCCESS ) {
		fprintf( stderr, "nvmlShutdown() failed (%d: %s), aborting.\n", r, nvmlErrorString( r ) );
		return 1;
	}

	dlclose( nvml_handle );
	return 0;
}
<|endoftext|>


<commit_before>#include "robot.hpp"
#include "console.hpp"
#include "commands.hpp"
#include "logger.hpp"
#include "radio.hpp"

Ticker lifeLight;
DigitalOut ledOne(LED1);
DigitalOut ledTwo(LED2);

DigitalOut led(p20, 0);

/*
 * some forward declarations to make the code easier to read
 */
void imAlive(void);
void setISRPriorities(void);
void initRadioThread(void);
void initConsoleRoutine(void);

void writeByte(DigitalInOut*, char);
char readByte(DigitalInOut* pin);
unsigned int crc8_add(unsigned int acc, char b);

const int tREC = 5;
const int tSLOT = 65;
const int tRSTLmin = 480;
const int tRSTLmax = 640;
const int tRSTLavg = 540;
const int tPDHmin = 15;
const int tPDHmax = 60;
const int tPDHavg = 35;
const int tPDLmin = 60;
const int tPDLmax = 240;
const int tPDLavg = 150;
const int tFPD = 8;
const int tMSPmin = 60;
const int tMSPmax = 75;
const int tMSPavg = 68;
const int tRSTH = 480;
const int tW0Lmin = 60;
const int tW0Lmax = 120;
const int tW0Lavg = 90;
const int tW1Lmin = 5;
const int tW1Lmax = 15;
const int tW1Lavg = 10;
const int tRLmin = 5;
const int tRLmax = 15;
const int tRLavg = 6;
const int tMSR = 15;

/**
 * system entry point
 */
int main(void)
{
	setISRPriorities();
	lifeLight.attach(&imAlive, 0.25);

	DigitalInOut idPin(p21, PIN_OUTPUT, PullUp, 1);

	printf("\033[2J");
	printf("Communicating with ID Chip...\r\n");

	// Reset signal, low for 480us
	idPin = 0;
	wait_us(tRSTLavg); // Trstl
	idPin = 1;

	// wait for presence response
	wait_us(tMSPavg); // Tmsp
	idPin.input();
	if(idPin == 0) {
		wait_us(tRSTH - tMSPavg); // wait for rest of tRSTH

		writeByte(&idPin, 0x33);

		char family = readByte(&idPin);

		char serial[6];
		for(int i = 0; i < 6; i++)
			serial[i] = readByte(&idPin);

		char crc = readByte(&idPin);

		printf("Family byte  : 0x%x\r\n", family);

		printf("Serial byte  : 0x");
		for(int i = 5; i >= 0; i--)
			printf("%x", serial[i]);

		printf("\r\nCRC          : 0x%x \r\n", crc);

		unsigned int calcCRC = crc8_add(0x0, family);
		for(int i = 0; i < 6; i++)
			calcCRC = crc8_add(calcCRC, serial[i]);

		printf("CRCs match?  : %d\r\n", calcCRC == crc);

		for(int i = 0; i < 17; i++)
			printf("\n");

		while(1) {
			led = !led;
			wait(1.0);
		}
	}
	else {
		printf("Failure :(\r\n");
		while(1) {
			led = !led;
			wait(0.5);
		}
	}

	isLogging = true;
	rjLogLevel = INF2;

	//initRadioThread();
	initConsoleRoutine();
}

void writeOne(DigitalInOut* pin) {
	*pin = 0;
	wait_us(tW1Lavg);
	*pin = 1;
	wait_us(tSLOT);
}

void writeZero(DigitalInOut* pin) {
	*pin = 0;
	wait_us(tW0Lavg);
	*pin = 1;
	wait_us(tREC);
}

void writeByte(DigitalInOut* pin, char b) {
	pin->output();

	for(uint i = 1; i < 256; i <<= 1) {
		if((b & i) == i)
			writeOne(pin);
		else
			writeZero(pin);
	}

	printf("Sent         : 0x%x\r\n", b);
}

char readByte(DigitalInOut* pin) {
	char value = 0;
	for(int i = 0; i < 8; i++) {
		pin->output();
		*pin = 0;
		wait_us(tRLavg);
		*pin = 1;

		wait_us(tMSR - tRLavg);
		pin->input();

		int bit = *pin;
		value |= bit << i;

		wait_us(tSLOT - tMSR);
	}

	return value;
}

unsigned int crc8_add(unsigned int acc, char byte) {
	acc ^= byte;

	for(int i = 0; i < 8; i++) {
		if(acc & 1) {
			acc = (acc >> 1) ^ 0x8c;
		}
		else {
			acc >>= 1;
		}
	}

	return acc;
}

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
	//set two bits for preemptive data, two bits for priority as the
	//structure for the IPRs. Grouping is global withing the IPRs so
	//this value should only be changed here.
	NVIC_SetPriorityGrouping(5);
	uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

	//set preemptive priority default to 2 (0..3)
	//set priority default to 1 (0..3)
	uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

	//When the kernel initialzes the PNVIC, all ISRs are set to the
	//highest priority, making it impossible to elevate a few over
	//the rest, so the default priority is lowered globally for the
	//table first.
	//
	//Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
	//specific
	for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
	{
		//set default priority
		NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);
	}

	////////////////////////////////////
	//  begin raise priority section  //
	////////////////////////////////////

	//reestablish watchdog
	NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

	//TODO raise radio
	//TODO raise others after discussion

	////////////////////////////////////
	//  begin lower priotity section  //
	////////////////////////////////////

	//set UART (console) interrupts to minimal priority
	//when debugging radio and other time sensitive operations, this
	//interrupt will need to be deferred, especially given the number of
	//calls to printf()
	NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 0));
	NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

	//TODO lower others after discussion

	//NVIC_EnableIRQ(TIMER0_IRQn);
	//NVIC_EnableIRQ(TIMER1_IRQn);
	//NVIC_EnableIRQ(TIMER2_IRQn);
	//NVIC_EnableIRQ(TIMER3_IRQn);
}

/**
 * initializes the radio communications thread
 */
void initRadioThread(void)
{
	initRadio();
}

/**
 * initializes the console
 */
void initConsoleRoutine(void)
{
	if (!COMPETITION_DEPLOY)
	{
		initConsole();

		for (;;)
		{
			//check console communications, currently does nothing
			//then execute any active iterative command
			conComCheck();
			//execute any active iterative command
			executeIterativeCommand();

			//check if a system stop is requested
			if (isSysStopReq() == true)
			{
				break;
			}

			//main loop heartbeat
			wait(0.1);
			ledTwo = !ledTwo;
	    	}

		//clear light for main loop (shows its complete)
		ledTwo = false;
	}
	else
	{
		for (;;);
	}
}

/**
 * timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive()
{
	ledOne = !ledOne;
}
<commit_msg>Edited robot2015's cpu's main.cpp to use DS2411 driver.<commit_after>#include "robot.hpp"
#include "console.hpp"
#include "commands.hpp"
#include "logger.hpp"
#include "radio.hpp"
#include "ds2411.hpp"

Ticker lifeLight;
DigitalOut ledOne(LED1);
DigitalOut ledTwo(LED2);

DigitalOut led(p20, 0);

/*
 * some forward declarations to make the code easier to read
 */
void imAlive(void);
void setISRPriorities(void);
void initRadioThread(void);
void initConsoleRoutine(void);

/**
 * system entry point
 */
int main(void)
{
	setISRPriorities();
	lifeLight.attach(&imAlive, 0.25);

	DigitalInOut idPin(p21, PIN_OUTPUT, PullUp, 1);

	printf("\033[2J");
	printf("Communicating with ID Chip...\r\n");

	DS2411_ID id;
	DS2411_Result result = ds2411_read_id(&idPin, &id);

	float waitTime;
	if(result == HANDSHAKE_FAIL) {
		printf("Handshake failure!\r\n");
		waitTime = 0.5;
	}
	else {
		printf("Family byte  : 0x%02X\r\n", id.family);

		printf("Serial byte  : 0x");
		for(int i = 5; i >= 0; i--)
			printf("%02X", id.serial[i]);

		printf("\r\nCRC          : 0x%02X \r\n", id.crc);

		printf("CRCs match?  : %d\r\n", result == CRC_MATCH);

		for(int i = 0; i < 18; i++)
			printf("\n");

		waitTime = result == CRC_MATCH ? 1.0 : 0.5;
	}

	while(1) {
		led = !led;
		wait(waitTime);
	}

	isLogging = true;
	rjLogLevel = INF2;

	//initRadioThread();
	initConsoleRoutine();
}

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
	//set two bits for preemptive data, two bits for priority as the
	//structure for the IPRs. Grouping is global withing the IPRs so
	//this value should only be changed here.
	NVIC_SetPriorityGrouping(5);
	uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

	//set preemptive priority default to 2 (0..3)
	//set priority default to 1 (0..3)
	uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

	//When the kernel initialzes the PNVIC, all ISRs are set to the
	//highest priority, making it impossible to elevate a few over
	//the rest, so the default priority is lowered globally for the
	//table first.
	//
	//Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
	//specific
	for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
	{
		//set default priority
		NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);
	}

	////////////////////////////////////
	//  begin raise priority section  //
	////////////////////////////////////

	//reestablish watchdog
	NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

	//TODO raise radio
	//TODO raise others after discussion

	////////////////////////////////////
	//  begin lower priotity section  //
	////////////////////////////////////

	//set UART (console) interrupts to minimal priority
	//when debugging radio and other time sensitive operations, this
	//interrupt will need to be deferred, especially given the number of
	//calls to printf()
	NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 0));
	NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

	//TODO lower others after discussion

	//NVIC_EnableIRQ(TIMER0_IRQn);
	//NVIC_EnableIRQ(TIMER1_IRQn);
	//NVIC_EnableIRQ(TIMER2_IRQn);
	//NVIC_EnableIRQ(TIMER3_IRQn);
}

/**
 * initializes the radio communications thread
 */
void initRadioThread(void)
{
	initRadio();
}

/**
 * initializes the console
 */
void initConsoleRoutine(void)
{
	if (!COMPETITION_DEPLOY)
	{
		initConsole();

		for (;;)
		{
			//check console communications, currently does nothing
			//then execute any active iterative command
			conComCheck();
			//execute any active iterative command
			executeIterativeCommand();

			//check if a system stop is requested
			if (isSysStopReq() == true)
			{
				break;
			}

			//main loop heartbeat
			wait(0.1);
			ledTwo = !ledTwo;
	    	}

		//clear light for main loop (shows its complete)
		ledTwo = false;
	}
	else
	{
		for (;;);
	}
}

/**
 * timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive()
{
	ledOne = !ledOne;
}
<|endoftext|>


<commit_before>#include "util/bitmap.h"
#include "gui/widget.h"
#include <math.h>
#include "globals.h"
#include "util/token.h"
#include "gui/coordinate.h"

using namespace Gui;

static const double S_PI = 3.14159265358979323846;
static const double DEG_TO_RAD = 180.0/S_PI;
static const double RAD_TO_DEG = S_PI/180.0;

static void round_double (double dbl_to_round , int &rounded_num) {
		rounded_num = static_cast<int>(dbl_to_round);
		if ((dbl_to_round - static_cast<double>(rounded_num)) >= 0.5) {rounded_num++;}
	}

//! min (borrowed from allegro)
static inline int Min(int x, int y){ return (((x) < (y)) ? (x) : (y)); }

//! max (borrowed from allegro)
static inline int Max(int x, int y){ return (((x) > (y)) ? (x) : (y)); }

//! mid (borrowed from allegro)
static inline int Mid(int x,int y,int z){ return (Max((x), Min((y), (z)))); }

Widget::Widget() : workArea(0)
{
	// Nothing yet
}

Widget::Widget( const Widget & w ){
	this->location = w.location;
	this->workArea = w.workArea;
}

Widget::~Widget(){
	if ( workArea ){
		delete workArea;
	}
}

// copy
Widget &Widget::operator=( const Widget &copy){
	location = copy.location;
	workArea = copy.workArea;

	return *this;
}

void Widget::setCoordinates(Token * token){
    if ( *token == "position" ){
        int x, y, width, height;
        *token >> x >> y >> width >> height;
        AbsolutePoint pos(x, y);
        AbsolutePoint dimensions(x + width, y + height);
        location.setPosition(pos);
        location.setDimensions(dimensions);
    } else if ( *token == "relative-position" ){
        double x1, y1, x2, y2;
        *token >> x1 >> y1 >> x2 >> y2;
        RelativePoint pos(x1,y1);
        RelativePoint dimensions(x2,y2);
        location = Coordinate(pos, dimensions);
    } else if ( *token == "coordinate" ){
        Token * tok;
        *token >> tok;
        while (tok->hasTokens()){
            Token * coordToken;
            *tok >> coordToken;
            if (*coordToken == "absolute"){
                int x, y, width, height;
                *coordToken >> x >> y >> width >> height;
                AbsolutePoint pos(x, y);
                AbsolutePoint dimensions(x + width, y + height);
                location = Coordinate(pos, dimensions);
            } else if (*coordToken == "relative"){
                double x1, y1, x2, y2;
                *coordToken >> x1 >> y1 >> x2 >> y2;
                RelativePoint pos(x1,y1);
                RelativePoint dimensions(x2,y2);
                location = Coordinate(pos, dimensions);
            } else if (*coordToken == "radius"){
                double radius;
                *coordToken >> radius;
                location.setRadius(radius);
            } else if (*coordToken == "z"){
                double z;
                *coordToken >> z;
                location.setZ(z);
            }
        }
    }
}

void Widget::setColors(Token * token){
    if ( *token == "position-body" ) {
        // This handles the body color of the widget
        int r,g,b;
        *token >> r >> g >> b >> colors.bodyAlpha;
        colors.body = Bitmap::makeColor(r,g,b);
    } else if ( *token == "position-border" ) {
        // This handles the border color of the widget
        int r,g,b;
        *token >> r >> g >> b >> colors.borderAlpha;
        colors.border = Bitmap::makeColor(r,g,b);
    }
}

void Widget::arc( const Bitmap & work, int x, int y, double startAngle, int radius, int color )
{
	int q = 0;// for counters
	double d_q = 0.0;// for percentage of loop completed
	double d_q_plus_one = 0.0;

	const double d_angular_length_deg = 0.030;
	const double d_start_angle_rad = startAngle*DEG_TO_RAD;
	const double d_angular_length_rad = d_angular_length_deg*DEG_TO_RAD;
	const double d_arc_distance_between_points = 0.25*pow(2.0 , static_cast<double>(10) / 10.0);
	double d_angular_length_rad_per_segment = 0.0;

	double arc_length = radius*d_angular_length_rad;
	if (arc_length < 0.0) {arc_length *= -1.0;}
	const double d_num_segments = arc_length / d_arc_distance_between_points;

	int num_segments = 0;
	round_double(d_num_segments , num_segments);

	if (num_segments == 0) {num_segments += 1;} // need at least one segment (two points)
	const int num_points = num_segments + 1;
	const double d_num_points_minus_one = static_cast<double>(num_points - 1);

	int arc_point_x;//[num_points];
	int arc_point_y;//[num_points];
	int arc_point2_x;//[num_points];
	int arc_point2_y;//[num_points];
	double d_arc_point_x = 0.0;
	double d_arc_point_y = 0.0;
	double d_arc_point2_x = 0.0;
	double d_arc_point2_y = 0.0;

	double current_angle_rad = 0.0;
	double current_angle2_rad = 0.0;

	if (d_arc_distance_between_points <= 1.0) {
		for (q = 0 ; q < num_points ; q++) {
			d_q = static_cast<double>(q);
			current_angle_rad = d_start_angle_rad + (d_q / d_num_points_minus_one)*d_angular_length_rad;
			d_arc_point_x = x + radius*cos(current_angle_rad);
			d_arc_point_y = y + radius*sin(current_angle_rad);

			round_double(d_arc_point_x , arc_point_x);
			round_double(d_arc_point_y , arc_point_y);

			work.putPixel(arc_point_x,arc_point_y,color);
		}
	}
	if (d_arc_distance_between_points > 1.0) {

		d_angular_length_rad_per_segment = d_angular_length_rad / d_num_points_minus_one;
		for (q = 0 ; q < num_segments ; q++) {
			d_q = static_cast<double>(q);
			d_q_plus_one = static_cast<double>(q + 1);

			current_angle_rad = d_start_angle_rad + d_q*d_angular_length_rad_per_segment;
			current_angle2_rad = d_start_angle_rad + d_q_plus_one*d_angular_length_rad_per_segment;

			d_arc_point_x = x + radius*cos(current_angle_rad);
			d_arc_point_y = y + radius*sin(current_angle_rad);

			round_double(d_arc_point_x , arc_point_x);
			round_double(d_arc_point_y , arc_point_y);

			d_arc_point2_x = x + radius*cos(current_angle2_rad);
			d_arc_point2_y = y + radius*sin(current_angle2_rad);

			round_double(d_arc_point2_x , arc_point2_x);
			round_double(d_arc_point2_y , arc_point2_y);

			work.line(arc_point_x,arc_point_y, arc_point2_x, arc_point2_y,color);
		}
	}
}

void Widget::roundRect( const Bitmap & work, int radius, int x1, int y1, int x2, int y2, int color )
{

	const int width = x2 - x1;
	const int height = y2 - y1;
	radius = Mid(0, radius, Min((x1+width - x1)/2, (y1+height - y1)/2));
	work.line(x1+radius, y1, x1+width-radius, y1, color);
	work.line(x1+radius, y1+height, x1+width-radius,y1+height, color);
	work.line(x1, y1+radius,x1, y1+height-radius, color);
	work.line(x1+width, y1+radius,x1+width, y1+height-radius, color);
	arc(work, x1+radius, y1+radius, S_PI-1.115, radius, color);
	arc(work, x1+radius + (width - radius *2), y1+radius, -S_PI/2 +0.116, radius, color);
	arc(work, x1+width-radius, y1+height-radius, -0.110, radius ,color);
	arc(work, x1+radius, y1+height-radius, S_PI/2-0.119, radius, color);

}

void Widget::roundRectFill( const Bitmap & work, int radius, int x1, int y1, int x2, int y2, int color )
{
	const int width = x2 - x1;
	const int height = y2 - y1;
	radius = Mid(0, radius, Min((x1+width - x1)/2, (y1+height - y1)/2));
	work.circleFill(x1+radius, y1+radius, radius, color);
	work.circleFill((x1+width)-radius, y1+radius, radius, color);
	work.circleFill(x1+radius, (y1+height)-radius, radius, color);
	work.circleFill((x1+width)-radius, (y1+height)-radius, radius, color);
	work.rectangleFill( x1+radius, y1, x2-radius, y1+radius, color);
	work.rectangleFill( x1, y1+radius, x2, y2-radius, color);
	work.rectangleFill( x1+radius, y2-radius, x2-radius, y2, color);
}

void Widget::checkWorkArea()
{

    if ( ! workArea ){
		workArea = new Bitmap(location.getWidth(),location.getHeight());
	} else if(location.getWidth() < workArea->getWidth() || location.getHeight() < workArea->getHeight()) {
		delete workArea;
		workArea = new Bitmap(location.getWidth(), location.getHeight());
	} else if(location.getWidth() > workArea->getWidth() || location.getHeight() > workArea->getHeight()) {
		delete workArea;
		workArea = new Bitmap(location.getWidth(),location.getHeight());
	}
	if ( workArea ){
		workArea->fill(Bitmap::makeColor(255,0,255));
	}
}
<commit_msg>Fix parsing of coordinate token.<commit_after>#include "util/bitmap.h"
#include "gui/widget.h"
#include <math.h>
#include "globals.h"
#include "util/token.h"
#include "gui/coordinate.h"

using namespace Gui;

static const double S_PI = 3.14159265358979323846;
static const double DEG_TO_RAD = 180.0/S_PI;
static const double RAD_TO_DEG = S_PI/180.0;

static void round_double (double dbl_to_round , int &rounded_num) {
		rounded_num = static_cast<int>(dbl_to_round);
		if ((dbl_to_round - static_cast<double>(rounded_num)) >= 0.5) {rounded_num++;}
	}

//! min (borrowed from allegro)
static inline int Min(int x, int y){ return (((x) < (y)) ? (x) : (y)); }

//! max (borrowed from allegro)
static inline int Max(int x, int y){ return (((x) > (y)) ? (x) : (y)); }

//! mid (borrowed from allegro)
static inline int Mid(int x,int y,int z){ return (Max((x), Min((y), (z)))); }

Widget::Widget() : workArea(0)
{
	// Nothing yet
}

Widget::Widget( const Widget & w ){
	this->location = w.location;
	this->workArea = w.workArea;
}

Widget::~Widget(){
	if ( workArea ){
		delete workArea;
	}
}

// copy
Widget &Widget::operator=( const Widget &copy){
	location = copy.location;
	workArea = copy.workArea;

	return *this;
}

void Widget::setCoordinates(Token * token){
    if ( *token == "position" ){
        int x, y, width, height;
        *token >> x >> y >> width >> height;
        AbsolutePoint pos(x, y);
        AbsolutePoint dimensions(x + width, y + height);
        location.setPosition(pos);
        location.setDimensions(dimensions);
    } else if ( *token == "relative-position" ){
        double x1, y1, x2, y2;
        *token >> x1 >> y1 >> x2 >> y2;
        RelativePoint pos(x1,y1);
        RelativePoint dimensions(x2,y2);
        location = Coordinate(pos, dimensions);
    } else if ( *token == "coordinate" ){
        while (token->hasTokens()){
            Token * coordToken;
            *token >> coordToken;
            if (*coordToken == "absolute"){
                int x, y, width, height;
                *coordToken >> x >> y >> width >> height;
                AbsolutePoint pos(x, y);
                AbsolutePoint dimensions(x + width, y + height);
                location = Coordinate(pos, dimensions);
            } else if (*coordToken == "relative"){
                double x1, y1, x2, y2;
                *coordToken >> x1 >> y1 >> x2 >> y2;
                RelativePoint pos(x1,y1);
                RelativePoint dimensions(x2,y2);
                location = Coordinate(pos, dimensions);
            } else if (*coordToken == "radius"){
                double radius;
                *coordToken >> radius;
                location.setRadius(radius);
            } else if (*coordToken == "z"){
                double z;
                *coordToken >> z;
                location.setZ(z);
            }
        }
    }
}

void Widget::setColors(Token * token){
    if ( *token == "position-body" ) {
        // This handles the body color of the widget
        int r,g,b;
        *token >> r >> g >> b >> colors.bodyAlpha;
        colors.body = Bitmap::makeColor(r,g,b);
    } else if ( *token == "position-border" ) {
        // This handles the border color of the widget
        int r,g,b;
        *token >> r >> g >> b >> colors.borderAlpha;
        colors.border = Bitmap::makeColor(r,g,b);
    }
}

void Widget::arc( const Bitmap & work, int x, int y, double startAngle, int radius, int color )
{
	int q = 0;// for counters
	double d_q = 0.0;// for percentage of loop completed
	double d_q_plus_one = 0.0;

	const double d_angular_length_deg = 0.030;
	const double d_start_angle_rad = startAngle*DEG_TO_RAD;
	const double d_angular_length_rad = d_angular_length_deg*DEG_TO_RAD;
	const double d_arc_distance_between_points = 0.25*pow(2.0 , static_cast<double>(10) / 10.0);
	double d_angular_length_rad_per_segment = 0.0;

	double arc_length = radius*d_angular_length_rad;
	if (arc_length < 0.0) {arc_length *= -1.0;}
	const double d_num_segments = arc_length / d_arc_distance_between_points;

	int num_segments = 0;
	round_double(d_num_segments , num_segments);

	if (num_segments == 0) {num_segments += 1;} // need at least one segment (two points)
	const int num_points = num_segments + 1;
	const double d_num_points_minus_one = static_cast<double>(num_points - 1);

	int arc_point_x;//[num_points];
	int arc_point_y;//[num_points];
	int arc_point2_x;//[num_points];
	int arc_point2_y;//[num_points];
	double d_arc_point_x = 0.0;
	double d_arc_point_y = 0.0;
	double d_arc_point2_x = 0.0;
	double d_arc_point2_y = 0.0;

	double current_angle_rad = 0.0;
	double current_angle2_rad = 0.0;

	if (d_arc_distance_between_points <= 1.0) {
		for (q = 0 ; q < num_points ; q++) {
			d_q = static_cast<double>(q);
			current_angle_rad = d_start_angle_rad + (d_q / d_num_points_minus_one)*d_angular_length_rad;
			d_arc_point_x = x + radius*cos(current_angle_rad);
			d_arc_point_y = y + radius*sin(current_angle_rad);

			round_double(d_arc_point_x , arc_point_x);
			round_double(d_arc_point_y , arc_point_y);

			work.putPixel(arc_point_x,arc_point_y,color);
		}
	}
	if (d_arc_distance_between_points > 1.0) {

		d_angular_length_rad_per_segment = d_angular_length_rad / d_num_points_minus_one;
		for (q = 0 ; q < num_segments ; q++) {
			d_q = static_cast<double>(q);
			d_q_plus_one = static_cast<double>(q + 1);

			current_angle_rad = d_start_angle_rad + d_q*d_angular_length_rad_per_segment;
			current_angle2_rad = d_start_angle_rad + d_q_plus_one*d_angular_length_rad_per_segment;

			d_arc_point_x = x + radius*cos(current_angle_rad);
			d_arc_point_y = y + radius*sin(current_angle_rad);

			round_double(d_arc_point_x , arc_point_x);
			round_double(d_arc_point_y , arc_point_y);

			d_arc_point2_x = x + radius*cos(current_angle2_rad);
			d_arc_point2_y = y + radius*sin(current_angle2_rad);

			round_double(d_arc_point2_x , arc_point2_x);
			round_double(d_arc_point2_y , arc_point2_y);

			work.line(arc_point_x,arc_point_y, arc_point2_x, arc_point2_y,color);
		}
	}
}

void Widget::roundRect( const Bitmap & work, int radius, int x1, int y1, int x2, int y2, int color )
{

	const int width = x2 - x1;
	const int height = y2 - y1;
	radius = Mid(0, radius, Min((x1+width - x1)/2, (y1+height - y1)/2));
	work.line(x1+radius, y1, x1+width-radius, y1, color);
	work.line(x1+radius, y1+height, x1+width-radius,y1+height, color);
	work.line(x1, y1+radius,x1, y1+height-radius, color);
	work.line(x1+width, y1+radius,x1+width, y1+height-radius, color);
	arc(work, x1+radius, y1+radius, S_PI-1.115, radius, color);
	arc(work, x1+radius + (width - radius *2), y1+radius, -S_PI/2 +0.116, radius, color);
	arc(work, x1+width-radius, y1+height-radius, -0.110, radius ,color);
	arc(work, x1+radius, y1+height-radius, S_PI/2-0.119, radius, color);

}

void Widget::roundRectFill( const Bitmap & work, int radius, int x1, int y1, int x2, int y2, int color )
{
	const int width = x2 - x1;
	const int height = y2 - y1;
	radius = Mid(0, radius, Min((x1+width - x1)/2, (y1+height - y1)/2));
	work.circleFill(x1+radius, y1+radius, radius, color);
	work.circleFill((x1+width)-radius, y1+radius, radius, color);
	work.circleFill(x1+radius, (y1+height)-radius, radius, color);
	work.circleFill((x1+width)-radius, (y1+height)-radius, radius, color);
	work.rectangleFill( x1+radius, y1, x2-radius, y1+radius, color);
	work.rectangleFill( x1, y1+radius, x2, y2-radius, color);
	work.rectangleFill( x1+radius, y2-radius, x2-radius, y2, color);
}

void Widget::checkWorkArea()
{

    if ( ! workArea ){
		workArea = new Bitmap(location.getWidth(),location.getHeight());
	} else if(location.getWidth() < workArea->getWidth() || location.getHeight() < workArea->getHeight()) {
		delete workArea;
		workArea = new Bitmap(location.getWidth(), location.getHeight());
	} else if(location.getWidth() > workArea->getWidth() || location.getHeight() > workArea->getHeight()) {
		delete workArea;
		workArea = new Bitmap(location.getWidth(),location.getHeight());
	}
	if ( workArea ){
		workArea->fill(Bitmap::makeColor(255,0,255));
	}
}
<|endoftext|>