<commit_before>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <sstream>
#include <fstream>

#include "HBonds.hpp"
#include "Errors.hpp"
#include "utils.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const char OPTIONS[] =
R"(Compute list of hydrogen bonds along a trajectory. Selections for the acceptor and donor atoms
can be specified using the chemfiles selection language. It is possible to provide an alternative
unit cell or topology for the trajectory file if they are not defined in the trajectory format.
Hydrogen bonds are defined as electrostatic attraction between two polar groups: the acceptor group
is a hydrogen atom covalently bound to an electronegative atom (usually O, N, F) while
the donor group is another highly electronegative atom.
The criteria used depend on a maximum donor-acceptor distance and a maximum donor-acceptor-H angle.
Hydrogen bonds criteria can be specified.

For more information about chemfiles selection language, please see
http://chemfiles.org/chemfiles/latest/selections.html

Usage:
  cfiles hbonds [options] <trajectory>
  cfiles hbonds (-h | --help)

Examples:
  cfiles hbonds water.xyz --cell 15:15:25 --guess-bonds
  cfiles hbonds in.pdb --acceptors=="bonds: type(#1) == O and type(#2) == H"
  cfiles hbonds protein.pdb --donors=="atoms: type N" -p 2.5:20.0

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `_hb.dat` extension.
  --format=<format>             force the input file format to be <format>
  -t <path>, --topology=<path>  alternative topology file for the input
  --topology-format=<format>    use <format> as format for the topology file
  --guess-bonds                 guess the bonds in the input
  -c <cell>, --cell=<cell>      alternative unit cell. <cell> format is one of
                                <a:b:c:α:β:γ> or <a:b:c> or <a>. 'a', 'b' and
                                'c' are in angstroms, 'α', 'β', and 'γ' are in
                                degrees.
  --steps=<steps>               steps to use from the input. <steps> format
                                is <start>:<end>[:<stride>] with <start>, <end>
                                and <stride> optional. Default is to use all
                                steps from the input; starting at 0, ending at
                                the last step, and with a stride of 1.
  --acceptors=<sel>             selection to use for the acceptors. This must be a
                                selection of size 2 and type bonds The second atom
				should be the hydrogen atom.
                                [default: bonds: type(#2) == H]
  --donors=<sel>                selection to use for the donors. This must be a
                                selection of size 1.
                                [default: atoms: type O or type N or type F]
  --distance=<dist>             distance criterion to use for the hydrogen bond detection.
                                'dist' is the donor-acceptor maximum distance in angstroms.
                                [default: 3.0]
  --angle=<angle>               angle criterion to use for the hydrogen bond detection.
                                'angle' is the donor-acceptor-hydrogen maximum angle in degrees.
                                [default: 30.0]
)";

static HBonds::Options parse_options(int argc, const char* argv[]) {
    auto options_str = command_header("hbonds", HBonds().description()) + "\n";
    options_str += "Laura Scalfi <laura.scalfi@ens.fr>\n";
    options_str += OPTIONS;
    auto args = docopt::docopt(options_str, {argv, argv + argc}, true, "");

    HBonds::Options options;
    options.trajectory = args.at("<trajectory>").asString();
    options.guess_bonds = args.at("--guess-bonds").asBool();

    options.selection_acceptor = args.at("--acceptors").asString();
    options.selection_donor = args.at("--donors").asString();

    if (args.at("--output")){
        options.outfile = args.at("--output").asString();
    } else {
        options.outfile = options.trajectory + "_hb.dat";
    }

    if (args.at("--steps")) {
        options.steps = steps_range::parse(args.at("--steps").asString());
    }

    if (args.at("--format")){
        options.format = args.at("--format").asString();
    }

    if (args.at("--topology")){
        if (options.guess_bonds) {
            throw CFilesError("Can not use both '--topology' and '--guess-bonds'");
        }
        options.topology = args.at("--topology").asString();
    }

    if (args.at("--topology-format")){
        if (options.topology == "") {
            throw CFilesError("Useless '--topology-format' without '--topology'");
        }
        options.topology_format = args.at("--topology-format").asString();
    }

    if (args.at("--cell")) {
        options.custom_cell = true;
        options.cell = parse_cell(args.at("--cell").asString());
	}

    options.distance = 3.0;
    options.angle = 30.0;
    if (args.at("--distance")) {
        try {
            options.distance = std::stod(args.at("--distance").asString());
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for distance criterion");
        }
    }
    if (args.at("--angle")) {
        try {
            options.angle = std::stod(args.at("--angle").asString())*pi/180;
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for angle criterion");
        }
    }

    return options;
}

std::string HBonds::description() const {
    return "compute hydrogen bonds network";
}

int HBonds::run(int argc, const char* argv[]) {
    auto options = parse_options(argc, argv);

    selection_acceptor_ = Selection(options.selection_acceptor);
    if (selection_acceptor_.size() != 2) {
        throw CFilesError("Can not use a selection for acceptors with size different than 2.");
    }

    auto selection_string = split(selection_acceptor_.string(),':');
    if (selection_string[0] != "bonds") {
        throw CFilesError("'Bonds' type selection compulsory for acceptors.");
    }

    selection_donor_ = Selection(options.selection_donor);
    if (selection_donor_.size() != 1) {
        throw CFilesError("Can not use a selection for donors with size larger than 1.");
    }

    auto infile = Trajectory(options.trajectory, 'r', options.format);
    std::ofstream outfile(options.outfile, std::ios::out);
    if (outfile.is_open()) {
        outfile << "#Hydrogen bond network in trajectory " << options.trajectory << std::endl;
        outfile << "# Selection: acceptors: " << options.selection_acceptor;
        outfile << " and donors: " << options.selection_donor << std::endl;
        outfile << "# Criteria:" << std::endl;
        outfile << "# donor-acceptor distance < " << options.distance << " angstroms" << std::endl;
        outfile << "# donor-acceptor-H angle < " << options.angle*180/pi << " degrees" << std::endl;
    } else {
        throw CFilesError("Could not open the '" + options.outfile + "' file.");
    }

    if (options.custom_cell) {
        infile.set_cell(options.cell);
    }

    if (options.topology != "") {
        infile.set_topology(options.topology, options.topology_format);
    }

    for (auto step: options.steps) {
        if (step >= infile.nsteps()) {
            break;
        }
        auto frame = infile.read_step(step);
        if (options.guess_bonds) {
            frame.guess_topology();
        }

        outfile << "# Frame: " << step << std::endl;
        outfile << "# Donor   Acceptor   Hydrogen  : Distance D-A    Angle D-A-H" << std::endl;

        auto positions = frame.positions();
        auto cell = frame.cell();

        auto matched = selection_acceptor_.evaluate(frame);
        for (auto match: matched) {
            assert(match.size() == 2);

            size_t acceptor = static_cast<size_t>(-1);
            size_t hydrogen = static_cast<size_t>(-1);

            if (frame.topology()[match[0]].type() == "H") {
                acceptor = match[1];
                hydrogen = match[0];
            }
            else if (frame.topology()[match[1]].type() == "H") {
                acceptor = match[0];
                hydrogen = match[1];
            }
            else
            {
                throw CFilesError("Invalid acceptors selection: there is no hydrogen atom.");
            }

            auto donors = selection_donor_.list(frame);
            for (auto donor: donors) {
                if (donor != acceptor && frame.topology()[donor].type() != "H") {
                    auto r_ad = cell.wrap(positions[donor] - positions[acceptor]);
                    auto distance = norm(r_ad);
                    auto r_ah = cell.wrap(positions[hydrogen] - positions[acceptor]);
                    auto theta = angle(r_ad, r_ah);
                    if (distance < options.distance && theta < options.angle) {
                        outfile << frame.topology()[donor].type() << donor << "   ";
                        outfile << frame.topology()[acceptor].type() << acceptor << "   ";
                        outfile << frame.topology()[hydrogen].type() << hydrogen << "  : ";
                        outfile << distance << "    ";
                        outfile << theta*180/pi << std::endl;
                    }
                }
            }
        }
    }

    return 0;
}
<commit_msg>Output format with name and index<commit_after>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <sstream>
#include <fstream>

#include "HBonds.hpp"
#include "Errors.hpp"
#include "utils.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const char OPTIONS[] =
R"(Compute list of hydrogen bonds along a trajectory. Selections for the acceptor and donor atoms
can be specified using the chemfiles selection language. It is possible to provide an alternative
unit cell or topology for the trajectory file if they are not defined in the trajectory format.
Hydrogen bonds are defined as electrostatic attraction between two polar groups: the acceptor group
is a hydrogen atom covalently bound to an electronegative atom (usually O, N, F) while
the donor group is another highly electronegative atom.
The criteria used depend on a maximum donor-acceptor distance and a maximum donor-acceptor-H angle.
Hydrogen bonds criteria can be specified.

For more information about chemfiles selection language, please see
http://chemfiles.org/chemfiles/latest/selections.html

Usage:
  cfiles hbonds [options] <trajectory>
  cfiles hbonds (-h | --help)

Examples:
  cfiles hbonds water.xyz --cell 15:15:25 --guess-bonds
  cfiles hbonds in.pdb --acceptors=="bonds: type(#1) == O and type(#2) == H"
  cfiles hbonds protein.pdb --donors=="atoms: type N" -p 2.5:20.0

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `_hb.dat` extension.
  --format=<format>             force the input file format to be <format>
  -t <path>, --topology=<path>  alternative topology file for the input
  --topology-format=<format>    use <format> as format for the topology file
  --guess-bonds                 guess the bonds in the input
  -c <cell>, --cell=<cell>      alternative unit cell. <cell> format is one of
                                <a:b:c:α:β:γ> or <a:b:c> or <a>. 'a', 'b' and
                                'c' are in angstroms, 'α', 'β', and 'γ' are in
                                degrees.
  --steps=<steps>               steps to use from the input. <steps> format
                                is <start>:<end>[:<stride>] with <start>, <end>
                                and <stride> optional. Default is to use all
                                steps from the input; starting at 0, ending at
                                the last step, and with a stride of 1.
  --acceptors=<sel>             selection to use for the acceptors. This must be a
                                selection of size 2 and type bonds The second atom
				should be the hydrogen atom.
                                [default: bonds: type(#2) == H]
  --donors=<sel>                selection to use for the donors. This must be a
                                selection of size 1.
                                [default: atoms: type O or type N or type F]
  --distance=<dist>             distance criterion to use for the hydrogen bond detection.
                                'dist' is the donor-acceptor maximum distance in angstroms.
                                [default: 3.0]
  --angle=<angle>               angle criterion to use for the hydrogen bond detection.
                                'angle' is the donor-acceptor-hydrogen maximum angle in degrees.
                                [default: 30.0]
)";

static HBonds::Options parse_options(int argc, const char* argv[]) {
    auto options_str = command_header("hbonds", HBonds().description()) + "\n";
    options_str += "Laura Scalfi <laura.scalfi@ens.fr>\n";
    options_str += OPTIONS;
    auto args = docopt::docopt(options_str, {argv, argv + argc}, true, "");

    HBonds::Options options;
    options.trajectory = args.at("<trajectory>").asString();
    options.guess_bonds = args.at("--guess-bonds").asBool();

    options.selection_acceptor = args.at("--acceptors").asString();
    options.selection_donor = args.at("--donors").asString();

    if (args.at("--output")){
        options.outfile = args.at("--output").asString();
    } else {
        options.outfile = options.trajectory + "_hb.dat";
    }

    if (args.at("--steps")) {
        options.steps = steps_range::parse(args.at("--steps").asString());
    }

    if (args.at("--format")){
        options.format = args.at("--format").asString();
    }

    if (args.at("--topology")){
        if (options.guess_bonds) {
            throw CFilesError("Can not use both '--topology' and '--guess-bonds'");
        }
        options.topology = args.at("--topology").asString();
    }

    if (args.at("--topology-format")){
        if (options.topology == "") {
            throw CFilesError("Useless '--topology-format' without '--topology'");
        }
        options.topology_format = args.at("--topology-format").asString();
    }

    if (args.at("--cell")) {
        options.custom_cell = true;
        options.cell = parse_cell(args.at("--cell").asString());
	}

    options.distance = 3.0;
    options.angle = 30.0;
    if (args.at("--distance")) {
        try {
            options.distance = std::stod(args.at("--distance").asString());
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for distance criterion");
        }
    }
    if (args.at("--angle")) {
        try {
            options.angle = std::stod(args.at("--angle").asString())*pi/180;
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for angle criterion");
        }
    }

    return options;
}

std::string HBonds::description() const {
    return "compute hydrogen bonds network";
}

int HBonds::run(int argc, const char* argv[]) {
    auto options = parse_options(argc, argv);

    selection_acceptor_ = Selection(options.selection_acceptor);
    if (selection_acceptor_.size() != 2) {
        throw CFilesError("Can not use a selection for acceptors with size different than 2.");
    }

    auto selection_string = split(selection_acceptor_.string(),':');
    if (selection_string[0] != "bonds") {
        throw CFilesError("'Bonds' type selection compulsory for acceptors.");
    }

    selection_donor_ = Selection(options.selection_donor);
    if (selection_donor_.size() != 1) {
        throw CFilesError("Can not use a selection for donors with size larger than 1.");
    }

    auto infile = Trajectory(options.trajectory, 'r', options.format);
    std::ofstream outfile(options.outfile, std::ios::out);
    if (outfile.is_open()) {
        outfile << "#Hydrogen bond network in trajectory " << options.trajectory << std::endl;
        outfile << "# Selection: acceptors: " << options.selection_acceptor;
        outfile << " and donors: " << options.selection_donor << std::endl;
        outfile << "# Criteria:" << std::endl;
        outfile << "# donor-acceptor distance < " << options.distance << " angstroms" << std::endl;
        outfile << "# donor-acceptor-H angle < " << options.angle*180/pi << " degrees" << std::endl;
    } else {
        throw CFilesError("Could not open the '" + options.outfile + "' file.");
    }

    if (options.custom_cell) {
        infile.set_cell(options.cell);
    }

    if (options.topology != "") {
        infile.set_topology(options.topology, options.topology_format);
    }

    for (auto step: options.steps) {
        if (step >= infile.nsteps()) {
            break;
        }
        auto frame = infile.read_step(step);
        if (options.guess_bonds) {
            frame.guess_topology();
        }

        outfile << "# Frame: " << step << std::endl;
        outfile << "# Donor (name index)   Acceptor (name index)   Hydrogen (name index)  : Distance D-A    Angle D-A-H" << std::endl;

        auto positions = frame.positions();
        auto cell = frame.cell();

        auto matched = selection_acceptor_.evaluate(frame);
        for (auto match: matched) {
            assert(match.size() == 2);

            size_t acceptor = static_cast<size_t>(-1);
            size_t hydrogen = static_cast<size_t>(-1);

            if (frame.topology()[match[0]].type() == "H") {
                acceptor = match[1];
                hydrogen = match[0];
            } else if (frame.topology()[match[1]].type() == "H") {
                acceptor = match[0];
                hydrogen = match[1];
            } else
            {
                throw CFilesError("Invalid acceptors selection: there is no hydrogen atom.");
            }

            auto donors = selection_donor_.list(frame);
            for (auto donor: donors) {
                if (donor != acceptor && frame.topology()[donor].type() != "H") {
                    auto r_ad = cell.wrap(positions[donor] - positions[acceptor]);
                    auto distance = norm(r_ad);
                    auto r_ah = cell.wrap(positions[hydrogen] - positions[acceptor]);
                    auto theta = angle(r_ad, r_ah);
                    if (distance < options.distance && theta < options.angle) {
                        outfile << frame.topology()[donor].name() << " " << donor << "   ";
                        outfile << frame.topology()[acceptor].name() << " " << acceptor << "   ";
                        outfile << frame.topology()[hydrogen].name() << " " << hydrogen << "  : ";
                        outfile << distance << "    ";
                        outfile << theta*180/pi << std::endl;
                    }
                }
            }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdio.h>
#include <ctype.h>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;

//parses the entered command putting each string seperated
//by spaces into a vector passed in by reference
//the function utilizes strtok to do this
void parse(char  x[], vector<string> &v){
    char* tmp;
    //separates the string by spaces
    tmp = strtok(x, " ");
    while(tmp != NULL){
        //stores in the vector
        v.push_back(tmp);
        //searches for the next " " character
        tmp = strtok(NULL, " ");
    }
}

//the function returns false if the command passed in
//is "exit" or any spaced variation of it.
//returnd false otherwise
bool isExit(char x[]){
    string tmp = x;
    string hold = "exit";
    char spc = ' ';
    unsigned int k = 0;

    if(tmp.size() < hold.size()){
        return false;
    }

    for(unsigned int i = 0; i < tmp.size(); i++){
        if(tmp.at(i) != spc){
            if(k < hold.size() && tmp.at(i) != hold.at(k)){
                return false;
            }
            k++;
        }
    }
    if(k != hold.size()){
        return false;
    }
    else{
        return true;
    }
    /*
    //sets up any of the acceptable commands
    //to exit
    string ext = "exit";
    string ext2 = " exit";
    string ext3 = "exit ";
    string ext4 = " exit ";
    //checks if the command is eqaul to any of the acceptable forms
    //returning true if equal to any and false otherwise
    if(x == ext || x == ext2 || x == ext3 || x == ext4){
        return true;
    }
    else{
        return false;
    }
    */
}

//the function searches for the '#' and
//removes anything after that character
string commentRemoval(string x){
    int comm = x.find('#');
    //if no '#' is found return the entire string
    if(comm == -1){
        return x;
    }
    //if the '#' is the first character return nothing
    else if(comm == 0){
        return "";
    }
    //otherwise return every thing up to the '#'
    else{
        return x.substr(0, comm);
    }
}

//this function runs the command using fork and execvp
//and returns once all commands from the entered char[]
//have been executed
void run(char str[]){

    //needed to parse with strtok
    char* pch;

    //holds the bool of if a command executed properly
    bool sucs = true;

    //holds the return status of a fork/execvp
    int status = 0;

    //holds the connector used for the current list of comamnds
    string connector;

    //holds a string version of the passed in char[] for later
    //comparing
    string strz = str;

    //the vector that holds the commands to be converted and executed
    vector<string> cmd;

    //cbegins breaking the entered commands up by connector
    pch = strtok(str, ";");

    //if the command is empty return
    if(pch==NULL){
        return;
    }

    //if using strtok with ";" changed the strz
    //set the connector to be ";"
    else if(pch != strz){
        connector = ";";
    }
    //else if strz was unchanged use strtok with "&&"
    //if this changes the string is NULL return
    //of if strtok changed from the original value of strz set the connector
    if(pch == strz){
        pch = strtok(str, "&&");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "&&";
        }
    }
    //repeat the above process but with "||" instead of "&&"
    if(pch == strz){
        pch = strtok(str, "||");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "||";
        }
    }

    //if the pch is not NULL and is the exit command exit the programm
    if(pch != NULL && isExit(pch)){
        exit(0);
    }

    //this while loop is where fork and execvp execute commands
    while(pch != NULL){
        //fork the programm
        int pid = fork();
        //if pid is -1 the fork failed so exit
        if(pid == -1){
            perror("fork");
            exit(1);
        }
        //if the pid is 0 the current id the current process is the child
        else if(pid == 0){
            //call the parsing function on the command and the cmd vector
            //to break it up into command and params
            parse(pch, cmd);
            //set the size of the dynamic char** that will be passed into execvp
            int cmd_size = cmd.size() + 1;
            char** argc = new char*[cmd_size];
            //for each string in cmd copy it into argc, which will be passed
            //into execvp
            for(unsigned int i = 0 ; i < cmd.size(); i++ ){
                argc[i] = new char[cmd.at(i).size()];
                strcpy(argc[i], cmd.at(i).c_str());
            }
            //set the last value of argc to be NULL so that execvp will work properly
            argc[cmd.size()] = NULL;
            //call execvp on the first element of argc and the entirety of it
            //if it returns -1 it has failed fo print an error and delete
            //the dynamically allocated memory
            if(-1 ==  execvp(argc[0], argc)){
                perror("execvp");
                delete[] argc;
                exit(1);
            }
        }
        //otherwise it is the parrent process
        else{
            //wait for any process to exit, in this case I only created on,
            //and store its exit code in status
            waitpid(-1, &status, 0);

            //if the value of status is larger than 0
            //it failed
            if(status > 0){
                sucs = false;
            }
            //otherwise if succeeded
            else{
                sucs = true;
            }

            //clear the vector holding the command to execute
	        cmd.clear();

            //run the next command if the connector logic and value of sucs allow it
            if((connector=="&&" && sucs) || (connector=="||" && !sucs) || (connector==";")){
                pch = strtok(NULL, connector.c_str());
            }
            //otherwise return
            else{
                return;
            }
            //if the next command is not NULL and is exit exit the program
            if(pch != NULL && isExit(pch)){
                exit(0);
            }
        }
    }
    //if there are no more commands to execute/parse return
    return;
}

//main takes in commands and passes them to run to execute
int main(){
    //continue until terminated by a conditional branch within run
    while(true){
        //get the users command including all spaces
        string input;
        cout << "$ ";
        getline(cin, input);

        //remove anything that is a comment from the users input
        input = commentRemoval(input);

        //determines the size of the input
        int input_size = input.size()+1;
        //dynamically allocates a char*[] of the size of the input + 1
        char* str = new char[input_size];
        //copies the input into the char* str[]
        strcpy(str, input.c_str());
        //calls run on the users entered commands
        run(str);
        //after running the dynamically allocated memory is deleted
        delete[] str;
   }
   return 0;
}
<commit_msg>fixed a bug with the exit command<commit_after>#include <iostream>
#include <stdio.h>
#include <ctype.h>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;

//parses the entered command putting each string seperated
//by spaces into a vector passed in by reference
//the function utilizes strtok to do this
void parse(char  x[], vector<string> &v){
    char* tmp;
    //separates the string by spaces
    tmp = strtok(x, " ");
    while(tmp != NULL){
        //stores in the vector
        v.push_back(tmp);
        //searches for the next " " character
        tmp = strtok(NULL, " ");
    }
}

//the function returns false if the command passed in
//is "exit" or any spaced variation of it.
//returnd false otherwise
bool isExit(char x[]){
    //sets up vars necessary for comparison
    string tmp = x;
    string hold = "exit";
    char spc = ' ';
    unsigned int k = 0;

    //if the size of the passed in char[] is less than that
    //necessary for it to be exit return false
    if(tmp.size() < hold.size()){
        return false;
    }

    //check each non-space character if within the first
    //four characters any of the characters dont align with "exit" return false
    //otherwise count how many more characters there are in the passed in string
    //if there are more than 4 return false otherwise return true
    //if a space appears when k is > 0 but < 4 return false, this prevents
    //bugs like "exi t" from working
    for(unsigned int i = 0; i < tmp.size(); i++){
        if(tmp.at(i) != spc){
            if(k < hold.size() && tmp.at(i) != hold.at(k)){
                return false;
            }
            k++;
        }
        else if(k > 0 && k < hold.size()){
            return false;
        }
    }
    if(k != hold.size()){
        return false;
    }
    else{
        return true;
    }
    //alternative way to parse that causes a bug when calling exit
    /*
    //sets up any of the acceptable commands
    //to exit
    string ext = "exit";
    string ext2 = " exit";
    string ext3 = "exit ";
    string ext4 = " exit ";
    //checks if the command is eqaul to any of the acceptable forms
    //returning true if equal to any and false otherwise
    if(x == ext || x == ext2 || x == ext3 || x == ext4){
        return true;
    }
    else{
        return false;
    }
    */
}

//the function searches for the '#' and
//removes anything after that character
string commentRemoval(string x){
    int comm = x.find('#');
    //if no '#' is found return the entire string
    if(comm == -1){
        return x;
    }
    //if the '#' is the first character return nothing
    else if(comm == 0){
        return "";
    }
    //otherwise return every thing up to the '#'
    else{
        return x.substr(0, comm);
    }
}

//this function runs the command using fork and execvp
//and returns once all commands from the entered char[]
//have been executed
void run(char str[]){

    //needed to parse with strtok
    char* pch;

    //holds the bool of if a command executed properly
    bool sucs = true;

    //holds the return status of a fork/execvp
    int status = 0;

    //holds the connector used for the current list of comamnds
    string connector;

    //holds a string version of the passed in char[] for later
    //comparing
    string strz = str;

    //the vector that holds the commands to be converted and executed
    vector<string> cmd;

    //cbegins breaking the entered commands up by connector
    pch = strtok(str, ";");

    //if the command is empty return
    if(pch==NULL){
        return;
    }

    //if using strtok with ";" changed the strz
    //set the connector to be ";"
    else if(pch != strz){
        connector = ";";
    }
    //else if strz was unchanged use strtok with "&&"
    //if this changes the string is NULL return
    //of if strtok changed from the original value of strz set the connector
    if(pch == strz){
        pch = strtok(str, "&&");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "&&";
        }
    }
    //repeat the above process but with "||" instead of "&&"
    if(pch == strz){
        pch = strtok(str, "||");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "||";
        }
    }

    //if the pch is not NULL and is the exit command exit the programm
    if(pch != NULL && isExit(pch)){
        exit(0);
    }

    //this while loop is where fork and execvp execute commands
    while(pch != NULL){
        //fork the programm
        int pid = fork();
        //if pid is -1 the fork failed so exit
        if(pid == -1){
            perror("fork");
            exit(1);
        }
        //if the pid is 0 the current id the current process is the child
        else if(pid == 0){
            //call the parsing function on the command and the cmd vector
            //to break it up into command and params
            parse(pch, cmd);
            //set the size of the dynamic char** that will be passed into execvp
            int cmd_size = cmd.size() + 1;
            char** argc = new char*[cmd_size];
            //for each string in cmd copy it into argc, which will be passed
            //into execvp
            for(unsigned int i = 0 ; i < cmd.size(); i++ ){
                argc[i] = new char[cmd.at(i).size()];
                strcpy(argc[i], cmd.at(i).c_str());
            }
            //set the last value of argc to be NULL so that execvp will work properly
            argc[cmd.size()] = NULL;
            //call execvp on the first element of argc and the entirety of it
            //if it returns -1 it has failed fo print an error and delete
            //the dynamically allocated memory
            if(-1 ==  execvp(argc[0], argc)){
                perror("execvp");
                delete[] argc;
                exit(1);
            }
        }
        //otherwise it is the parrent process
        else{
            //wait for any process to exit, in this case I only created on,
            //and store its exit code in status
            waitpid(-1, &status, 0);

            //if the value of status is larger than 0
            //it failed
            if(status > 0){
                sucs = false;
            }
            //otherwise if succeeded
            else{
                sucs = true;
            }

            //clear the vector holding the command to execute
	        cmd.clear();

            //run the next command if the connector logic and value of sucs allow it
            if((connector=="&&" && sucs) || (connector=="||" && !sucs) || (connector==";")){
                pch = strtok(NULL, connector.c_str());
            }
            //otherwise return
            else{
                return;
            }
            //if the next command is not NULL and is exit exit the program
            if(pch != NULL && isExit(pch)){
                exit(0);
            }
        }
    }
    //if there are no more commands to execute/parse return
    return;
}

//main takes in commands and passes them to run to execute
int main(){
    //continue until terminated by a conditional branch within run
    while(true){
        //get the users command including all spaces
        string input;
        cout << "$ ";
        getline(cin, input);

        //remove anything that is a comment from the users input
        input = commentRemoval(input);

        //determines the size of the input
        int input_size = input.size()+1;
        //dynamically allocates a char*[] of the size of the input + 1
        char* str = new char[input_size];
        //copies the input into the char* str[]
        strcpy(str, input.c_str());
        //calls run on the users entered commands
        run(str);
        //after running the dynamically allocated memory is deleted
        delete[] str;
   }
   return 0;
}
<|endoftext|>


<commit_before>#include "Layer.h"
#include <vector>

Layer::Layer(int neuronCount, int inputCount, float momentum, float learningConstant){
  this->neurons.resize(neuronCount + 1);
  this->inputs = inputCount;
  for(int i = 0; i < neuronCount; i++){
    this->neurons[i] = new Neuron(inputCount, learningConstant, momentum);
  }
  this->neurons[neuronCount] = new BiasNeuron();
}

std::vector<float> Layer::feed(std::vector<float> in){
  std::vector<float> out;
  out.resize(this->getSize());
  for(int i = 0; i < this->getSize(); i++){
    out[i] = this->neurons[i]->feed(in);
  }
  return out;
}

int Layer::getSize(){
  return this->neurons.size();
}

OutputLayer::OutputLayer(int neuronCount, int inputCount, float momentum, float learningConstant) :
 Layer(neuronCount, inputCount, momentum, learningConstant){

 }
<commit_msg>Added the HiddenLayer constructor<commit_after>#include "Layer.h"
#include <vector>

Layer::Layer(int neuronCount, int inputCount, float momentum, float learningConstant){
  this->neurons.resize(neuronCount + 1);
  this->inputs = inputCount;
  for(int i = 0; i < neuronCount; i++){
    this->neurons[i] = new Neuron(inputCount, learningConstant, momentum);
  }
  this->neurons[neuronCount] = new BiasNeuron();
}

std::vector<float> Layer::feed(std::vector<float> in){
  std::vector<float> out;
  out.resize(this->getSize());
  for(int i = 0; i < this->getSize(); i++){
    out[i] = this->neurons[i]->feed(in);
  }
  return out;
}

int Layer::getSize(){
  return this->neurons.size();
}

OutputLayer::OutputLayer(int neuronCount, int inputCount, float momentum, float learningConstant) :
 Layer(neuronCount, inputCount, momentum, learningConstant){

 }

 HiddenLayer::HiddenLayer(int neuronCount, int inputCount, float momentum, float learningConstant):
  Layer(neuronCount, inputCount, momentum, learningConstant){

  }
<|endoftext|>


<commit_before>/***********************************
 Copyright 2019 Ravishankar Mathur

 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 Model.cpp
 * Definitions for the Model class.
 */

#include <OpenFrames/Model.hpp>
#include <osg/Geode>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgManipulator/TrackballDragger>
#include <osgParticle/ParticleSystem>
#include <osgDB/ReadFile>
#include <osgVolume/Volume>
#include <iostream>

namespace OpenFrames
{

  Model::Model( const std::string &name)
  : ReferenceFrame(name)
  {
    init();
  }

  Model::Model( const std::string &name, const osg::Vec3 &color)
  : ReferenceFrame(name, color)
  {
    init();
  }

  Model::Model( const std::string &name, const osg::Vec4 &color)
  : ReferenceFrame(name, color)
  {
    init();
  }

  Model::Model( const std::string &name, float r, float g, float b, float a)
  : ReferenceFrame(name, r, g, b, a)
  {
    init();
  }

  Model::~Model() { }

  void Model::showContents(bool showContents)
  {
    if(showContents)
    {
      _modelXform->setNodeMask(~0x0);
      _extras->setNodeMask(~0x0);
    }
    else
    {
      _modelXform->setNodeMask(0x0);
      _extras->setNodeMask(0x0);
    }
  }

  bool Model::getContentsShown() const
  {
    return ((_modelXform->getNodeMask() != 0x0) || (_extras->getNodeMask() != 0x0));
  }

  void Model::init()
  {
    _modelXform = new FrameTransform;
    _xform->addChild(_modelXform);
    _extras = new osg::Geode;
    _extras->setName(_name + " extras");
    _group = new osg::Group;
    _group->addChild(_xform.get());
    _group->addChild(_extras.get());
  }

  osg::Group* Model::getGroup() const
  {
    return _group.get();
  }

  /********************************************************/
  bool Model::setModel( const std::string& filename, bool force_reload )
  {
    // First check if we are reloading the same model file (assuming it has the same name)
    if(_model.valid() && (_model->getName() == filename) && !force_reload) return true;

    // Read the new model file (if a filename is given)
    osg::Node *newModel = NULL;
    if(filename.length() > 0)
    {
      newModel = osgDB::readNodeFile(filename);
    }

    // Next, remove existing data if needed
    if((filename.length() == 0) || (newModel != NULL))
    {
      // Remove current model
      _modelXform->removeChild(_model.get());
      _model = NULL;

      // Remove existing ParticleSystems
      _extras->removeDrawables(0, _extras->getNumDrawables());

      // No filename given, so just reset axes and quit
      if(filename.length() == 0)
      {
        moveXAxis(osg::Vec3d(), 1);
        moveYAxis(osg::Vec3d(), 1);
        moveZAxis(osg::Vec3d(), 1);
        return true;
      }
    }
    else
    {
      std::cerr<< "Model ERROR: Model file \'" << filename << "\' could not be loaded!" << std::endl;
      return false; // Model could not be loaded
    }

    _model = newModel; // Set new model
    _model->setName(filename);

    /* If the model's root node is a group, iterate through its children
     to find any osg::ParticleSystem children.  Then move those children
     to our group so they are not affected by this frame's transform.
     This is done because ParticleSystems need to be in world space. */
    osg::Group *modelGroup = dynamic_cast<osg::Group*>(_model.get());
    if(modelGroup)
    {
      osg::Geode *modelGeode;
      osgParticle::ParticleSystem *ps;

      // Find each Geode, since that could contain a ParticleSystem
      for(unsigned int i = 0; i < modelGroup->getNumChildren(); ++i)
      {
        modelGeode = dynamic_cast<osg::Geode*>(modelGroup->getChild(i));
        if(modelGeode)
        {
          // Search through the Geode for a ParticleSystem
          for(unsigned int j = 0; j < modelGeode->getNumDrawables(); ++j)
          {
            ps = dynamic_cast<osgParticle::ParticleSystem*>(modelGeode->getDrawable(j));
            if(ps) // ParticleSystem found
            {
              _extras->addDrawable(ps);
              modelGeode->removeDrawable(ps);
              --j;
            }
          }

          // Delete the Geode if it's empty
          if(modelGeode->getNumDrawables() == 0)
          {
            modelGroup->removeChild(modelGeode);
            --i;
          }
        }
      }
    }

    // If the model is an osgVolume tile then add a volume above it
    bool rescaleNormals = true;
    osg::ref_ptr<osgVolume::VolumeTile> volumeTile = dynamic_cast<osgVolume::VolumeTile*>(_model.get());
    if (volumeTile)
    {
      OSG_NOTICE << "OpenFrames::Model loading volume" << std::endl;
      rescaleNormals = false;
      osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
      volume->addChild(_model);
      _model = volume;
      _model->setName(filename);
    }

    // Add the new model to this frame
    _modelXform->addChild(_model.get());

    // Rescale normals in case we want to scale the model
    if(rescaleNormals) _model->getOrCreateStateSet()->setMode( GL_RESCALE_NORMAL, osg::StateAttribute::ON );

    // Set the model pivot at its geometric center, so that scales/rotations will make sense.
    osg::Vec3d center = _model->getBound()._center;
    setModelPivot(center[0], center[1], center[2]);

    return true;
  }

  /********************************************************/
  bool Model::shareModel( const Model* otherModel )
  {
    if(!setModel("")) return false; // Clear any existing data

    _model = otherModel->getModel(); // Get model data
    if(!_model.valid()) return true; // No model to share

    // Add the new model to this frame
    _modelXform->addChild(_model.get());

    // Set the model pivot at its geometric center, so that scales/rotations will make sense.
    osg::Vec3d center = _model->getBound()._center;
    setModelPivot(center[0], center[1], center[2]);

    // Get any extras such as ParticleSystems
    osg::Geode *otherExtras = otherModel->getExtras();
    if(otherExtras->getNumDrawables() > 0)
    {
      // Get all drawables
      for(unsigned int i = 0; i < otherExtras->getNumDrawables(); ++i)
      {
        _extras->addDrawable(otherExtras->getDrawable(i));
      }
    }

    return true;
  }

  /** Set the position of the model wrt its own ReferenceFrame. */
  void Model::setModelPosition( const double &x, const double &y, const double &z)
  {
    _modelXform->setPosition(x, y, z);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Set the scale of the model wrt the pivot point. */
  void Model::setModelScale( const double &sx, const double &sy, const double &sz)
  {
    if((sx == 0.0) || (sy == 0.0) || (sz == 0.0)) return;

    _modelXform->setScale(sx, sy, sz);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Set/get the pivot point of the model. */
  void Model::setModelPivot(const double &px, const double &py, const double &pz)
  {
    _modelXform->setPivot(px, py, pz);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Enable model dragging */
  void Model::addDraggerCallback(osgManipulator::DraggerCallback* callback)
  {
    // Create dragger if needed
    if(!_dragger.valid())
    {
      _draggerXform = new osg::MatrixTransform;
      _xform->addChild(_draggerXform);

      osgManipulator::TrackballDragger* draggerTrackball = new osgManipulator::TrackballDragger();
      draggerTrackball->setAxisLineWidth(5.0);
      draggerTrackball->setupDefaultGeometry();

      _dragger = draggerTrackball;
      _xform->addChild(_dragger);
      const osg::BoundingSphere& bound = getBound();
      float scale = bound.radius();
      _dragger->setMatrix(osg::Matrix::scale(scale, scale, scale) *
                          osg::Matrix::translate(-(bound.center())));
      _dragger->setHandleEvents(true);
      _dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_CTRL);

      ModelDraggerTransformCallback* draggerCallback = new ModelDraggerTransformCallback(_modelXform.get(), _draggerXform.get());
      _dragger->addDraggerCallback(draggerCallback);
    }

    // Add given callback to dragger
    if(callback != nullptr) _dragger->addDraggerCallback(callback);
  }

  /** Move the model's x/y/z axes to default positions. */
  void Model::repositionAxes()
  {
    if(_model) // If model exists, move the axes to the its bounds
    {
      // Get the model's transformed bounding sphere
      osg::BoundingSphere bs = _modelXform->getBound();

      // Place the axes at the edge of the bounding sphere
      moveXAxis(bs._center + osg::Vec3(bs._radius, 0, 0), 0.5*bs._radius);
      moveYAxis(bs._center + osg::Vec3(0, bs._radius, 0), 0.5*bs._radius);
      moveZAxis(bs._center + osg::Vec3(0, 0, bs._radius), 0.5*bs._radius);
    }
    else // Otherwise move its axes to the origin
    {
      moveXAxis(osg::Vec3(0, 0, 0), 1.0);
      moveYAxis(osg::Vec3(0, 0, 0), 1.0);
      moveZAxis(osg::Vec3(0, 0, 0), 1.0);
    }
  }

  const osg::BoundingSphere& Model::getBound() const
  {
    // If model exists, have bounding sphere encompass it and the
    // axes/labels, but keep it centered on the model since that is
    // the object of interest.
    ReferenceFrame::getBound();
    if(_model.valid())
    {
      osg::BoundingSphere bs = _modelXform->getBound();
      bs.expandRadiusBy(_bound);
      _bound = bs;
    }

    return _bound;
  }

  /*****************************************************************/
  ModelDraggerTransformCallback::ModelDraggerTransformCallback(FrameTransform* modelxform, osg::MatrixTransform* draggerxform)
  : osgManipulator::DraggerTransformCallback(draggerxform), _modelXform(modelxform)
  { }

  bool ModelDraggerTransformCallback::receive(const osgManipulator::MotionCommand& command)
  {
    if(!osgManipulator::DraggerTransformCallback::receive(command)) return false;

    // For a MOVE command, decompose the transformation matrix
    // TODO: Directly compute transformation components without using intermediate MatrixTransform
    if((command.getStage() == osgManipulator::MotionCommand::MOVE) && _modelXform.valid())
    {
      osg::Vec3d trans, scale;
      osg::Quat rot, rotSO;
      _transform->getMatrix().decompose(trans, rot, scale, rotSO);
      _modelXform->setPosition(trans);
      _modelXform->setAttitude(rot);
    }

    return true;
  }

} // !namespace OpenFrames
<commit_msg>Enable left-ctrl key for dragger activation (temp fix for OSG 3.6.5 change in mod key handling)<commit_after>/***********************************
 Copyright 2019 Ravishankar Mathur

 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 Model.cpp
 * Definitions for the Model class.
 */

#include <OpenFrames/Model.hpp>
#include <osg/Geode>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgManipulator/TrackballDragger>
#include <osgParticle/ParticleSystem>
#include <osgDB/ReadFile>
#include <osgVolume/Volume>
#include <iostream>

namespace OpenFrames
{

  Model::Model( const std::string &name)
  : ReferenceFrame(name)
  {
    init();
  }

  Model::Model( const std::string &name, const osg::Vec3 &color)
  : ReferenceFrame(name, color)
  {
    init();
  }

  Model::Model( const std::string &name, const osg::Vec4 &color)
  : ReferenceFrame(name, color)
  {
    init();
  }

  Model::Model( const std::string &name, float r, float g, float b, float a)
  : ReferenceFrame(name, r, g, b, a)
  {
    init();
  }

  Model::~Model() { }

  void Model::showContents(bool showContents)
  {
    if(showContents)
    {
      _modelXform->setNodeMask(~0x0);
      _extras->setNodeMask(~0x0);
    }
    else
    {
      _modelXform->setNodeMask(0x0);
      _extras->setNodeMask(0x0);
    }
  }

  bool Model::getContentsShown() const
  {
    return ((_modelXform->getNodeMask() != 0x0) || (_extras->getNodeMask() != 0x0));
  }

  void Model::init()
  {
    _modelXform = new FrameTransform;
    _xform->addChild(_modelXform);
    _extras = new osg::Geode;
    _extras->setName(_name + " extras");
    _group = new osg::Group;
    _group->addChild(_xform.get());
    _group->addChild(_extras.get());
  }

  osg::Group* Model::getGroup() const
  {
    return _group.get();
  }

  /********************************************************/
  bool Model::setModel( const std::string& filename, bool force_reload )
  {
    // First check if we are reloading the same model file (assuming it has the same name)
    if(_model.valid() && (_model->getName() == filename) && !force_reload) return true;

    // Read the new model file (if a filename is given)
    osg::Node *newModel = NULL;
    if(filename.length() > 0)
    {
      newModel = osgDB::readNodeFile(filename);
    }

    // Next, remove existing data if needed
    if((filename.length() == 0) || (newModel != NULL))
    {
      // Remove current model
      _modelXform->removeChild(_model.get());
      _model = NULL;

      // Remove existing ParticleSystems
      _extras->removeDrawables(0, _extras->getNumDrawables());

      // No filename given, so just reset axes and quit
      if(filename.length() == 0)
      {
        moveXAxis(osg::Vec3d(), 1);
        moveYAxis(osg::Vec3d(), 1);
        moveZAxis(osg::Vec3d(), 1);
        return true;
      }
    }
    else
    {
      std::cerr<< "Model ERROR: Model file \'" << filename << "\' could not be loaded!" << std::endl;
      return false; // Model could not be loaded
    }

    _model = newModel; // Set new model
    _model->setName(filename);

    /* If the model's root node is a group, iterate through its children
     to find any osg::ParticleSystem children.  Then move those children
     to our group so they are not affected by this frame's transform.
     This is done because ParticleSystems need to be in world space. */
    osg::Group *modelGroup = dynamic_cast<osg::Group*>(_model.get());
    if(modelGroup)
    {
      osg::Geode *modelGeode;
      osgParticle::ParticleSystem *ps;

      // Find each Geode, since that could contain a ParticleSystem
      for(unsigned int i = 0; i < modelGroup->getNumChildren(); ++i)
      {
        modelGeode = dynamic_cast<osg::Geode*>(modelGroup->getChild(i));
        if(modelGeode)
        {
          // Search through the Geode for a ParticleSystem
          for(unsigned int j = 0; j < modelGeode->getNumDrawables(); ++j)
          {
            ps = dynamic_cast<osgParticle::ParticleSystem*>(modelGeode->getDrawable(j));
            if(ps) // ParticleSystem found
            {
              _extras->addDrawable(ps);
              modelGeode->removeDrawable(ps);
              --j;
            }
          }

          // Delete the Geode if it's empty
          if(modelGeode->getNumDrawables() == 0)
          {
            modelGroup->removeChild(modelGeode);
            --i;
          }
        }
      }
    }

    // If the model is an osgVolume tile then add a volume above it
    bool rescaleNormals = true;
    osg::ref_ptr<osgVolume::VolumeTile> volumeTile = dynamic_cast<osgVolume::VolumeTile*>(_model.get());
    if (volumeTile)
    {
      OSG_NOTICE << "OpenFrames::Model loading volume" << std::endl;
      rescaleNormals = false;
      osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
      volume->addChild(_model);
      _model = volume;
      _model->setName(filename);
    }

    // Add the new model to this frame
    _modelXform->addChild(_model.get());

    // Rescale normals in case we want to scale the model
    if(rescaleNormals) _model->getOrCreateStateSet()->setMode( GL_RESCALE_NORMAL, osg::StateAttribute::ON );

    // Set the model pivot at its geometric center, so that scales/rotations will make sense.
    osg::Vec3d center = _model->getBound()._center;
    setModelPivot(center[0], center[1], center[2]);

    return true;
  }

  /********************************************************/
  bool Model::shareModel( const Model* otherModel )
  {
    if(!setModel("")) return false; // Clear any existing data

    _model = otherModel->getModel(); // Get model data
    if(!_model.valid()) return true; // No model to share

    // Add the new model to this frame
    _modelXform->addChild(_model.get());

    // Set the model pivot at its geometric center, so that scales/rotations will make sense.
    osg::Vec3d center = _model->getBound()._center;
    setModelPivot(center[0], center[1], center[2]);

    // Get any extras such as ParticleSystems
    osg::Geode *otherExtras = otherModel->getExtras();
    if(otherExtras->getNumDrawables() > 0)
    {
      // Get all drawables
      for(unsigned int i = 0; i < otherExtras->getNumDrawables(); ++i)
      {
        _extras->addDrawable(otherExtras->getDrawable(i));
      }
    }

    return true;
  }

  /** Set the position of the model wrt its own ReferenceFrame. */
  void Model::setModelPosition( const double &x, const double &y, const double &z)
  {
    _modelXform->setPosition(x, y, z);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Set the scale of the model wrt the pivot point. */
  void Model::setModelScale( const double &sx, const double &sy, const double &sz)
  {
    if((sx == 0.0) || (sy == 0.0) || (sz == 0.0)) return;

    _modelXform->setScale(sx, sy, sz);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Set/get the pivot point of the model. */
  void Model::setModelPivot(const double &px, const double &py, const double &pz)
  {
    _modelXform->setPivot(px, py, pz);

    repositionAxes(); // Reset the x/y/z axes
  }

  /** Enable model dragging */
  void Model::addDraggerCallback(osgManipulator::DraggerCallback* callback)
  {
    // Create dragger if needed
    if(!_dragger.valid())
    {
      _draggerXform = new osg::MatrixTransform;
      _xform->addChild(_draggerXform);

      osgManipulator::TrackballDragger* draggerTrackball = new osgManipulator::TrackballDragger();
      draggerTrackball->setAxisLineWidth(5.0);
      draggerTrackball->setupDefaultGeometry();

      _dragger = draggerTrackball;
      _xform->addChild(_dragger);
      const osg::BoundingSphere& bound = getBound();
      float scale = bound.radius();
      _dragger->setMatrix(osg::Matrix::scale(scale, scale, scale) *
                          osg::Matrix::translate(-(bound.center())));
      _dragger->setHandleEvents(true);
      _dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_CTRL);
      _dragger->setActivationKeyEvent(osgGA::GUIEventAdapter::KEY_Control_L);

      ModelDraggerTransformCallback* draggerCallback = new ModelDraggerTransformCallback(_modelXform.get(), _draggerXform.get());
      _dragger->addDraggerCallback(draggerCallback);
    }

    // Add given callback to dragger
    if(callback != nullptr) _dragger->addDraggerCallback(callback);
  }

  /** Move the model's x/y/z axes to default positions. */
  void Model::repositionAxes()
  {
    if(_model) // If model exists, move the axes to the its bounds
    {
      // Get the model's transformed bounding sphere
      osg::BoundingSphere bs = _modelXform->getBound();

      // Place the axes at the edge of the bounding sphere
      moveXAxis(bs._center + osg::Vec3(bs._radius, 0, 0), 0.5*bs._radius);
      moveYAxis(bs._center + osg::Vec3(0, bs._radius, 0), 0.5*bs._radius);
      moveZAxis(bs._center + osg::Vec3(0, 0, bs._radius), 0.5*bs._radius);
    }
    else // Otherwise move its axes to the origin
    {
      moveXAxis(osg::Vec3(0, 0, 0), 1.0);
      moveYAxis(osg::Vec3(0, 0, 0), 1.0);
      moveZAxis(osg::Vec3(0, 0, 0), 1.0);
    }
  }

  const osg::BoundingSphere& Model::getBound() const
  {
    // If model exists, have bounding sphere encompass it and the
    // axes/labels, but keep it centered on the model since that is
    // the object of interest.
    ReferenceFrame::getBound();
    if(_model.valid())
    {
      osg::BoundingSphere bs = _modelXform->getBound();
      bs.expandRadiusBy(_bound);
      _bound = bs;
    }

    return _bound;
  }

  /*****************************************************************/
  ModelDraggerTransformCallback::ModelDraggerTransformCallback(FrameTransform* modelxform, osg::MatrixTransform* draggerxform)
  : osgManipulator::DraggerTransformCallback(draggerxform), _modelXform(modelxform)
  { }

  bool ModelDraggerTransformCallback::receive(const osgManipulator::MotionCommand& command)
  {
    if(!osgManipulator::DraggerTransformCallback::receive(command)) return false;

    // For a MOVE command, decompose the transformation matrix
    // TODO: Directly compute transformation components without using intermediate MatrixTransform
    if((command.getStage() == osgManipulator::MotionCommand::MOVE) && _modelXform.valid())
    {
      osg::Vec3d trans, scale;
      osg::Quat rot, rotSO;
      _transform->getMatrix().decompose(trans, rot, scale, rotSO);
      _modelXform->setPosition(trans);
      _modelXform->setAttitude(rot);
    }

    return true;
  }

} // !namespace OpenFrames
<|endoftext|>


<commit_before>/*
 * Jamoma DSP Audio Buffer Object
 * Copyright © 2003, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

#define thisTTClass			TTBuffer
#define thisTTClassName		"buffer"
#define thisTTClassTags		"audio, buffer"

TTObjectPtr TTBuffer::instantiate(TTSymbolPtr name, TTValue& arguments)
{
	return new TTBuffer(arguments);
}

extern "C" void TTBuffer::registerClass()
{
	TTClassRegister(TT("buffer"), thisTTClassTags, TTBuffer::instantiate);
}

TTBuffer::TTBuffer(TTValue& arguments) :
	TTMatrix(arguments),
	mSampleRate(44100.0)
{
	this->setType(TT("float64"));
	this->setElementCount(1);

	addAttributeWithGetterAndSetter(NumChannels,		kTypeUInt16);
	addAttributeWithGetterAndSetter(Length,				kTypeFloat64);
	addAttributeWithGetterAndSetter(LengthInSamples,	kTypeUInt64);
	addAttribute(SampleRate,							kTypeFloat64);

	addMessage(normalize);
	addMessageWithArguments(fill);

	addMessageWithArguments(getValueAtIndex);
	registerMessage(TT("peek"), (TTMethod)&TTBuffer::getValueAtIndex);

	addMessageWithArguments(setValueAtIndex);
	registerMessage(TT("poke"), (TTMethod)&TTBuffer::setValueAtIndex);

	// TODO: more messages to implement
	//	"readFile"   (requires libsndfile straightening-out)
	//	"writeFile"  (requires libsndfile straightening-out)
	//	a way to query attributes: for example what is the sr and bpm of an AIFF file?
}

TTBuffer::~TTBuffer()
{
	;
}

TTErr TTBuffer::setNumChannels(const TTValue& newNumChannels)
{
	TTValue v(mDimensions[0], TTUInt32(newNumChannels));

	return setDimensions(v);
}

TTErr TTBuffer::getNumChannels(TTValue& returnedChannelCount)
{
	returnedChannelCount = mDimensions[0];
	return kTTErrNone;
}

TTErr TTBuffer::setLength(const TTValue& newLength)
{
	TTValue v(TTFloat64(newLength) * mSampleRate * 0.001, mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLength(TTValue& returnedLength)
{
	returnedLength = (mDimensions[1] / mSampleRate) * 1000.0;
	return kTTErrNone;
}

TTErr TTBuffer::setLengthInSamples(const TTValue& newLengthInSamples)
{
	TTValue v(TTUInt32(newLengthInSamples), mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLengthInSamples(TTValue& returnedLengthInSamples)
{
	returnedLengthInSamples = mDimensions[1];
	return kTTErrNone;
}

TTErr TTBuffer::getValueAtIndex(const TTValue& index, TTValue &output)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;
	TTErr			err;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)		// TODO: sure would be nice to change the name of this method to "size" or something...
		index.get(i++, sampleChannel);

	err = peek(sampleIndex, sampleChannel, sampleValue);
	if (!err)
		output.set(i++, sampleValue);
	return err;
}

TTErr TTBuffer::peek(const TTUInt64 index, const TTUInt16 channel, TTSampleValue& value)
{
	// TODO: perhaps we should range check the input here first...
	get2d(index, channel, value);
	return kTTErrNone;
}

/**	Set the sample value for a given index.
	The first number passed in the index parameter will be interpreted as the sample index.
	If there are three numbers passed, then the second number, if passed, will designate the channel index (defaults to zero).
	The final value will be used as the sample value that will be copied to the designated index.
*/
TTErr TTBuffer::setValueAtIndex(const TTValue& index, TTValue& unusedOutput)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)
		index.get(i++, sampleChannel);
	index.get(i++, sampleValue);

	return poke(sampleIndex, sampleChannel, sampleValue);
}

TTErr TTBuffer::poke(const TTUInt64 index, const TTUInt16 channel, const TTSampleValue value)
{
	// TODO: perhaps we should range check the input here first...
	set2d(index, channel, value);
	return kTTErrNone;
}

#define mLengthInSamples mDimensions[0]
#define mNumChannels mDimensions[1]

TTErr TTBuffer::fill(const TTValue& value, TTValue& unusedOutput)
{
	TTSymbol*	fillAlgorithm = value;

	if (fillAlgorithm == kTTSym_sine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i, channel, sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_sineMod) {							// (modulator version: ranges from 0.0 to 1.0, rather than -1.0 to 1.0)
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i, channel, 0.5 + (0.5 * sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i, channel, cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosineMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i, channel, 0.5 + (0.5 * cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_ramp) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i, channel, -1.0 + (2.0 * (float(i) / mDimensions[0])));
		}
	}
	else if (fillAlgorithm == kTTSym_rampMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i, channel, float(i) / mDimensions[0]);
		}
	}

	return kTTErrNone;
}

