<commit_before>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSharedPointer>
#include <QHostInfo>
#include "AllCellsDustLib.hpp"
#include "Array.hpp"
#include "CommandLineArguments.hpp"
#include "Console.hpp"
#include "ConsoleHierarchyCreator.hpp"
#include "FatalError.hpp"
#include "FileLog.hpp"
#include "FilePaths.hpp"
#include "LatexHierarchyWriter.hpp"
#include "MemoryStatistics.hpp"
#include "MonteCarloSimulation.hpp"
#include "PanDustSystem.hpp"
#include "Parallel.hpp"
#include "ParallelFactory.hpp"
#include "PeerToPeerCommunicator.hpp"
#include "ProcessManager.hpp"
#include "Simulation.hpp"
#include "SmileSchemaWriter.hpp"
#include "SkirtCommandLineHandler.hpp"
#include "StopWatch.hpp"
#include "TimeLogger.hpp"
#include "XmlHierarchyCreator.hpp"
#include "XmlHierarchyWriter.hpp"

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

namespace
{
    // the allowed options list, in the format consumed by the CommandLineArguments constructor
    static const char* allowedOptions = "-t* -s* -d -b -v -m -l* -e -k -i* -o* -r -x";
}

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

SkirtCommandLineHandler::SkirtCommandLineHandler(QStringList cmdlineargs)
    : _args(cmdlineargs, allowedOptions), _hasError(false), _parallelSims(0)
{
    // get the host name
    _hostname = QHostInfo::localHostName();
    if (_hostname.isEmpty()) _username = "unknown host";

    // get the user name
    _username = qgetenv("USER");
    if (_username.isEmpty()) _username = qgetenv("USERNAME");
    if (_username.isEmpty()) _username = "unknown user";

    // issue welcome message
    _console.info("Welcome to " + QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion());
    _console.info("Running on " + _hostname + " for " + _username);
}

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

int SkirtCommandLineHandler::perform()
{
    // catch and properly report any exceptions
    try
    {
        // if there are no arguments at all --> interactive mode
        // if there is at least one file path argument --> batch mode
        // if the -x option is present --> export smile schema (undocumented option)
        // otherwise --> error
        if (_args.isValid() && !_args.hasOptions() && !_args.hasFilepaths()) return doInteractive();
        if (_args.hasFilepaths()) return doBatch();
        if (_args.isPresent("-x")) return doSmileSchema();
        _console.error("Invalid command line arguments");
        printHelp();
    }
    catch (FatalError& error)
    {
        foreach (QString line, error.message()) _console.error(line);
    }
    return EXIT_FAILURE;
}

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

int SkirtCommandLineHandler::doInteractive()
{
    if (ProcessManager::isMultiProc()) throw FATALERROR("Interactive mode cannot be run with multiple processes");

    _console.info("Interactively constructing a simulation...");

    // ask for the name of the ski file in which to save the result
    QString filename;
    while (true)
    {
        filename = _console.promptForInput("Enter the name of the ski file to be created");

        // reject empty strings
        if (!filename.isEmpty())
        {
            // add .ski extension if needed
            if (!filename.toLower().endsWith(".ski")) filename += ".ski";

            // reject name if file already exists
            if (!QFile::exists(filename))
            {
                // accept the filename
                break;
            }
            else _console.error("This file already exists; enter another name");
        }
        else _console.error("Enter a nonempty string");
    }

    // interactively construct the simulation; use shared pointer for automatic clean-up
    ConsoleHierarchyCreator creator;
    QSharedPointer<Simulation> simulation( creator.createHierarchy<Simulation>() );

    // create the ski file reflecting this simulation
    XmlHierarchyWriter writer;
    writer.writeHierarchy(simulation.data(), filename);
    _console.info("Successfully created ski file '" + filename + "'.");
    _console.info("To run the simulation use the command: skirt " + filename.left(filename.length()-4));

    return EXIT_SUCCESS;
}

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

int SkirtCommandLineHandler::doBatch()
{
    // build a list of filenames for existing ski files
    _hasError = false;
    foreach (QString filepath, _args.filepaths()) _skifiles << skifilesFor(filepath);

    // exit if there were any problems with the file paths
    if (_hasError || _skifiles.isEmpty())
    {
        if (!_args.isPresent("-b")) printHelp();
        return EXIT_FAILURE;
    }

    // if there is only one ski file, simply perform the single simulation
    if (_skifiles.size() == 1)
    {
        doSimulation(0); // memory statistics are reported in doSimulation()
    }
    else
    {
        // determine the number of parallel simulations
        _parallelSims = std::max(_args.intValue("-s"), 1);

        // prevent different simulations to be launched at once while MPI parallelization is used
        if (ProcessManager::isMultiProc() && _parallelSims > 1)
            throw FATALERROR("You cannot run different simulations in parallel whilst parallelizing them with MPI. "
                             "Retry with -s set to 1 or consider launching different SKIRT instances.");

        // perform a simulation for each ski file
        TimeLogger logger(&_console, "a set of " + QString::number(_skifiles.size()) + " simulations"
                          + (_parallelSims > 1 ? ", " + QString::number(_parallelSims) + " in parallel" : ""));
        ParallelFactory factory;
        factory.setMaxThreadCount(_parallelSims);
        factory.parallel()->call(this, &SkirtCommandLineHandler::doSimulation, _skifiles.size());
    }

    // report memory statistics for the complete run
    _console.info(MemoryStatistics::reportAvailable(true) + " -- " + MemoryStatistics::reportPeak(true));

    // report stopwatch results, if any
    foreach (QString line, StopWatch::report()) _console.warning(line);
    return EXIT_SUCCESS;
}

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

int SkirtCommandLineHandler::doSmileSchema()
{
    SmileSchemaWriter writer;
    writer.writeSmileSchema();
    _console.info("Successfully created SMILE schema file 'skirt.smile'.");
    return EXIT_SUCCESS;
}

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

QStringList SkirtCommandLineHandler::skifilesFor(QString filepath)
{
    QStringList result;
    QFileInfo info(filepath);
    QString name = info.fileName();

    // no recursion and no wildcards -> expect a single result
    if (!_args.isPresent("-r") && !name.contains('?') && !name.contains('*'))
    {
        // if the file does not exist as specified, try adding the .ski extension
        if (!QFile::exists(filepath) && !filepath.toLower().endsWith(".ski")) filepath += ".ski";
        if (!QFile::exists(filepath))
        {
            _hasError = true;
            _console.error("This ski file does not exist: " + filepath);
        }
        else result << filepath;
    }

    // recursion and/or wildcards -> multiple results possible
    else
    {
        // find matching files in this directory, possibly recursively (depending on -r option);
        // in this case do not automatically add the .ski extension; it leads to trouble with patterns
        // like "test*" which are automatically expanded by the shell before invoking the application
        result << skifilesFor(info.absoluteDir(), name);

        if (result.isEmpty())
        {
            _hasError = true;
            _console.error("No ski file matches the pattern: " + filepath);
        }
    }

    return result;
}

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

QStringList SkirtCommandLineHandler::skifilesFor(const QDir& dir, QString name)
{
    QStringList result;

    // add matching files at the current directory level
    foreach (QString entry, dir.entryList(QStringList() << name,
                                          QDir::Files|QDir::Readable|QDir::NoDotAndDotDot,
                                          QDir::Name|QDir::IgnoreCase) )
    {
        result << dir.absoluteFilePath(entry);
    }

    // if recursion is requested, call ourselves for all directories at this level
    if (_args.isPresent("-r"))
    {
        foreach (QString entry, dir.entryList(QDir::AllDirs|QDir::Readable|QDir::NoDotAndDotDot,
                                              QDir::Name|QDir::IgnoreCase) )
        {
            QDir subdir(dir);
            subdir.cd(entry);
            result << skifilesFor(subdir, name);
        }
    }

    return result;
}

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

void SkirtCommandLineHandler::doSimulation(size_t index)
{
    QString filename = _skifiles[index];
    if (_skifiles.size() > 1) _console.warning("Performing simulation #" + QString::number(index+1) +
                                               " of " + QString::number(_skifiles.size()));
    _console.info("Constructing a simulation from ski file '" + filename + "'...");

    // Construct the simulation from the ski file; use shared pointer for automatic clean-up
    XmlHierarchyCreator creator;
    QSharedPointer<Simulation> simulation( creator.createHierarchy<Simulation>(filename) );

    // Check whether emulation mode if enabled
    bool emulation = _args.isPresent("-e");
    if (emulation)
    {
        // Change the number of photon packages to 1 (we don't care about actually performing it)
        simulation->find<MonteCarloSimulation>(false)->setPackages(1);

        // Disable dust self-absorption (does not lead to additional memory usage, would not converge anyway)
        try {simulation->find<PanDustSystem>(false)->setSelfAbsorption(false);}
        catch (FatalError&) {}

        // Limit the number of self-absorption cycles to avoid the convergence loop (does not work?)
        //try {simulation->find<PanDustSystem>(false)->setCycles(1);}
        //catch (FatalError&) {}
    }

    // Check whether memory (de)allocation logging is enabled
    bool memoryalloc = _args.isPresent("-l");
    #ifndef BUILDING_MEMORY
    if (memoryalloc) throw FATALERROR("Enable BUILDING_MEMORY in the build options to use the -l option");
    #endif

    // Set up any simulation attributes that are not loaded from the ski file:
    //  - the paths for input and output files
    QFileInfo skiinfo(filename);
    simulation->filePaths()->setOutputPrefix(skiinfo.completeBaseName());
    QString base = _args.isPresent("-k") ? skiinfo.absolutePath() : QDir::currentPath();
    simulation->filePaths()->setInputPath((_args.value("-i").startsWith('/') ? "" : base + "/") + _args.value("-i"));
    simulation->filePaths()->setOutputPath((_args.value("-o").startsWith('/') ? "" : base + "/") + _args.value("-o"));

    //  - the number of parallel threads
    if (_args.intValue("-t") > 0) simulation->parallelFactory()->setMaxThreadCount(_args.intValue("-t"));
    if (memoryalloc)
    {
        if (_args.intValue("-t") > 0)
            simulation->log()->warning("You cannot use multiple threads when logging memory (de)allocation. Setting "
                                       "the number of threads to 1.");
        simulation->parallelFactory()->setMaxThreadCount(1); // memory (de)allocation logging requires singlethreading
    }

    //  - the multiprocessing environment
    PeerToPeerCommunicator* comm = simulation->communicator();
    comm->setup();

    //  - the activation of data parallelization
    if (_args.isPresent("-d") && comm->isMultiProc())
    {
        PanDustSystem* pds = nullptr;
        try {pds = simulation->find<PanDustSystem>(false);}
        catch (FatalError&) {}

        if (pds && pds->dustemission())
        {
            try {pds->find<AllCellsDustLib>();}
            catch(FatalError&)
            {
                throw FATALERROR("When using -d, the dust emission can only be calculated using an AllCellsDustLib");
            }
        }
        // no PanDustSystem -> true,
        // pds but no dust emission -> true,
        // pds with dust emission -> error when no AllCellsDustLib
        comm->setDataParallel(true);
    }

    //  - the console and the file log (and memory (de)allocation logging)
    FileLog* log = new FileLog();
    simulation->log()->setLinkedLog(log);
    simulation->log()->setVerbose(_args.isPresent("-v"));
    simulation->log()->setMemoryLogging(_args.isPresent("-m"));
    if (emulation) simulation->log()->setLowestLevel(Log::Error); // in emulation mode, only log errors to the console
    if (_parallelSims > 1 || _args.isPresent("-b")) simulation->log()->setLowestLevel(Log::Success);
    #ifdef BUILDING_MEMORY
    if (memoryalloc)
    {
        // enable memory logging for each log message when memory (de)allocation logging is enabled
        simulation->log()->setMemoryLogging(true);
        // set the lower limit for memory (de)allocation logging
        log->setLimit(_args.doubleValue("-l"));
        Array::setLogger(log);
    }
    #endif

    // Output a ski file and a latex file reflecting this simulation for later reference
    if (comm->isRoot())
    {
        XmlHierarchyWriter writer1;
        writer1.writeHierarchy(simulation.data(), simulation->filePaths()->output("parameters.xml"));
        LatexHierarchyWriter writer2;
        writer2.writeHierarchy(simulation.data(), simulation->filePaths()->output("parameters.tex"));
    }

    // Run the simulation; catch and rethrow exceptions so they are also logged to file
    try
    {
        log->setup();
        log->info(QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion());
        log->info("Running on " + _hostname + " for " + _username);
        if (emulation) _console.info("Emulating the simulation steps and monitoring memory usage...");
        simulation->setupAndRun();

        // if this is the only or first simulation in the run, report memory statistics in the simulation's log file
        if (_skifiles.size() == 1 || (_parallelSims==1 && index==0))
            log->info(MemoryStatistics::reportAvailable(true) + " -- " + MemoryStatistics::reportPeak(true));

        #ifdef BUILDING_MEMORY
        // disable memory (de)allocation logging after the simulation finished
        if (memoryalloc) Array::setLogger(nullptr);
        #endif
    }
    catch (FatalError& error)
    {
        foreach (QString line, error.message()) log->error(line);
        throw error;
    }
}

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

void SkirtCommandLineHandler::printHelp()
{
    _console.warning("");
    _console.warning("To create a new ski file interactively:    skirt");
    _console.warning("To run a simulation with default options:  skirt <ski-filename>");
    _console.warning("");
    _console.warning("  skirt [-t <threads>] [-s <simulations>] [-d]");
    _console.warning("        [-b] [-v] [-m] [-l <limit>] [-e]");
    _console.warning("        [-k] [-i <dirpath>] [-o <dirpath>]");
    _console.warning("        [-r] {<filepath>}*");
    _console.warning("");
    _console.warning("  -t <threads> : the number of parallel threads for each simulation");
    _console.warning("  -s <simulations> : the number of parallel simulations per process");
    _console.warning("  -d : enable data parallelization mode for multiple processes");
    _console.warning("  -b : force brief console logging");
    _console.warning("  -v : force verbose logging for multiple processes");
    _console.warning("  -m : state the amount of used memory at the start of each log message");
    _console.warning("  -l <limit> : enable memory (de)allocation logging (lower limit in GB)");
    _console.warning("  -e : run the simulation in 'emulation' mode to get an estimate of the memory consumption");
    _console.warning("  -k : make the input/output paths relative to the ski file being processed");
    _console.warning("  -i <dirpath> : the relative or absolute path for simulation input files");
    _console.warning("  -o <dirpath> : the relative or absolute path for simulation output files");
    _console.warning("  -r : cause recursive directory descent for all specified ski file paths");
    _console.warning("  <filepath> : the relative or absolute file path for a ski file");
    _console.warning("               (the filename may contain ? and * wildcards)");
    _console.warning("");
}

//////////////////////////////////////////////////////////////////////
<commit_msg>-d: Throw an error when there are more processes than wavelengths.<commit_after>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSharedPointer>
#include <QHostInfo>
#include "AllCellsDustLib.hpp"
#include "Array.hpp"
#include "CommandLineArguments.hpp"
#include "Console.hpp"
#include "ConsoleHierarchyCreator.hpp"
#include "FatalError.hpp"
#include "FileLog.hpp"
#include "FilePaths.hpp"
#include "LatexHierarchyWriter.hpp"
#include "MemoryStatistics.hpp"
#include "MonteCarloSimulation.hpp"
#include "PanDustSystem.hpp"
#include "Parallel.hpp"
#include "ParallelFactory.hpp"
#include "PeerToPeerCommunicator.hpp"
#include "ProcessManager.hpp"
#include "Simulation.hpp"
#include "SmileSchemaWriter.hpp"
#include "SkirtCommandLineHandler.hpp"
#include "StopWatch.hpp"
#include "TimeLogger.hpp"
#include "WavelengthGrid.hpp"
#include "XmlHierarchyCreator.hpp"
#include "XmlHierarchyWriter.hpp"

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

namespace
{
    // the allowed options list, in the format consumed by the CommandLineArguments constructor
    static const char* allowedOptions = "-t* -s* -d -b -v -m -l* -e -k -i* -o* -r -x";
}

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

SkirtCommandLineHandler::SkirtCommandLineHandler(QStringList cmdlineargs)
    : _args(cmdlineargs, allowedOptions), _hasError(false), _parallelSims(0)
{
    // get the host name
    _hostname = QHostInfo::localHostName();
    if (_hostname.isEmpty()) _username = "unknown host";

    // get the user name
    _username = qgetenv("USER");
    if (_username.isEmpty()) _username = qgetenv("USERNAME");
    if (_username.isEmpty()) _username = "unknown user";

    // issue welcome message
    _console.info("Welcome to " + QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion());
    _console.info("Running on " + _hostname + " for " + _username);
}

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

int SkirtCommandLineHandler::perform()
{
    // catch and properly report any exceptions
    try
    {
        // if there are no arguments at all --> interactive mode
        // if there is at least one file path argument --> batch mode
        // if the -x option is present --> export smile schema (undocumented option)
        // otherwise --> error
        if (_args.isValid() && !_args.hasOptions() && !_args.hasFilepaths()) return doInteractive();
        if (_args.hasFilepaths()) return doBatch();
        if (_args.isPresent("-x")) return doSmileSchema();
        _console.error("Invalid command line arguments");
        printHelp();
    }
    catch (FatalError& error)
    {
        foreach (QString line, error.message()) _console.error(line);
    }
    return EXIT_FAILURE;
}

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

int SkirtCommandLineHandler::doInteractive()
{
    if (ProcessManager::isMultiProc()) throw FATALERROR("Interactive mode cannot be run with multiple processes");

    _console.info("Interactively constructing a simulation...");

    // ask for the name of the ski file in which to save the result
    QString filename;
    while (true)
    {
        filename = _console.promptForInput("Enter the name of the ski file to be created");

        // reject empty strings
        if (!filename.isEmpty())
        {
            // add .ski extension if needed
            if (!filename.toLower().endsWith(".ski")) filename += ".ski";

            // reject name if file already exists
            if (!QFile::exists(filename))
            {
                // accept the filename
                break;
            }
            else _console.error("This file already exists; enter another name");
        }
        else _console.error("Enter a nonempty string");
    }

    // interactively construct the simulation; use shared pointer for automatic clean-up
    ConsoleHierarchyCreator creator;
    QSharedPointer<Simulation> simulation( creator.createHierarchy<Simulation>() );

    // create the ski file reflecting this simulation
    XmlHierarchyWriter writer;
    writer.writeHierarchy(simulation.data(), filename);
    _console.info("Successfully created ski file '" + filename + "'.");
    _console.info("To run the simulation use the command: skirt " + filename.left(filename.length()-4));

    return EXIT_SUCCESS;
}

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

int SkirtCommandLineHandler::doBatch()
{
    // build a list of filenames for existing ski files
    _hasError = false;
    foreach (QString filepath, _args.filepaths()) _skifiles << skifilesFor(filepath);

    // exit if there were any problems with the file paths
    if (_hasError || _skifiles.isEmpty())
    {
        if (!_args.isPresent("-b")) printHelp();
        return EXIT_FAILURE;
    }

    // if there is only one ski file, simply perform the single simulation
    if (_skifiles.size() == 1)
    {
        doSimulation(0); // memory statistics are reported in doSimulation()
    }
    else
    {
        // determine the number of parallel simulations
        _parallelSims = std::max(_args.intValue("-s"), 1);

        // prevent different simulations to be launched at once while MPI parallelization is used
        if (ProcessManager::isMultiProc() && _parallelSims > 1)
            throw FATALERROR("You cannot run different simulations in parallel whilst parallelizing them with MPI. "
                             "Retry with -s set to 1 or consider launching different SKIRT instances.");

        // perform a simulation for each ski file
        TimeLogger logger(&_console, "a set of " + QString::number(_skifiles.size()) + " simulations"
                          + (_parallelSims > 1 ? ", " + QString::number(_parallelSims) + " in parallel" : ""));
        ParallelFactory factory;
        factory.setMaxThreadCount(_parallelSims);
        factory.parallel()->call(this, &SkirtCommandLineHandler::doSimulation, _skifiles.size());
    }

    // report memory statistics for the complete run
    _console.info(MemoryStatistics::reportAvailable(true) + " -- " + MemoryStatistics::reportPeak(true));

    // report stopwatch results, if any
    foreach (QString line, StopWatch::report()) _console.warning(line);
    return EXIT_SUCCESS;
}

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

int SkirtCommandLineHandler::doSmileSchema()
{
    SmileSchemaWriter writer;
    writer.writeSmileSchema();
    _console.info("Successfully created SMILE schema file 'skirt.smile'.");
    return EXIT_SUCCESS;
}

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

QStringList SkirtCommandLineHandler::skifilesFor(QString filepath)
{
    QStringList result;
    QFileInfo info(filepath);
    QString name = info.fileName();

    // no recursion and no wildcards -> expect a single result
    if (!_args.isPresent("-r") && !name.contains('?') && !name.contains('*'))
    {
        // if the file does not exist as specified, try adding the .ski extension
        if (!QFile::exists(filepath) && !filepath.toLower().endsWith(".ski")) filepath += ".ski";
        if (!QFile::exists(filepath))
        {
            _hasError = true;
            _console.error("This ski file does not exist: " + filepath);
        }
        else result << filepath;
    }

    // recursion and/or wildcards -> multiple results possible
    else
    {
        // find matching files in this directory, possibly recursively (depending on -r option);
        // in this case do not automatically add the .ski extension; it leads to trouble with patterns
        // like "test*" which are automatically expanded by the shell before invoking the application
        result << skifilesFor(info.absoluteDir(), name);

        if (result.isEmpty())
        {
            _hasError = true;
            _console.error("No ski file matches the pattern: " + filepath);
        }
    }

    return result;
}

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