TTErr TTBuffer::normalize(const TTValue& aValue)
{
	TTFloat64			normalizeTo = 1.0;
	TTRowID				m = mDimensions[0]; // mFrameLength
	TTColumnID			n = mDimensions[1]; // mNumChannels
	TTSampleValuePtr	samples = (TTSampleValuePtr)getLockedPointer();
	TTFloat64			peakValue = 0.0;
	TTFloat64			scalar;

	if (aValue.getSize() && TTFloat64(aValue) > 0.0)
		normalizeTo = aValue;

	for (int k=0; k<m*n; k++) {
		TTFloat64 magnitude = abs(samples[k]);

		if (magnitude > peakValue)
			peakValue = magnitude;
	}

	scalar = normalizeTo / peakValue;

	for (int k=0; k<m*n; k++)
		samples[k] *= scalar;

	releaseLockedPointer();
	return kTTErrNone;
}
<commit_msg>TTBuffer: fix for bad (zero-based) indexing in the fill() method.<commit_after>/*
 * Jamoma DSP Audio Buffer Object
 * Copyright © 2003, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

#define thisTTClass			TTBuffer
#define thisTTClassName		"buffer"
#define thisTTClassTags		"audio, buffer"

TTObjectPtr TTBuffer::instantiate(TTSymbolPtr name, TTValue& arguments)
{
	return new TTBuffer(arguments);
}

extern "C" void TTBuffer::registerClass()
{
	TTClassRegister(TT("buffer"), thisTTClassTags, TTBuffer::instantiate);
}

TTBuffer::TTBuffer(TTValue& arguments) :
	TTMatrix(arguments),
	mSampleRate(44100.0)
{
	this->setType(TT("float64"));
	this->setElementCount(1);

	addAttributeWithGetterAndSetter(NumChannels,		kTypeUInt16);
	addAttributeWithGetterAndSetter(Length,				kTypeFloat64);
	addAttributeWithGetterAndSetter(LengthInSamples,	kTypeUInt64);
	addAttribute(SampleRate,							kTypeFloat64);

	addMessage(normalize);
	addMessageWithArguments(fill);

	addMessageWithArguments(getValueAtIndex);
	registerMessage(TT("peek"), (TTMethod)&TTBuffer::getValueAtIndex);

	addMessageWithArguments(setValueAtIndex);
	registerMessage(TT("poke"), (TTMethod)&TTBuffer::setValueAtIndex);

	// TODO: more messages to implement
	//	"readFile"   (requires libsndfile straightening-out)
	//	"writeFile"  (requires libsndfile straightening-out)
	//	a way to query attributes: for example what is the sr and bpm of an AIFF file?
}

TTBuffer::~TTBuffer()
{
	;
}

TTErr TTBuffer::setNumChannels(const TTValue& newNumChannels)
{
	TTValue v(mDimensions[0], TTUInt32(newNumChannels));

	return setDimensions(v);
}

TTErr TTBuffer::getNumChannels(TTValue& returnedChannelCount)
{
	returnedChannelCount = mDimensions[0];
	return kTTErrNone;
}

TTErr TTBuffer::setLength(const TTValue& newLength)
{
	TTValue v(TTFloat64(newLength) * mSampleRate * 0.001, mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLength(TTValue& returnedLength)
{
	returnedLength = (mDimensions[1] / mSampleRate) * 1000.0;
	return kTTErrNone;
}

TTErr TTBuffer::setLengthInSamples(const TTValue& newLengthInSamples)
{
	TTValue v(TTUInt32(newLengthInSamples), mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLengthInSamples(TTValue& returnedLengthInSamples)
{
	returnedLengthInSamples = mDimensions[1];
	return kTTErrNone;
}

TTErr TTBuffer::getValueAtIndex(const TTValue& index, TTValue &output)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;
	TTErr			err;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)		// TODO: sure would be nice to change the name of this method to "size" or something...
		index.get(i++, sampleChannel);

	err = peek(sampleIndex, sampleChannel, sampleValue);
	if (!err)
		output.set(i++, sampleValue);
	return err;
}

TTErr TTBuffer::peek(const TTUInt64 index, const TTUInt16 channel, TTSampleValue& value)
{
	// TODO: perhaps we should range check the input here first...
	get2d(index, channel, value);
	return kTTErrNone;
}

/**	Set the sample value for a given index.
	The first number passed in the index parameter will be interpreted as the sample index.
	If there are three numbers passed, then the second number, if passed, will designate the channel index (defaults to zero).
	The final value will be used as the sample value that will be copied to the designated index.
*/
TTErr TTBuffer::setValueAtIndex(const TTValue& index, TTValue& unusedOutput)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)
		index.get(i++, sampleChannel);
	index.get(i++, sampleValue);

	return poke(sampleIndex, sampleChannel, sampleValue);
}

TTErr TTBuffer::poke(const TTUInt64 index, const TTUInt16 channel, const TTSampleValue value)
{
	// TODO: perhaps we should range check the input here first...
	set2d(index, channel, value);
	return kTTErrNone;
}

#define mLengthInSamples mDimensions[0]
#define mNumChannels mDimensions[1]

TTErr TTBuffer::fill(const TTValue& value, TTValue& unusedOutput)
{
	TTSymbol*	fillAlgorithm = value;

	if (fillAlgorithm == kTTSym_sine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_sineMod) {							// (modulator version: ranges from 0.0 to 1.0, rather than -1.0 to 1.0)
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosineMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_ramp) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, -1.0 + (2.0 * (float(i) / mDimensions[0])));
		}
	}
	else if (fillAlgorithm == kTTSym_rampMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, float(i) / mDimensions[0]);
		}
	}

	return kTTErrNone;
}

TTErr TTBuffer::normalize(const TTValue& aValue)
{
	TTFloat64			normalizeTo = 1.0;
	TTRowID				m = mDimensions[0]; // mFrameLength
	TTColumnID			n = mDimensions[1]; // mNumChannels
	TTSampleValuePtr	samples = (TTSampleValuePtr)getLockedPointer();
	TTFloat64			peakValue = 0.0;
	TTFloat64			scalar;

	if (aValue.getSize() && TTFloat64(aValue) > 0.0)
		normalizeTo = aValue;

	for (int k=0; k<m*n; k++) {
		TTFloat64 magnitude = abs(samples[k]);

		if (magnitude > peakValue)
			peakValue = magnitude;
	}

	scalar = normalizeTo / peakValue;

	for (int k=0; k<m*n; k++)
		samples[k] *= scalar;

	releaseLockedPointer();
	return kTTErrNone;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <memory>

#include <caf/fwd.hpp>

#include "vast/config.hpp"

namespace vast::system {

// -- classes ------------------------------------------------------------------

class application;
class configuration;
class default_application;
class export_command;
class import_command;
class indexer_stage_driver;
class node_command;
class partition;
class pcap_reader_command;
class pcap_writer_command;
class remote_command;
class sink_command;
class source_command;
class start_command;
class table_indexer;

// -- structs ------------------------------------------------------------------

#ifdef VAST_MEASUREMENT_MUTEX_WORKAROUND
struct atomic_measurement;
#endif
struct index_state;
struct measurement;
struct node_state;
struct query_status;
struct spawn_arguments;

// -- templates ----------------------------------------------------------------

template <class Reader, class Defaults>
class reader_command;

template <class Writer>
class writer_command;

// -- aliases ------------------------------------------------------------------

#ifndef VAST_MEASUREMENT_MUTEX_WORKAROUND
using atomic_measurement = std::atomic<measurement>;
#endif
using node_actor = caf::stateful_actor<node_state>;
using partition_ptr = std::unique_ptr<partition>;
using table_indexer_ptr = caf::intrusive_ptr<table_indexer>;

} // namespace vast::system
<commit_msg>Remove outdated forward declarations<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <memory>

#include <caf/fwd.hpp>

#include "vast/config.hpp"

namespace vast::system {

// -- classes ------------------------------------------------------------------

class application;
class configuration;
class default_application;
class export_command;
class import_command;
class indexer_stage_driver;
class node_command;
class partition;
class pcap_reader_command;
class pcap_writer_command;
class remote_command;
class sink_command;
class source_command;
class start_command;
class table_indexer;

// -- structs ------------------------------------------------------------------

#ifdef VAST_MEASUREMENT_MUTEX_WORKAROUND
struct atomic_measurement;
#endif
struct index_state;
struct measurement;
struct node_state;
struct query_status;
struct spawn_arguments;

// -- aliases ------------------------------------------------------------------

#ifndef VAST_MEASUREMENT_MUTEX_WORKAROUND
using atomic_measurement = std::atomic<measurement>;
#endif
using node_actor = caf::stateful_actor<node_state>;
using partition_ptr = std::unique_ptr<partition>;
using table_indexer_ptr = caf::intrusive_ptr<table_indexer>;

} // namespace vast::system
<|endoftext|>