QStringList SkirtCommandLineHandler::skifilesFor(const QDir& dir, QString name)
{
    QStringList result;

    // add matching files at the current directory level
    foreach (QString entry, dir.entryList(QStringList() << name,
                                          QDir::Files|QDir::Readable|QDir::NoDotAndDotDot,
                                          QDir::Name|QDir::IgnoreCase) )
    {
        result << dir.absoluteFilePath(entry);
    }

    // if recursion is requested, call ourselves for all directories at this level
    if (_args.isPresent("-r"))
    {
        foreach (QString entry, dir.entryList(QDir::AllDirs|QDir::Readable|QDir::NoDotAndDotDot,
                                              QDir::Name|QDir::IgnoreCase) )
        {
            QDir subdir(dir);
            subdir.cd(entry);
            result << skifilesFor(subdir, name);
        }
    }

    return result;
}

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

void SkirtCommandLineHandler::doSimulation(size_t index)
{
    QString filename = _skifiles[index];
    if (_skifiles.size() > 1) _console.warning("Performing simulation #" + QString::number(index+1) +
                                               " of " + QString::number(_skifiles.size()));
    _console.info("Constructing a simulation from ski file '" + filename + "'...");

    // Construct the simulation from the ski file; use shared pointer for automatic clean-up
    XmlHierarchyCreator creator;
    QSharedPointer<Simulation> simulation( creator.createHierarchy<Simulation>(filename) );

    // Check whether emulation mode if enabled
    bool emulation = _args.isPresent("-e");
    if (emulation)
    {
        // Change the number of photon packages to 1 (we don't care about actually performing it)
        simulation->find<MonteCarloSimulation>(false)->setPackages(1);

        // Disable dust self-absorption (does not lead to additional memory usage, would not converge anyway)
        try {simulation->find<PanDustSystem>(false)->setSelfAbsorption(false);}
        catch (FatalError&) {}

        // Limit the number of self-absorption cycles to avoid the convergence loop (does not work?)
        //try {simulation->find<PanDustSystem>(false)->setCycles(1);}
        //catch (FatalError&) {}
    }

    // Check whether memory (de)allocation logging is enabled
    bool memoryalloc = _args.isPresent("-l");
    #ifndef BUILDING_MEMORY
    if (memoryalloc) throw FATALERROR("Enable BUILDING_MEMORY in the build options to use the -l option");
    #endif

    // Set up any simulation attributes that are not loaded from the ski file:
    //  - the paths for input and output files
    QFileInfo skiinfo(filename);
    simulation->filePaths()->setOutputPrefix(skiinfo.completeBaseName());
    QString base = _args.isPresent("-k") ? skiinfo.absolutePath() : QDir::currentPath();
    simulation->filePaths()->setInputPath((_args.value("-i").startsWith('/') ? "" : base + "/") + _args.value("-i"));
    simulation->filePaths()->setOutputPath((_args.value("-o").startsWith('/') ? "" : base + "/") + _args.value("-o"));

    //  - the number of parallel threads
    if (_args.intValue("-t") > 0) simulation->parallelFactory()->setMaxThreadCount(_args.intValue("-t"));
    if (memoryalloc)
    {
        if (_args.intValue("-t") > 0)
            simulation->log()->warning("You cannot use multiple threads when logging memory (de)allocation. Setting "
                                       "the number of threads to 1.");
        simulation->parallelFactory()->setMaxThreadCount(1); // memory (de)allocation logging requires singlethreading
    }

    //  - the multiprocessing environment
    PeerToPeerCommunicator* comm = simulation->communicator();
    comm->setup();

    //  - the activation of data parallelization
    if (_args.isPresent("-d") && comm->isMultiProc())
    {
        if (simulation->find<WavelengthGrid>(false)->Nlambda() < comm->size())
            throw FATALERROR("When using -d, the number of wavelengths must be larger than the number of processes.");

        PanDustSystem* pds = nullptr;
        try {pds = simulation->find<PanDustSystem>(false);}
        catch (FatalError&) {}

        if (pds && pds->dustemission())
        {
            try {pds->find<AllCellsDustLib>();}
            catch(FatalError&)
            {
                throw FATALERROR("When using -d, the dust emission can only be calculated using an AllCellsDustLib");
            }
        }
        // no PanDustSystem -> true,
        // pds but no dust emission -> true,
        // pds with dust emission -> error when no AllCellsDustLib
        comm->setDataParallel(true);
    }

    //  - the console and the file log (and memory (de)allocation logging)
    FileLog* log = new FileLog();
    simulation->log()->setLinkedLog(log);
    simulation->log()->setVerbose(_args.isPresent("-v"));
    simulation->log()->setMemoryLogging(_args.isPresent("-m"));
    if (emulation) simulation->log()->setLowestLevel(Log::Error); // in emulation mode, only log errors to the console
    if (_parallelSims > 1 || _args.isPresent("-b")) simulation->log()->setLowestLevel(Log::Success);
    #ifdef BUILDING_MEMORY
    if (memoryalloc)
    {
        // enable memory logging for each log message when memory (de)allocation logging is enabled
        simulation->log()->setMemoryLogging(true);
        // set the lower limit for memory (de)allocation logging
        log->setLimit(_args.doubleValue("-l"));
        Array::setLogger(log);
    }
    #endif

    // Output a ski file and a latex file reflecting this simulation for later reference
    if (comm->isRoot())
    {
        XmlHierarchyWriter writer1;
        writer1.writeHierarchy(simulation.data(), simulation->filePaths()->output("parameters.xml"));
        LatexHierarchyWriter writer2;
        writer2.writeHierarchy(simulation.data(), simulation->filePaths()->output("parameters.tex"));
    }

    // Run the simulation; catch and rethrow exceptions so they are also logged to file
    try
    {
        log->setup();
        log->info(QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion());
        log->info("Running on " + _hostname + " for " + _username);
        if (emulation) _console.info("Emulating the simulation steps and monitoring memory usage...");
        simulation->setupAndRun();

        // if this is the only or first simulation in the run, report memory statistics in the simulation's log file
        if (_skifiles.size() == 1 || (_parallelSims==1 && index==0))
            log->info(MemoryStatistics::reportAvailable(true) + " -- " + MemoryStatistics::reportPeak(true));

        #ifdef BUILDING_MEMORY
        // disable memory (de)allocation logging after the simulation finished
        if (memoryalloc) Array::setLogger(nullptr);
        #endif
    }
    catch (FatalError& error)
    {
        foreach (QString line, error.message()) log->error(line);
        throw error;
    }
}

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

void SkirtCommandLineHandler::printHelp()
{
    _console.warning("");
    _console.warning("To create a new ski file interactively:    skirt");
    _console.warning("To run a simulation with default options:  skirt <ski-filename>");
    _console.warning("");
    _console.warning("  skirt [-t <threads>] [-s <simulations>] [-d]");
    _console.warning("        [-b] [-v] [-m] [-l <limit>] [-e]");
    _console.warning("        [-k] [-i <dirpath>] [-o <dirpath>]");
    _console.warning("        [-r] {<filepath>}*");
    _console.warning("");
    _console.warning("  -t <threads> : the number of parallel threads for each simulation");
    _console.warning("  -s <simulations> : the number of parallel simulations per process");
    _console.warning("  -d : enable data parallelization mode for multiple processes");
    _console.warning("  -b : force brief console logging");
    _console.warning("  -v : force verbose logging for multiple processes");
    _console.warning("  -m : state the amount of used memory at the start of each log message");
    _console.warning("  -l <limit> : enable memory (de)allocation logging (lower limit in GB)");
    _console.warning("  -e : run the simulation in 'emulation' mode to get an estimate of the memory consumption");
    _console.warning("  -k : make the input/output paths relative to the ski file being processed");
    _console.warning("  -i <dirpath> : the relative or absolute path for simulation input files");
    _console.warning("  -o <dirpath> : the relative or absolute path for simulation output files");
    _console.warning("  -r : cause recursive directory descent for all specified ski file paths");
    _console.warning("  <filepath> : the relative or absolute file path for a ski file");
    _console.warning("               (the filename may contain ? and * wildcards)");
    _console.warning("");
}

//////////////////////////////////////////////////////////////////////
<|endoftext|>


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

/**
 * @file
 **/

#include "modules/planning/tasks/dp_poly_path/trajectory_cost.h"

#include <algorithm>
#include <cmath>
#include <utility>

#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::math::Box2d;
using apollo::common::math::Vec2d;
using apollo::common::TrajectoryPoint;

TrajectoryCost::TrajectoryCost(
    const DpPolyPathConfig &config, const ReferenceLine &reference_line,
    const std::vector<const PathObstacle *> &obstacles,
    const common::VehicleParam &vehicle_param,
    const SpeedData &heuristic_speed_data, const common::SLPoint &init_sl_point)
    : config_(config),
      reference_line_(&reference_line),
      vehicle_param_(vehicle_param),
      heuristic_speed_data_(heuristic_speed_data),
      init_sl_point_(init_sl_point) {
  const double total_time =
      std::min(heuristic_speed_data_.TotalTime(), FLAGS_prediction_total_time);

  num_of_time_stamps_ = static_cast<uint32_t>(
      std::floor(total_time / config.eval_time_interval()));

  for (const auto ptr_path_obstacle : obstacles) {
    if (ptr_path_obstacle->IsIgnore()) {
      continue;
    }
    const auto ptr_obstacle = ptr_path_obstacle->obstacle();
    if (Obstacle::IsVirtualObstacle(ptr_obstacle->Perception())) {
      // Virtual obstacle
      continue;
    } else if (Obstacle::IsStaticObstacle(ptr_obstacle->Perception())) {
      auto sl_boundary = ptr_path_obstacle->perception_sl_boundary();
      const double kDefaultLaneWidth = 1.5;
      const auto &vehicle_config =
          common::VehicleConfigHelper::instance()->GetConfig();
      const double width = vehicle_config.vehicle_param().width();

      if (sl_boundary.start_l() + kDefaultLaneWidth < width &&
          kDefaultLaneWidth - sl_boundary.end_l() < width) {
        // lane blocking obstacle
        continue;
      }

      const double length = vehicle_config.vehicle_param().length();
      if (sl_boundary.start_s() - init_sl_point_.s() < 2.0 * length) {
        // if too close, we treat the obstacle as non-nudgable
        continue;
      }

      TrajectoryPoint trajectory_point = ptr_obstacle->GetPointAtTime(0.0);
      constexpr double kBuff = 0.2;
      Box2d obstacle_box = ptr_obstacle->GetBoundingBox(trajectory_point);
      Box2d expanded_obstacle_box =
          Box2d(obstacle_box.center(), obstacle_box.heading(),
                obstacle_box.length() + kBuff, obstacle_box.width() + kBuff);
      static_obstacle_boxes_.push_back(std::move(expanded_obstacle_box));
    } else {
      std::vector<Box2d> box_by_time;
      for (uint32_t t = 0; t <= num_of_time_stamps_; ++t) {
        TrajectoryPoint trajectory_point =
            ptr_obstacle->GetPointAtTime(t * config.eval_time_interval());

        Box2d obstacle_box = ptr_obstacle->GetBoundingBox(trajectory_point);
        constexpr double kBuff = 0.5;
        Box2d expanded_obstacle_box =
            Box2d(obstacle_box.center(), obstacle_box.heading(),
                  obstacle_box.length() + kBuff, obstacle_box.width() + kBuff);
        box_by_time.push_back(expanded_obstacle_box);
      }
      dynamic_obstacle_boxes_.push_back(std::move(box_by_time));
    }
  }
}

double TrajectoryCost::CalculatePathCost(const QuinticPolynomialCurve1d &curve,
                                         const double start_s,
                                         const double end_s) const {
  double path_cost = 0.0;
  for (double path_s = 0.0; path_s < (end_s - start_s);
       path_s += config_.path_resolution()) {
    const double l = curve.Evaluate(0, path_s);

    std::function<double(const double)> quasi_softmax = [this](const double x) {
      const double l0 = this->config_.path_l_cost_param_l0();
      const double b = this->config_.path_l_cost_param_b();
      const double k = this->config_.path_l_cost_param_k();
      return (b + std::exp(-k * (x - l0))) / (1.0 + std::exp(-k * (x - l0)));
    };

    path_cost += l * l * config_.path_l_cost() * quasi_softmax(std::fabs(l));

    double left_width = 0.0;
    double right_width = 0.0;
    reference_line_->GetLaneWidth(path_s, &left_width, &right_width);

    const auto &vehicle_config =
        common::VehicleConfigHelper::instance()->GetConfig();
    const double width = vehicle_config.vehicle_param().width();

    constexpr double kBuff = 0.2;
    if (std::fabs(l) > std::fabs(init_sl_point_.l()) &&
        (l + width + kBuff > left_width || l - width - kBuff < right_width)) {
      path_cost += config_.path_out_lane_cost();
    }

    const double dl = std::fabs(curve.Evaluate(1, path_s));
    path_cost += dl * dl * config_.path_dl_cost();

    const double ddl = std::fabs(curve.Evaluate(2, path_s));
    path_cost += ddl * ddl * config_.path_ddl_cost();
  }
  return path_cost * config_.path_resolution();
}

double TrajectoryCost::CalculateStaticObstacleCost(
    const QuinticPolynomialCurve1d &curve, const double start_s,
    const double end_s) const {
  double obstacle_cost = 0.0;

  for (double curr_s = start_s; curr_s <= end_s;
       curr_s += config_.path_resolution()) {
    const double s = curr_s - start_s;  // spline curve s
    const double l = curve.Evaluate(0, s);
    const double dl = curve.Evaluate(1, s);

    const common::SLPoint sl =
        common::util::MakeSLPoint(curr_s, l);  // ego vehicle sl point
    const Box2d ego_box = GetBoxFromSLPoint(sl, dl);
    for (const auto &obstacle_box : static_obstacle_boxes_) {
      obstacle_cost += GetCostBetweenObsBoxes(ego_box, obstacle_box);
    }
  }
  return obstacle_cost * config_.path_resolution();
}

double TrajectoryCost::CalculateDynamicObstacleCost(
    const QuinticPolynomialCurve1d &curve, const double start_s,
    const double end_s) const {
  double obstacle_cost = 0.0;
  double time_stamp = 0.0;

  for (size_t index = 0; index < num_of_time_stamps_;
       ++index, time_stamp += config_.eval_time_interval()) {
    common::SpeedPoint speed_point;
    heuristic_speed_data_.EvaluateByTime(time_stamp, &speed_point);
    if (speed_point.s() < start_s - init_sl_point_.s()) {
      continue;
    }
    if (speed_point.s() > end_s - init_sl_point_.s()) {
      break;
    }

    const double s =
        init_sl_point_.s() + speed_point.s() - start_s;  // s on spline curve
    const double l = curve.Evaluate(0, s);
    const double dl = curve.Evaluate(1, s);

    const common::SLPoint sl =
        common::util::MakeSLPoint(init_sl_point_.s() + speed_point.s(), l);
    const Box2d ego_box = GetBoxFromSLPoint(sl, dl);
    for (const auto &obstacle_trajectory : dynamic_obstacle_boxes_) {
      obstacle_cost +=
          GetCostBetweenObsBoxes(ego_box, obstacle_trajectory.at(index));
    }
  }
  constexpr double kDynamicObsWeight = 1e-3;
  return obstacle_cost * config_.eval_time_interval() * kDynamicObsWeight;
}

double TrajectoryCost::GetCostBetweenObsBoxes(const Box2d &ego_box,
                                              const Box2d &obstacle_box) const {
  // Simple version: calculate obstacle cost by distance
  const double distance = obstacle_box.DistanceTo(ego_box);
  if (distance > config_.obstacle_ignore_distance()) {
    return 0.0;
  }

  std::function<double(const double, const double)> softmax = [](
      const double x, const double x0) {
    return std::exp(-(x - x0)) / (1.0 + std::exp(-(x - x0)));
  };

  double obstacle_cost = 0.0;
  obstacle_cost += config_.obstacle_collision_cost() *
                   softmax(distance, config_.obstacle_collision_distance());
  obstacle_cost += 20.0 * softmax(distance, config_.obstacle_risk_distance());
  return obstacle_cost;
}

Box2d TrajectoryCost::GetBoxFromSLPoint(const common::SLPoint &sl,
                                        const double dl) const {
  Vec2d xy_point;
  reference_line_->SLToXY(sl, &xy_point);

  ReferencePoint reference_point = reference_line_->GetReferencePoint(sl.s());

  const double one_minus_kappa_r_d = 1 - reference_point.kappa() * sl.l();
  const double delta_theta = std::atan2(dl, one_minus_kappa_r_d);
  const double theta =
      common::math::NormalizeAngle(delta_theta + reference_point.heading());
  return Box2d(xy_point, theta, vehicle_param_.length(),
               vehicle_param_.width());
}

// TODO(All): optimize obstacle cost calculation time
double TrajectoryCost::Calculate(const QuinticPolynomialCurve1d &curve,
                                 const double start_s,
                                 const double end_s) const {
  double total_cost = 0.0;
  // path cost
  total_cost += CalculatePathCost(curve, start_s, end_s);

  // static obstacle cost
  total_cost += CalculateStaticObstacleCost(curve, start_s, end_s);

  // dynamic obstacle cost
  total_cost += CalculateDynamicObstacleCost(curve, start_s, end_s);
  return total_cost;
}

double TrajectoryCost::RiskDistanceCost(const double distance) const {
  return (5.0 - distance) * ((5.0 - distance)) * 10;
}

double TrajectoryCost::RegularDistanceCost(const double distance) const {
  return std::max(20.0 - distance, 0.0);
}

}  // namespace planning
}  // namespace apollo
<commit_msg>Update trajectory_cost.cc<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/tasks/dp_poly_path/trajectory_cost.h"

#include <algorithm>
#include <cmath>
#include <utility>

#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::math::Box2d;
using apollo::common::math::Vec2d;
using apollo::common::TrajectoryPoint;

TrajectoryCost::TrajectoryCost(
    const DpPolyPathConfig &config, const ReferenceLine &reference_line,
    const std::vector<const PathObstacle *> &obstacles,
    const common::VehicleParam &vehicle_param,
    const SpeedData &heuristic_speed_data, const common::SLPoint &init_sl_point)
    : config_(config),
      reference_line_(&reference_line),
      vehicle_param_(vehicle_param),
      heuristic_speed_data_(heuristic_speed_data),
      init_sl_point_(init_sl_point) {
  const double total_time =
      std::min(heuristic_speed_data_.TotalTime(), FLAGS_prediction_total_time);

  num_of_time_stamps_ = static_cast<uint32_t>(
      std::floor(total_time / config.eval_time_interval()));

  for (const auto ptr_path_obstacle : obstacles) {
    if (ptr_path_obstacle->IsIgnore()) {
      continue;
    }
    const auto ptr_obstacle = ptr_path_obstacle->obstacle();
    if (Obstacle::IsVirtualObstacle(ptr_obstacle->Perception())) {
      // Virtual obstacle
      continue;
    } else if (Obstacle::IsStaticObstacle(ptr_obstacle->Perception())) {
      auto sl_boundary = ptr_path_obstacle->perception_sl_boundary();
      const double kDefaultLaneWidth = 1.5;
      const auto &vehicle_config =
          common::VehicleConfigHelper::instance()->GetConfig();
      const double width = vehicle_config.vehicle_param().width();

      if (sl_boundary.start_l() + kDefaultLaneWidth < width &&
          kDefaultLaneWidth - sl_boundary.end_l() < width) {
        // lane blocking obstacle
        continue;
      }

      const double length = vehicle_config.vehicle_param().length();
      if (sl_boundary.start_s() - init_sl_point_.s() < 2.0 * length) {
        // if too close, we treat the obstacle as non-nudgable
        continue;
      }

      TrajectoryPoint trajectory_point = ptr_obstacle->GetPointAtTime(0.0);
      constexpr double kBuff = 0.2;
      Box2d obstacle_box = ptr_obstacle->GetBoundingBox(trajectory_point);
      Box2d expanded_obstacle_box =
          Box2d(obstacle_box.center(), obstacle_box.heading(),
                obstacle_box.length() + kBuff, obstacle_box.width() + kBuff);
      static_obstacle_boxes_.push_back(std::move(expanded_obstacle_box));
    } else {
      std::vector<Box2d> box_by_time;
      for (uint32_t t = 0; t <= num_of_time_stamps_; ++t) {
        TrajectoryPoint trajectory_point =
            ptr_obstacle->GetPointAtTime(t * config.eval_time_interval());

        Box2d obstacle_box = ptr_obstacle->GetBoundingBox(trajectory_point);
        constexpr double kBuff = 0.5;
        Box2d expanded_obstacle_box =
            Box2d(obstacle_box.center(), obstacle_box.heading(),
                  obstacle_box.length() + kBuff, obstacle_box.width() + kBuff);
        box_by_time.push_back(expanded_obstacle_box);
      }
      dynamic_obstacle_boxes_.push_back(std::move(box_by_time));
    }
  }
}

double TrajectoryCost::CalculatePathCost(const QuinticPolynomialCurve1d &curve,
                                         const double start_s,
                                         const double end_s) const {
  double path_cost = 0.0;
  for (double path_s = 0.0; path_s < (end_s - start_s);
       path_s += config_.path_resolution()) {
    const double l = curve.Evaluate(0, path_s);

    std::function<double(const double)> quasi_softmax = [this](const double x) {
      const double l0 = this->config_.path_l_cost_param_l0();
      const double b = this->config_.path_l_cost_param_b();
      const double k = this->config_.path_l_cost_param_k();
      return (b + std::exp(-k * (x - l0))) / (1.0 + std::exp(-k * (x - l0)));
    };

    path_cost += l * l * config_.path_l_cost() * quasi_softmax(std::fabs(l));

    double left_width = 0.0;
    double right_width = 0.0;
    reference_line_->GetLaneWidth(path_s, &left_width, &right_width);

    const auto &vehicle_config =
        common::VehicleConfigHelper::instance()->GetConfig();
    const double width = vehicle_config.vehicle_param().width();

    constexpr double kBuff = 0.2;
    if (std::fabs(l) > std::fabs(init_sl_point_.l()) &&
        (l + width / 2.0 + kBuff > left_width || l - width / 2.0 - kBuff < right_width)) {
      path_cost += config_.path_out_lane_cost();
    }

    const double dl = std::fabs(curve.Evaluate(1, path_s));
    path_cost += dl * dl * config_.path_dl_cost();

    const double ddl = std::fabs(curve.Evaluate(2, path_s));
    path_cost += ddl * ddl * config_.path_ddl_cost();
  }
  return path_cost * config_.path_resolution();
}

double TrajectoryCost::CalculateStaticObstacleCost(
    const QuinticPolynomialCurve1d &curve, const double start_s,
    const double end_s) const {
  double obstacle_cost = 0.0;

  for (double curr_s = start_s; curr_s <= end_s;
       curr_s += config_.path_resolution()) {
    const double s = curr_s - start_s;  // spline curve s
    const double l = curve.Evaluate(0, s);
    const double dl = curve.Evaluate(1, s);

    const common::SLPoint sl =
        common::util::MakeSLPoint(curr_s, l);  // ego vehicle sl point
    const Box2d ego_box = GetBoxFromSLPoint(sl, dl);
    for (const auto &obstacle_box : static_obstacle_boxes_) {
      obstacle_cost += GetCostBetweenObsBoxes(ego_box, obstacle_box);
    }
  }
  return obstacle_cost * config_.path_resolution();
}

double TrajectoryCost::CalculateDynamicObstacleCost(
    const QuinticPolynomialCurve1d &curve, const double start_s,
    const double end_s) const {
  double obstacle_cost = 0.0;
  double time_stamp = 0.0;

  for (size_t index = 0; index < num_of_time_stamps_;
       ++index, time_stamp += config_.eval_time_interval()) {
    common::SpeedPoint speed_point;
    heuristic_speed_data_.EvaluateByTime(time_stamp, &speed_point);
    if (speed_point.s() < start_s - init_sl_point_.s()) {
      continue;
    }
    if (speed_point.s() > end_s - init_sl_point_.s()) {
      break;
    }

    const double s =
        init_sl_point_.s() + speed_point.s() - start_s;  // s on spline curve
    const double l = curve.Evaluate(0, s);
    const double dl = curve.Evaluate(1, s);

    const common::SLPoint sl =
        common::util::MakeSLPoint(init_sl_point_.s() + speed_point.s(), l);
    const Box2d ego_box = GetBoxFromSLPoint(sl, dl);
    for (const auto &obstacle_trajectory : dynamic_obstacle_boxes_) {
      obstacle_cost +=
          GetCostBetweenObsBoxes(ego_box, obstacle_trajectory.at(index));
    }
  }
  constexpr double kDynamicObsWeight = 1e-3;
  return obstacle_cost * config_.eval_time_interval() * kDynamicObsWeight;
}

double TrajectoryCost::GetCostBetweenObsBoxes(const Box2d &ego_box,
                                              const Box2d &obstacle_box) const {
  // Simple version: calculate obstacle cost by distance
  const double distance = obstacle_box.DistanceTo(ego_box);
  if (distance > config_.obstacle_ignore_distance()) {
    return 0.0;
  }

  std::function<double(const double, const double)> softmax = [](
      const double x, const double x0) {
    return std::exp(-(x - x0)) / (1.0 + std::exp(-(x - x0)));
  };

  double obstacle_cost = 0.0;
  obstacle_cost += config_.obstacle_collision_cost() *
                   softmax(distance, config_.obstacle_collision_distance());
  obstacle_cost += 20.0 * softmax(distance, config_.obstacle_risk_distance());
  return obstacle_cost;
}

Box2d TrajectoryCost::GetBoxFromSLPoint(const common::SLPoint &sl,
                                        const double dl) const {
  Vec2d xy_point;
  reference_line_->SLToXY(sl, &xy_point);

  ReferencePoint reference_point = reference_line_->GetReferencePoint(sl.s());

  const double one_minus_kappa_r_d = 1 - reference_point.kappa() * sl.l();
  const double delta_theta = std::atan2(dl, one_minus_kappa_r_d);
  const double theta =
      common::math::NormalizeAngle(delta_theta + reference_point.heading());
  return Box2d(xy_point, theta, vehicle_param_.length(),
               vehicle_param_.width());
}

// TODO(All): optimize obstacle cost calculation time
double TrajectoryCost::Calculate(const QuinticPolynomialCurve1d &curve,
                                 const double start_s,
                                 const double end_s) const {
  double total_cost = 0.0;
  // path cost
  total_cost += CalculatePathCost(curve, start_s, end_s);

  // static obstacle cost
  total_cost += CalculateStaticObstacleCost(curve, start_s, end_s);

  // dynamic obstacle cost
  total_cost += CalculateDynamicObstacleCost(curve, start_s, end_s);
  return total_cost;
}

double TrajectoryCost::RiskDistanceCost(const double distance) const {
  return (5.0 - distance) * ((5.0 - distance)) * 10;
}

double TrajectoryCost::RegularDistanceCost(const double distance) const {
  return std::max(20.0 - distance, 0.0);
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>#pragma once

#include "Common.h"
#include <vector>
#include <unordered_map>
#include <map>
#include <type_traits>

namespace Core
{
	template <typename Key, class Map>
	class Bookmark
	{
	public:
		void Add(const Key& key, uint markValue)
		{
			_map.insert(std::make_pair(key, markValue));
		}

		uint Find(const Key& key) const
		{
			const auto& iter = _map.find(key);

			bool found = iter != _map.end();
			return found ? iter->second : -1;//std::numeric_limits<uint>::max();
		}

		bool Has(const Key& key) const
		{
			return _map.find(key) != _map.end();
		}

		void Delete(const Key& key)
		{
			auto found = _map.find(key);
			if (found != _map.end())
				_map.erase(found);
		}

		void DeleteAll()
		{
			_map.clear();
		}

		static constexpr uint Fail() { return -1; }//std::numeric_limits<uint>::max(); }

	private:
		Map	_map;
	};

	template<typename Key>
	using BookHashMapmark = Bookmark<Key, std::unordered_map<Key, uint>>;

	template<typename Key>
	using BookMapmark = Bookmark<Key, std::map<Key, uint>>;
}<commit_msg>Bookmark - markValue이 uint가 고정이 아닌 다른 타입도 쓸 수 있도록 수정<commit_after>#pragma once

#include "Common.h"
#include <vector>
#include <unordered_map>
#include <map>
#include <type_traits>
#include <limits>

namespace Core
{
	template <typename Key, class Map>
	class Bookmark
	{
	public:
		void Add(const Key& key, Map::mapped_type markValue)
		{
			_map.insert(std::make_pair(key, markValue));
		}

		uint Find(const Key& key) const
		{
			const auto& iter = _map.find(key);

			bool found = iter != _map.end();
			return found ? iter->second : std::numeric_limits<Map::mapped_type>::max();
		}

		bool Has(const Key& key) const
		{
			return _map.find(key) != _map.end();
		}

		void Delete(const Key& key)
		{
			auto found = _map.find(key);
			if (found != _map.end())
				_map.erase(found);
		}

		void DeleteAll()
		{
			_map.clear();
		}

		static constexpr uint Fail() { return std::numeric_limits<Map::mapped_type>::max(); }

	private:
		Map	_map;
	};

	template<typename Key, typename MarkValueType = uint>
	using BookHashMapmark = Bookmark<Key, std::unordered_map<Key, MarkValueType>>;

	template<typename Key, typename MarkValueType = uint>
	using BookMapmark = Bookmark<Key, std::map<Key, MarkValueType>>;
}
<|endoftext|>


<commit_before>#include <mbed.h>
#include <cmsis_os.h>
#include <memory>

#include "SharedSPI.hpp"
#include "CC1201Radio.hpp"
#include "logger.hpp"
#include "pins.hpp"
#include "usb-interface.hpp"
#include "watchdog.hpp"
#include "RJBaseUSBDevice.hpp"

#define RJ_WATCHDOG_TIMER_VALUE 2  // seconds

using namespace std;

// USBHID interface.  The false at the end tells it not to connect initially
RJBaseUSBDevice usbLink(RJ_BASE2015_VENDOR_ID, RJ_BASE2015_PRODUCT_ID,
                        RJ_BASE2015_RELEASE);

bool initRadio() {
    /// A shared spi bus used for the fpga and cc1201 radio
    shared_ptr<SharedSPI> sharedSPI =
        make_shared<SharedSPI>(RJ_SPI_MOSI, RJ_SPI_MISO, RJ_SPI_SCK);
    sharedSPI->format(8, 0);  // 8 bits per transfer

    // RX/TX leds
    auto rxTimeoutLED =
        make_shared<FlashingTimeoutLED>(DigitalOut(LED1, OpenDrain));
    auto txTimeoutLED =
        make_shared<FlashingTimeoutLED>(DigitalOut(LED2, OpenDrain));

    // Startup the CommModule interface
    CommModule::Instance = make_shared<CommModule>(rxTimeoutLED, txTimeoutLED);
    shared_ptr<CommModule> commModule = CommModule::Instance;

    // Create a new physical hardware communication link
    global_radio =
        new CC1201(sharedSPI, RJ_RADIO_nCS, RJ_RADIO_INT, preferredSettings,
                   sizeof(preferredSettings) / sizeof(registerSetting_t));

    return global_radio->isConnected();
}

void radioRxHandler(rtp::packet* pkt) {
    // write packet content out to endpoint 1
    vector<uint8_t> buffer;
    pkt->pack(&buffer);
    bool success = usbLink.writeNB(1, buffer.data(), buffer.size(),
                                   MAX_PACKET_SIZE_EPBULK);

    if (!success) {
        LOG(WARN, "Failed to transfer received packet over usb");
    }
}

int main() {
    // set baud rate to higher value than the default for faster terminal
    Serial s(RJ_SERIAL_RXTX);
    s.baud(57600);

    // Set the default logging configurations
    isLogging = RJ_LOGGING_EN;
    rjLogLevel = INIT;

    LOG(INIT, "Base station starting...");

    if (initRadio()) {
        LOG(INIT, "Radio interface ready on %3.2fMHz!", global_radio->freq());

        CommModule::Instance->setRxHandler(&radioRxHandler, rtp::port::CONTROL);
        CommModule::Instance->setTxHandler(
            (CommLink*)global_radio, &CommLink::sendPacket, rtp::port::CONTROL);
    } else {
        LOG(FATAL, "No radio interface found!");
    }

    DigitalOut radioStatusLed(LED4, global_radio->isConnected());

    // set callbacks for usb control transfers
    usbLink.writeRegisterCallback = [](uint8_t reg, uint8_t val) {
        global_radio->writeReg(reg, val);
    };
    usbLink.readRegisterCallback = [](uint8_t reg) {
        return global_radio->readReg(reg);
    };
    usbLink.strobeCallback = [](uint8_t strobe) {
        global_radio->strobe(strobe);
    };

    LOG(INIT, "Initializing USB interface...");
    usbLink.connect();  // note: this blocks until the link is connected
    LOG(INIT, "Initialized USB interface!");

    // Set the watdog timer's initial config
    Watchdog::Set(RJ_WATCHDOG_TIMER_VALUE);

    LOG(INIT, "Listening for commands over USB");

    uint8_t buf[MAX_PACKET_SIZE_EPBULK];
    uint32_t bufSize;

    while (true) {
        // make sure we can always reach back to main by renewing the watchdog
        // timer periodically
        Watchdog::Renew();

        // attempt to read data from endpoint 2
        // if data is available, write it into @pkt and send it
        if (usbLink.readEP_NB(2, buf, &bufSize, sizeof(buf))) {
            // TODO: header data?  port?

            // construct packet from buffer received over USB
            rtp::packet pkt;
            pkt.recv(buf, bufSize);

            // transmit!
            CommModule::Instance->send(pkt);
        }
    }
}
<commit_msg>register handlers for more ports in base station<commit_after>#include <mbed.h>
#include <cmsis_os.h>
#include <memory>

#include "SharedSPI.hpp"
#include "CC1201Radio.hpp"
#include "logger.hpp"
#include "pins.hpp"
#include "usb-interface.hpp"
#include "watchdog.hpp"
#include "RJBaseUSBDevice.hpp"

#define RJ_WATCHDOG_TIMER_VALUE 2  // seconds

using namespace std;

// USBHID interface.  The false at the end tells it not to connect initially
RJBaseUSBDevice usbLink(RJ_BASE2015_VENDOR_ID, RJ_BASE2015_PRODUCT_ID,
                        RJ_BASE2015_RELEASE);

bool initRadio() {
    /// A shared spi bus used for the fpga and cc1201 radio
    shared_ptr<SharedSPI> sharedSPI =
        make_shared<SharedSPI>(RJ_SPI_MOSI, RJ_SPI_MISO, RJ_SPI_SCK);
    sharedSPI->format(8, 0);  // 8 bits per transfer

    // RX/TX leds
    auto rxTimeoutLED =
        make_shared<FlashingTimeoutLED>(DigitalOut(LED1, OpenDrain));
    auto txTimeoutLED =
        make_shared<FlashingTimeoutLED>(DigitalOut(LED2, OpenDrain));

    // Startup the CommModule interface
    CommModule::Instance = make_shared<CommModule>(rxTimeoutLED, txTimeoutLED);
    shared_ptr<CommModule> commModule = CommModule::Instance;

    // Create a new physical hardware communication link
    global_radio =
        new CC1201(sharedSPI, RJ_RADIO_nCS, RJ_RADIO_INT, preferredSettings,
                   sizeof(preferredSettings) / sizeof(registerSetting_t));

    return global_radio->isConnected();
}

void radioRxHandler(rtp::packet* pkt) {
    // write packet content out to endpoint 1
    vector<uint8_t> buffer;
    pkt->pack(&buffer);
    bool success = usbLink.writeNB(1, buffer.data(), buffer.size(),
                                   MAX_PACKET_SIZE_EPBULK);

    if (!success) {
        LOG(WARN, "Failed to transfer received packet over usb");
    }
}

int main() {
    // set baud rate to higher value than the default for faster terminal
    Serial s(RJ_SERIAL_RXTX);
    s.baud(57600);

    // Set the default logging configurations
    isLogging = RJ_LOGGING_EN;
    rjLogLevel = INIT;

    LOG(INIT, "Base station starting...");

    if (initRadio()) {
        LOG(INIT, "Radio interface ready on %3.2fMHz!", global_radio->freq());

        // register handlers for any ports we might use
        for (rtp::port port :
             {rtp::port::CONTROL, rtp::port::PING, rtp::port::LEGACY}) {
            CommModule::Instance->setRxHandler(&radioRxHandler, port);
            CommModule::Instance->setTxHandler((CommLink*)global_radio,
                                               &CommLink::sendPacket, port);
        }
    } else {
        LOG(FATAL, "No radio interface found!");
    }

    DigitalOut radioStatusLed(LED4, global_radio->isConnected());

    // set callbacks for usb control transfers
    usbLink.writeRegisterCallback = [](uint8_t reg, uint8_t val) {
        global_radio->writeReg(reg, val);
    };
    usbLink.readRegisterCallback = [](uint8_t reg) {
        return global_radio->readReg(reg);
    };
    usbLink.strobeCallback = [](uint8_t strobe) {
        global_radio->strobe(strobe);
    };

    LOG(INIT, "Initializing USB interface...");
    usbLink.connect();  // note: this blocks until the link is connected
    LOG(INIT, "Initialized USB interface!");

    // Set the watdog timer's initial config
    Watchdog::Set(RJ_WATCHDOG_TIMER_VALUE);

    LOG(INIT, "Listening for commands over USB");

    uint8_t buf[MAX_PACKET_SIZE_EPBULK];
    uint32_t bufSize;

    while (true) {
        // make sure we can always reach back to main by renewing the watchdog
        // timer periodically
        Watchdog::Renew();

        // attempt to read data from endpoint 2
        // if data is available, write it into @pkt and send it
        if (usbLink.readEP_NB(2, buf, &bufSize, sizeof(buf))) {
            // TODO: header data?  port?

            // construct packet from buffer received over USB
            rtp::packet pkt;
            pkt.recv(buf, bufSize);

            // transmit!
            CommModule::Instance->send(pkt);
        }
    }
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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 "platform/platform.h"
#include "renderInstance/renderPassManager.h"

#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "materials/customMaterialDefinition.h"
#include "materials/materialManager.h"
#include "scene/sceneManager.h"
#include "scene/sceneObject.h"
#include "gfx/primBuilder.h"
#include "platform/profiler.h"
#include "renderInstance/renderBinManager.h"
#include "renderInstance/renderObjectMgr.h"
#include "renderInstance/renderMeshMgr.h"
#include "renderInstance/renderTranslucentMgr.h"
#include "renderInstance/renderGlowMgr.h"
#include "renderInstance/renderTerrainMgr.h"
#include "core/util/safeDelete.h"
#include "math/util/matrixSet.h"
#include "console/engineAPI.h"

const RenderInstType RenderInstType::Invalid( "" );

const RenderInstType RenderPassManager::RIT_Mesh("Mesh");
const RenderInstType RenderPassManager::RIT_Shadow("Shadow");
const RenderInstType RenderPassManager::RIT_Sky("Sky");
const RenderInstType RenderPassManager::RIT_Terrain("Terrain");
const RenderInstType RenderPassManager::RIT_Object("Object");
const RenderInstType RenderPassManager::RIT_ObjectTranslucent("ObjectTranslucent");
const RenderInstType RenderPassManager::RIT_Decal("Decal");
const RenderInstType RenderPassManager::RIT_DecalRoad("DecalRoad");
const RenderInstType RenderPassManager::RIT_Water("Water");
const RenderInstType RenderPassManager::RIT_Foliage("Foliage");
const RenderInstType RenderPassManager::RIT_VolumetricFog("ObjectVolumetricFog");
const RenderInstType RenderPassManager::RIT_Translucent("Translucent");
const RenderInstType RenderPassManager::RIT_Begin("Begin");
const RenderInstType RenderPassManager::RIT_Custom("Custom");
const RenderInstType RenderPassManager::RIT_Particle("Particle");
const RenderInstType RenderPassManager::RIT_Occluder("Occluder");
const RenderInstType RenderPassManager::RIT_Editor("Editor");

//*****************************************************************************
// RenderInstance
//*****************************************************************************

void RenderInst::clear()
{
   dMemset( this, 0, sizeof(RenderInst) );
}

void MeshRenderInst::clear()
{
   dMemset( this, 0, sizeof(MeshRenderInst) );
   visibility = 1.0f;
}

void ParticleRenderInst::clear()
{
   dMemset( this, 0, sizeof(ParticleRenderInst) );
}

void ObjectRenderInst::clear()
{
   userData = NULL;

   dMemset( this, 0, sizeof( ObjectRenderInst ) );

   // The memset here is kinda wrong... it clears the
   // state initialized by the delegate constructor.
   //
   // This fixes it... but we probably need to have a
   // real constructor for RenderInsts.
   renderDelegate.clear();
}

void OccluderRenderInst::clear()
{
   dMemset( this, 0, sizeof(OccluderRenderInst) );
}

IMPLEMENT_CONOBJECT(RenderPassManager);

ConsoleDocClass( RenderPassManager,
   "@brief A grouping of render bin managers which forms a render pass.\n\n"
   "The render pass is used to order a set of RenderBinManager objects which are used "
   "when rendering a scene.  This class does little work itself other than managing "
   "its list of render bins.\n\n"
   "In 'core/scripts/client/renderManager.cs' you will find the DiffuseRenderPassManager "
   "which is used by the C++ engine to render the scene.\n\n"
   "@see RenderBinManager\n"
   "@ingroup RenderBin\n" );

RenderPassManager::RenderBinEventSignal& RenderPassManager::getRenderBinSignal()
{
   static RenderBinEventSignal theSignal;
   return theSignal;
}

void RenderPassManager::initPersistFields()
{
}

RenderPassManager::RenderPassManager()
{
   mSceneManager = NULL;
   VECTOR_SET_ASSOCIATION( mRenderBins );

   mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
   constructInPlace(mMatrixSet);
}

RenderPassManager::~RenderPassManager()
{
   dFree_aligned(mMatrixSet);

   // Any bins left need to be deleted.
   for ( U32 i=0; i<mRenderBins.size(); i++ )
   {
      RenderBinManager *bin = mRenderBins[i];

      // Clear the parent first, so that RenderBinManager::onRemove()
      // won't call removeManager() and break this loop.
      bin->setRenderPass( NULL );
      bin->deleteObject();
   }
}

void RenderPassManager::_insertSort(Vector<RenderBinManager*>& list, RenderBinManager* mgr, bool renderOrder)
{
   U32 i;
   for (i = 0; i < list.size(); i++)
   {
      bool renderCompare = mgr->getRenderOrder() < list[i]->getRenderOrder();
      bool processAddCompare = mgr->getProcessAddOrder() < list[i]->getProcessAddOrder();
      if ((renderOrder && renderCompare) || (!renderOrder && processAddCompare))
      {
         list.insert(i);
         list[i] = mgr;
         return;
      }
   }

   list.push_back(mgr);
}

void RenderPassManager::addManager(RenderBinManager* mgr)
{
   if ( !mgr->isProperlyAdded() )
      mgr->registerObject();

   AssertFatal( mgr->getRenderPass() == NULL, "RenderPassManager::addManager() - Bin is still part of another pass manager!" );
   mgr->setRenderPass( this );

   _insertSort(mRenderBins, mgr, true);
}

void RenderPassManager::removeManager(RenderBinManager* mgr)
{
   AssertFatal( mgr->getRenderPass() == this, "RenderPassManager::removeManager() - We do not own this bin!" );

   mgr->setRenderPass( NULL );
   mRenderBins.remove( mgr );
}

RenderBinManager* RenderPassManager::getManager(S32 i) const
{
   if (i >= 0 && i < mRenderBins.size())
      return mRenderBins[i];
   else
      return NULL;
}

void RenderPassManager::addInst( RenderInst *inst )
{
   PROFILE_SCOPE( RenderPassManager_addInst );

   AssertFatal( inst != NULL, "RenderPassManager::addInst - Got null instance!" );

   AddInstTable::Iterator iter = mAddInstSignals.find( inst->type );
   if ( iter == mAddInstSignals.end() )
      return;

   iter->value.trigger( inst );
}

void RenderPassManager::sort()
{
   PROFILE_SCOPE( RenderPassManager_Sort );

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      AssertFatal(*itr, "Render manager invalid!");
      (*itr)->sort();
   }
}

void RenderPassManager::clear()
{
   PROFILE_SCOPE( RenderPassManager_Clear );

   mChunker.clear();

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      AssertFatal(*itr, "Invalid render manager!");
      (*itr)->clear();
   }
}

void RenderPassManager::render(SceneRenderState * state)
{
   PROFILE_SCOPE( RenderPassManager_Render );

   GFX->pushWorldMatrix();
   MatrixF proj = GFX->getProjectionMatrix();

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      RenderBinManager *curBin = *itr;
      AssertFatal(curBin, "Invalid render manager!");
      getRenderBinSignal().trigger(curBin, state, true);
      curBin->render(state);
      getRenderBinSignal().trigger(curBin, state, false);
   }

   GFX->popWorldMatrix();
   GFX->setProjectionMatrix( proj );

   // Restore a clean state for subsequent rendering.
   GFX->setupGenericShaders();
   for(S32 i = 0; i < GFX->getNumSamplers(); ++i)
      GFX->setTexture(i, NULL);
}

void RenderPassManager::renderPass(SceneRenderState * state)
{
   PROFILE_SCOPE( RenderPassManager_RenderPass );
   sort();
   render(state);
   clear();
}

GFXTextureObject *RenderPassManager::getDepthTargetTexture()
{
   // If this is OpenGL, or something else has set the depth buffer, return the pointer
   if( mDepthBuff.isValid() )
   {
      // If this is OpenGL, make sure the depth target matches up
      // with the active render target.  Otherwise recreate.

      if( GFX->getAdapterType() == OpenGL )
      {
         GFXTarget* activeRT = GFX->getActiveRenderTarget();
         AssertFatal( activeRT, "Must be an active render target to call 'getDepthTargetTexture'" );

         Point2I activeRTSize = activeRT->getSize();
         if( mDepthBuff.getWidth() == activeRTSize.x &&
             mDepthBuff.getHeight() == activeRTSize.y )
            return mDepthBuff.getPointer();
      }
      else
         return mDepthBuff.getPointer();
   }

   if(GFX->getAdapterType() == OpenGL)
   {
      AssertFatal(GFX->getActiveRenderTarget(), "Must be an active render target to call 'getDepthTargetTexture'");

      const Point2I rtSize = GFX->getActiveRenderTarget()->getSize();
      mDepthBuff.set(rtSize.x, rtSize.y, GFXFormatD24S8,
         &GFXDefaultZTargetProfile, avar("%s() - mDepthBuff (line %d)", __FUNCTION__, __LINE__));
      return mDepthBuff.getPointer();
   }

   // Default return value
   return GFXTextureTarget::sDefaultDepthStencil;
}

void RenderPassManager::setDepthTargetTexture( GFXTextureObject *zTarget )
{
   mDepthBuff = zTarget;
}

const MatrixF* RenderPassManager::allocSharedXform( SharedTransformType stt )
{
   AssertFatal(stt == View || stt == Projection, "Bad shared transform type");

   // Enable this to simulate non-shared transform performance
   //#define SIMULATE_NON_SHARED_TRANSFORMS
#ifdef SIMULATE_NON_SHARED_TRANSFORMS
   return allocUniqueXform(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#else
   return &(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#endif
}

void RenderPassManager::assignSharedXform( SharedTransformType stt, const MatrixF &xfm )
{
   AssertFatal(stt == View || stt == Projection, "Bad shared transform type");
   if(stt == View)
      mMatrixSet->setSceneView(xfm);
   else
      mMatrixSet->setSceneProjection(xfm);
}

// Script interface

DefineEngineMethod(RenderPassManager, getManagerCount, S32, (),,
   "Returns the total number of bin managers." )
{
   return object->getManagerCount();
}

DefineEngineMethod( RenderPassManager, getManager, RenderBinManager*, ( S32 index ),,
   "Returns the render bin manager at the index or null if the index is out of range." )
{
   if(index < 0 || index >= object->getManagerCount())
      return NULL;

   return object->getManager(index);
}

DefineEngineMethod( RenderPassManager, addManager, void, ( RenderBinManager *renderBin ),,
   "Add as a render bin manager to the pass." )
{
   if ( renderBin )
      object->addManager( renderBin );
}

DefineEngineMethod( RenderPassManager, removeManager, void, ( RenderBinManager *renderBin ),,
   "Removes a render bin manager." )
{
   if ( renderBin )
      object->removeManager( renderBin );
}

<commit_msg>Make RenderPassManager call Parent::InitPersistFields<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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 "platform/platform.h"
#include "renderInstance/renderPassManager.h"

#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "materials/customMaterialDefinition.h"
#include "materials/materialManager.h"
#include "scene/sceneManager.h"
#include "scene/sceneObject.h"
#include "gfx/primBuilder.h"
#include "platform/profiler.h"
#include "renderInstance/renderBinManager.h"
#include "renderInstance/renderObjectMgr.h"
#include "renderInstance/renderMeshMgr.h"
#include "renderInstance/renderTranslucentMgr.h"
#include "renderInstance/renderGlowMgr.h"
#include "renderInstance/renderTerrainMgr.h"
#include "core/util/safeDelete.h"
#include "math/util/matrixSet.h"
#include "console/engineAPI.h"

const RenderInstType RenderInstType::Invalid( "" );

const RenderInstType RenderPassManager::RIT_Mesh("Mesh");
const RenderInstType RenderPassManager::RIT_Shadow("Shadow");
const RenderInstType RenderPassManager::RIT_Sky("Sky");
const RenderInstType RenderPassManager::RIT_Terrain("Terrain");
const RenderInstType RenderPassManager::RIT_Object("Object");
const RenderInstType RenderPassManager::RIT_ObjectTranslucent("ObjectTranslucent");
const RenderInstType RenderPassManager::RIT_Decal("Decal");
const RenderInstType RenderPassManager::RIT_DecalRoad("DecalRoad");
const RenderInstType RenderPassManager::RIT_Water("Water");
const RenderInstType RenderPassManager::RIT_Foliage("Foliage");
const RenderInstType RenderPassManager::RIT_VolumetricFog("ObjectVolumetricFog");
const RenderInstType RenderPassManager::RIT_Translucent("Translucent");
const RenderInstType RenderPassManager::RIT_Begin("Begin");
const RenderInstType RenderPassManager::RIT_Custom("Custom");
const RenderInstType RenderPassManager::RIT_Particle("Particle");
const RenderInstType RenderPassManager::RIT_Occluder("Occluder");
const RenderInstType RenderPassManager::RIT_Editor("Editor");

//*****************************************************************************
// RenderInstance
//*****************************************************************************

void RenderInst::clear()
{
   dMemset( this, 0, sizeof(RenderInst) );
}

void MeshRenderInst::clear()
{
   dMemset( this, 0, sizeof(MeshRenderInst) );
   visibility = 1.0f;
}

void ParticleRenderInst::clear()
{
   dMemset( this, 0, sizeof(ParticleRenderInst) );
}

void ObjectRenderInst::clear()
{
   userData = NULL;

   dMemset( this, 0, sizeof( ObjectRenderInst ) );

   // The memset here is kinda wrong... it clears the
   // state initialized by the delegate constructor.
   //
   // This fixes it... but we probably need to have a
   // real constructor for RenderInsts.
   renderDelegate.clear();
}

void OccluderRenderInst::clear()
{
   dMemset( this, 0, sizeof(OccluderRenderInst) );
}

IMPLEMENT_CONOBJECT(RenderPassManager);

ConsoleDocClass( RenderPassManager,
   "@brief A grouping of render bin managers which forms a render pass.\n\n"
   "The render pass is used to order a set of RenderBinManager objects which are used "
   "when rendering a scene.  This class does little work itself other than managing "
   "its list of render bins.\n\n"
   "In 'core/scripts/client/renderManager.cs' you will find the DiffuseRenderPassManager "
   "which is used by the C++ engine to render the scene.\n\n"
   "@see RenderBinManager\n"
   "@ingroup RenderBin\n" );

RenderPassManager::RenderBinEventSignal& RenderPassManager::getRenderBinSignal()
{
   static RenderBinEventSignal theSignal;
   return theSignal;
}

void RenderPassManager::initPersistFields()
{
   Parent::initPersistFields();
}

RenderPassManager::RenderPassManager()
{
   mSceneManager = NULL;
   VECTOR_SET_ASSOCIATION( mRenderBins );

   mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
   constructInPlace(mMatrixSet);
}

RenderPassManager::~RenderPassManager()
{
   dFree_aligned(mMatrixSet);

   // Any bins left need to be deleted.
   for ( U32 i=0; i<mRenderBins.size(); i++ )
   {
      RenderBinManager *bin = mRenderBins[i];

      // Clear the parent first, so that RenderBinManager::onRemove()
      // won't call removeManager() and break this loop.
      bin->setRenderPass( NULL );
      bin->deleteObject();
   }
}

void RenderPassManager::_insertSort(Vector<RenderBinManager*>& list, RenderBinManager* mgr, bool renderOrder)
{
   U32 i;
   for (i = 0; i < list.size(); i++)
   {
      bool renderCompare = mgr->getRenderOrder() < list[i]->getRenderOrder();
      bool processAddCompare = mgr->getProcessAddOrder() < list[i]->getProcessAddOrder();
      if ((renderOrder && renderCompare) || (!renderOrder && processAddCompare))
      {
         list.insert(i);
         list[i] = mgr;
         return;
      }
   }

   list.push_back(mgr);
}

void RenderPassManager::addManager(RenderBinManager* mgr)
{
   if ( !mgr->isProperlyAdded() )
      mgr->registerObject();

   AssertFatal( mgr->getRenderPass() == NULL, "RenderPassManager::addManager() - Bin is still part of another pass manager!" );
   mgr->setRenderPass( this );

   _insertSort(mRenderBins, mgr, true);
}

void RenderPassManager::removeManager(RenderBinManager* mgr)
{
   AssertFatal( mgr->getRenderPass() == this, "RenderPassManager::removeManager() - We do not own this bin!" );

   mgr->setRenderPass( NULL );
   mRenderBins.remove( mgr );
}

RenderBinManager* RenderPassManager::getManager(S32 i) const
{
   if (i >= 0 && i < mRenderBins.size())
      return mRenderBins[i];
   else
      return NULL;
}

void RenderPassManager::addInst( RenderInst *inst )
{
   PROFILE_SCOPE( RenderPassManager_addInst );

   AssertFatal( inst != NULL, "RenderPassManager::addInst - Got null instance!" );

   AddInstTable::Iterator iter = mAddInstSignals.find( inst->type );
   if ( iter == mAddInstSignals.end() )
      return;

   iter->value.trigger( inst );
}

void RenderPassManager::sort()
{
   PROFILE_SCOPE( RenderPassManager_Sort );

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      AssertFatal(*itr, "Render manager invalid!");
      (*itr)->sort();
   }
}

void RenderPassManager::clear()
{
   PROFILE_SCOPE( RenderPassManager_Clear );

   mChunker.clear();

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      AssertFatal(*itr, "Invalid render manager!");
      (*itr)->clear();
   }
}

void RenderPassManager::render(SceneRenderState * state)
{
   PROFILE_SCOPE( RenderPassManager_Render );

   GFX->pushWorldMatrix();
   MatrixF proj = GFX->getProjectionMatrix();

   for (Vector<RenderBinManager *>::iterator itr = mRenderBins.begin();
      itr != mRenderBins.end(); itr++)
   {
      RenderBinManager *curBin = *itr;
      AssertFatal(curBin, "Invalid render manager!");
      getRenderBinSignal().trigger(curBin, state, true);
      curBin->render(state);
      getRenderBinSignal().trigger(curBin, state, false);
   }

   GFX->popWorldMatrix();
   GFX->setProjectionMatrix( proj );

   // Restore a clean state for subsequent rendering.
   GFX->setupGenericShaders();
   for(S32 i = 0; i < GFX->getNumSamplers(); ++i)
      GFX->setTexture(i, NULL);
}

void RenderPassManager::renderPass(SceneRenderState * state)
{
   PROFILE_SCOPE( RenderPassManager_RenderPass );
   sort();
   render(state);
   clear();
}

GFXTextureObject *RenderPassManager::getDepthTargetTexture()
{
   // If this is OpenGL, or something else has set the depth buffer, return the pointer
   if( mDepthBuff.isValid() )
   {
      // If this is OpenGL, make sure the depth target matches up
      // with the active render target.  Otherwise recreate.

      if( GFX->getAdapterType() == OpenGL )
      {
         GFXTarget* activeRT = GFX->getActiveRenderTarget();
         AssertFatal( activeRT, "Must be an active render target to call 'getDepthTargetTexture'" );

         Point2I activeRTSize = activeRT->getSize();
         if( mDepthBuff.getWidth() == activeRTSize.x &&
             mDepthBuff.getHeight() == activeRTSize.y )
            return mDepthBuff.getPointer();
      }
      else
         return mDepthBuff.getPointer();
   }

   if(GFX->getAdapterType() == OpenGL)
   {
      AssertFatal(GFX->getActiveRenderTarget(), "Must be an active render target to call 'getDepthTargetTexture'");

      const Point2I rtSize = GFX->getActiveRenderTarget()->getSize();
      mDepthBuff.set(rtSize.x, rtSize.y, GFXFormatD24S8,
         &GFXDefaultZTargetProfile, avar("%s() - mDepthBuff (line %d)", __FUNCTION__, __LINE__));
      return mDepthBuff.getPointer();
   }

   // Default return value
   return GFXTextureTarget::sDefaultDepthStencil;
}

void RenderPassManager::setDepthTargetTexture( GFXTextureObject *zTarget )
{
   mDepthBuff = zTarget;
}

const MatrixF* RenderPassManager::allocSharedXform( SharedTransformType stt )
{
   AssertFatal(stt == View || stt == Projection, "Bad shared transform type");

   // Enable this to simulate non-shared transform performance
   //#define SIMULATE_NON_SHARED_TRANSFORMS
#ifdef SIMULATE_NON_SHARED_TRANSFORMS
   return allocUniqueXform(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#else
   return &(stt == View ? mMatrixSet->getWorldToCamera() : mMatrixSet->getCameraToScreen());
#endif
}

void RenderPassManager::assignSharedXform( SharedTransformType stt, const MatrixF &xfm )
{
   AssertFatal(stt == View || stt == Projection, "Bad shared transform type");
   if(stt == View)
      mMatrixSet->setSceneView(xfm);
   else
      mMatrixSet->setSceneProjection(xfm);
}

// Script interface

DefineEngineMethod(RenderPassManager, getManagerCount, S32, (),,
   "Returns the total number of bin managers." )
{
   return object->getManagerCount();
}

DefineEngineMethod( RenderPassManager, getManager, RenderBinManager*, ( S32 index ),,
   "Returns the render bin manager at the index or null if the index is out of range." )
{
   if(index < 0 || index >= object->getManagerCount())
      return NULL;

   return object->getManager(index);
}

DefineEngineMethod( RenderPassManager, addManager, void, ( RenderBinManager *renderBin ),,
   "Add as a render bin manager to the pass." )
{
   if ( renderBin )
      object->addManager( renderBin );
}

DefineEngineMethod( RenderPassManager, removeManager, void, ( RenderBinManager *renderBin ),,
   "Removes a render bin manager." )
{
   if ( renderBin )
      object->removeManager( renderBin );
}

<|endoftext|>


<commit_before> /* NEEDED??

 */

#include "SensorizerServer.h"

SensorizerServer::SensorizerServer() {
	//manually init array
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		sensorInputs[i] = NULL;
	}

	this->midiDevice = new MidiDevice();

	this->loadPreset();
}

SensorizerServer::~SensorizerServer() {
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL)
			delete sensorInputs[i];
	}

	delete this->midiDevice;
}

void SensorizerServer::init() {
	this->midiDevice->setup();

	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL)
			sensorInputs[i]->init();
	}

}

//reads all input devices values into the sensorInput objects.
//also sends all values from sensor inputs.
/*
void SensorizerServer::readAll() {
	//if (arduino != null) {
		//arduino bindings
		for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
	//		if (sensorInputs[i].deviceName == "arduino") {
				//float v = (float)arduino.analogRead(sensorInputs[i].getDeviceInputIdx()) / 1023.0f;
				//float v = arduino.read(sensorInputs[i].getDeviceInputIdx());
				float v = analogRead(i);

				//if (v > 0)
				//	Debug.print(Debug.DEBUG, "ardunio input " + i + ": " + v);

				sensorInputs[i]->setValue(v);
				sensorInputs[i]->send();
	//		}
		}
	//}
}
*/

void SensorizerServer::readPin(int pinIdx, int pinValue) {
	if (pinIdx >= SENSOR_INPUTS_LENGTH)
		return;

	float v = pinValue / 1024.0;

//DEBUG_PRINT_NUM("readPin pin: ", pinIdx)
//DEBUG_PRINT_NUM("readPin val: ", v)

	sensorInputs[pinIdx]->setValue(v);
	sensorInputs[pinIdx]->send();
}

void SensorizerServer::loadPreset() {
	int i = 0;
	SensorOutput* s;
	MidiMapping* m;

	//arduino 0
s = new SensorOutput();
s->inRange.low = 0.028571429;
s->inRange.high = 0.35;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.014285714;
s->cutoffRange.high = 0.95;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

// m = new MidiMapping(this->midiDevice);
// m->channel = 0;
// m->note = 60 + i;
// s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 1
s = new SensorOutput();
s->inRange.low = 0.021428572;
s->inRange.high = 0.44285715;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.057142872;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 57;//60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 2
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.47142863;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 3
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.5;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.07;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 4
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.5;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 5
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 1;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;
}

void SensorizerServer::loadNotes(byte notes[]) {
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL) {
			if (sensorInputs[i]->dropdownMidiMappings[0] != NULL)
				sensorInputs[i]->dropdownMidiMappings[0]->note = notes[i];
		}
	}
}
<commit_msg>fixed cutoff range<commit_after> /* NEEDED??

 */

#include "SensorizerServer.h"

SensorizerServer::SensorizerServer() {
	//manually init array
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		sensorInputs[i] = NULL;
	}

	this->midiDevice = new MidiDevice();

	this->loadPreset();
}

SensorizerServer::~SensorizerServer() {
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL)
			delete sensorInputs[i];
	}

	delete this->midiDevice;
}

void SensorizerServer::init() {
	this->midiDevice->setup();

	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL)
			sensorInputs[i]->init();
	}

}

//reads all input devices values into the sensorInput objects.
//also sends all values from sensor inputs.
/*
void SensorizerServer::readAll() {
	//if (arduino != null) {
		//arduino bindings
		for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
	//		if (sensorInputs[i].deviceName == "arduino") {
				//float v = (float)arduino.analogRead(sensorInputs[i].getDeviceInputIdx()) / 1023.0f;
				//float v = arduino.read(sensorInputs[i].getDeviceInputIdx());
				float v = analogRead(i);

				//if (v > 0)
				//	Debug.print(Debug.DEBUG, "ardunio input " + i + ": " + v);

				sensorInputs[i]->setValue(v);
				sensorInputs[i]->send();
	//		}
		}
	//}
}
*/

void SensorizerServer::readPin(int pinIdx, int pinValue) {
	if (pinIdx >= SENSOR_INPUTS_LENGTH)
		return;

	float v = pinValue / 1024.0;

//DEBUG_PRINT_NUM("readPin pin: ", pinIdx)
//DEBUG_PRINT_NUM("readPin val: ", v)

	sensorInputs[pinIdx]->setValue(v);
	sensorInputs[pinIdx]->send();
}

void SensorizerServer::loadPreset() {
	int i = 0;
	SensorOutput* s;
	MidiMapping* m;

	//arduino 0
s = new SensorOutput();
s->inRange.low = 0.028571429;
s->inRange.high = 0.35;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.014285714;
s->cutoffRange.high = 0.95;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

// m = new MidiMapping(this->midiDevice);
// m->channel = 0;
// m->note = 60 + i;
// s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 1
s = new SensorOutput();
s->inRange.low = 0.021428572;
s->inRange.high = 0.44285715;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.057142872;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 57;//60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 2
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.47142863;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 3
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.5;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 4
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 0.5;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;

//arduino 5
s = new SensorOutput();
s->inRange.low = 0;
s->inRange.high = 1;
s->outRange.low = 0;
s->outRange.high = 1;
s->cutoffRange.low = 0.1;
s->cutoffRange.high = 1;
s->setCutoffType(3); //Nullable
s->multiplyVal = 1;
s->addVal = 0;
s->isInvert = false;

m = new MidiMapping(this->midiDevice);
m->channel = 0;
m->note = 60 + i;
m->setMsgType(MidiMapping::NOTE_ONE_ONLY);
s->addMidiMapping(m);

sensorInputs[i++] = s;
}

void SensorizerServer::loadNotes(byte notes[]) {
	for (int i = 0; i < SENSOR_INPUTS_LENGTH; i++) {
		if (sensorInputs[i] != NULL) {
			if (sensorInputs[i]->dropdownMidiMappings[0] != NULL)
				sensorInputs[i]->dropdownMidiMappings[0]->note = notes[i];
		}
	}
}
<|endoftext|>