<commit_before>//
// Created by kyle on 10/12/16.
//
#include "tansa/jocsParser.h"
#include <regex>
#include <algorithm>
namespace tansa {
const std::string Jocs::HOME_KEY = "startPosition";
const std::string Jocs::ID_KEY = "id";

const std::string Jocs::UNITS_KEY = "units";
const std::string Jocs::LENGTH_KEY = "length";
const std::string Jocs::TIME_KEY = "time";
const std::string Jocs::ANGLE_KEY = "angle";

const std::string Jocs::THEATER_VOLUME_KEY = "theater_volume";
const std::string Jocs::MIN_KEY = "min";
const std::string Jocs::MAX_KEY = "max";

const std::string Jocs::REPEAT_KEY = "repeat";

const std::string Jocs::CHOREOGRAPHY_KEY = "chor";
const std::string Jocs::ACTION_TIME_KEY = "time";

const std::string Jocs::ACTION_ROOT_KEY = "action";
const std::string Jocs::ACTION_TYPE_KEY = "type";
const std::string Jocs::DURATION_KEY = "duration";

const std::string Jocs::DRONE_ARRAY_KEY = "drones";
const std::string Jocs::DRONE_START_OFF_KEY = "startOffset";
const std::string Jocs::DRONE_END_OFF_KEY = "endOffset";
const std::string Jocs::DRONE_OFF_KEY = "totalOffset"; // TODO: use this for circles and hovers

const std::string Jocs::ACTION_DATA_KEY = "data";
const std::string Jocs::STARTPOS_KEY = "startPoint";
const std::string Jocs::ENDPOS_KEY = "endPoint";
const std::string Jocs::HOVER_KEY = "hoverPoint";
const std::string Jocs::CIRCLE_ORIGIN_KEY = "originPoint";
const std::string Jocs::CIRCLE_RADIUS_KEY = "radius";
const std::string Jocs::CIRCLE_THETA1_KEY = "theta1";
const std::string Jocs::CIRCLE_THETA2_KEY = "theta2";

const double Jocs::FEET_TO_METERS = 0.3048;
const double Jocs::DEGREES_TO_RADIANS = M_PI/180.0;

Jocs Jocs::Parse(std::string jocsPath) {
	ifstream jocsStream(jocsPath);
	std::string jocsData((std::istreambuf_iterator<char>(jocsStream)), std::istreambuf_iterator<char>());
	//For some reason this regex didn't like the end of line $...but does work without it
	assert(jocsData.find("//") == std::string::npos);
	auto rawJson = nlohmann::json::parse(jocsData);
	auto units = rawJson[UNITS_KEY];
	bool needConvertToMeters = (units[LENGTH_KEY] == "feet");
	bool needConvertToRadians = (units[ANGLE_KEY] == "degrees");
	unsigned repeat = rawJson[REPEAT_KEY];
	auto ret = Jocs(needConvertToMeters, needConvertToRadians, repeat);
	ret.parseActions(rawJson);
	auto actions = ret.GetActions();
	auto homes = ret.GetHomes();
	auto floatComp = [](double a, double b) -> bool { return fabs(a-b) < 0.1; };
	auto pointComp = [](Point a, Point b) -> bool { return fabs((a-b).norm()) < 0.1; };
	try {
		for (unsigned j = 0; j < actions.size(); j++) {
			auto startPoint = homes[j];
			double startTime = 0.0;
			//Sort actions for each drone based on start time
			std::sort(actions[j].begin(), actions[j].end(),
					  [](Action *const &lhs, Action *const &rhs) { return lhs->GetStartTime() < rhs->GetStartTime(); });
			for (unsigned i = 0; i < actions[j].size(); i++) {
				//Check temporal continuity
				Action *a = actions[j][i];
				double sTime = a->GetStartTime();
				double eTime = a->GetEndTime();
				if (!floatComp(sTime, startTime)) {
					throw std::runtime_error(
							"Time Discontinuity for Drone: " + std::to_string(j) + " with start time: " +
							std::to_string(sTime) + " and end time: " + std::to_string(eTime));
				}
				startTime = eTime;
				//Check spatial continuity
				if (a->GetActionType() != ActionTypes::Light) {
					auto ma = static_cast<MotionAction *>(a);
					auto actionStart = ma->GetStartPoint();
					if (!pointComp(actionStart, startPoint)) {
						throw std::runtime_error(
								"Spatial Discontinuity for Drone: " + std::to_string(j) + ". Jumping from point: " +
								"[" + std::to_string(startPoint.x()) + " " + std::to_string(startPoint.y()) + " " +
								std::to_string(startPoint.z()) + "]" +
								" to point: " "[" + std::to_string(actionStart.x()) + " " +
								std::to_string(actionStart.y()) + " " + std::to_string(actionStart.z()) + "]" + "\n"
								+ "at start time: " + std::to_string(sTime)
						);
					}
					startPoint = ma->GetEndPoint();
				}
			}
		}
	} catch (std::runtime_error e){
		std::cerr << e.what() << std::endl;

	}
	return ret;
}

void Jocs::parseActions(const nlohmann::json &data) {

	auto actionsJson = data[CHOREOGRAPHY_KEY];
	auto drones = data[DRONE_ARRAY_KEY];
	assert(drones.is_array());
	assert(actionsJson.is_array());
	auto droneLength = drones.size();
	homes.resize(droneLength);
	double conversionFactor = needConvertToMeters ? FEET_TO_METERS : 1.0;
	for(unsigned i = 0; i < droneLength; i++){
		homes[i] = Point(drones[i][HOME_KEY][0], drones[i][HOME_KEY][1], drones[i][HOME_KEY][2])*conversionFactor;
	}

	auto length = actionsJson.size();
	//allocate space for each subarray for each drone.
	actions.resize(droneLength);
	// For each drone, gather actions in a vector and add as entry in "actions" 2d vector
	double lastTime = 0.0;
	for(unsigned k = 0; k < repeat; k++) {
		for (unsigned i = 0; i < length; i++) {
			if (i == length - 1) {
				lastTime = parseAction(actionsJson[i], lastTime);
			} else {
				parseAction(actionsJson[i], lastTime);
			}
		}
	}
	// Go back and review actions such that transitions can be created with polynomial trajectories
	for (unsigned i = 0; i < actions.size(); i++) {
		// Each entry in "actions" has a vector full of actions for that drone
		for (unsigned j = 0; j < actions[i].size(); j++) {
			if (!actions[i][j]->IsCalculated()) {
				double thisStart = actions[i][j]->GetStartTime();
				double thisEnd = actions[i][j]->GetEndTime();
				if (j == 0) {
					MotionAction *next = static_cast<MotionAction *>(actions[i][j + 1]);
					auto endState = next->GetPathState(next->GetStartTime());
					delete actions[i][j];
					actions[i][j] = new MotionAction(i,
													 PolynomialTrajectory::compute(
															 {homes[i]},
															 thisStart,
															 {endState.position, endState.velocity,
															  endState.acceleration},
															 thisEnd
													 ),
													 ActionTypes::Transition
					);
				} else if (j == (actions[i].size() - 1)) {
					//TODO: Handle the case of the last action being a transition, where our ending velocity and acceleration are 0 and destination is home.
				} else {

					// Calculate previous and next motion to generate what's needed for the transition
					MotionAction *prev = static_cast<MotionAction *>(actions[i][j - 1]);
					MotionAction *next = static_cast<MotionAction *>(actions[i][j + 1]);
					// Get states from the previous and next state that were found
					auto startState = prev->GetPathState(prev->GetEndTime());
					auto endState = next->GetPathState(next->GetStartTime());
					// Cleanup object and replace with a new MotionAction
					delete actions[i][j];
					actions[i][j] = new MotionAction(i, PolynomialTrajectory::compute(
							{startState.position, startState.velocity, startState.acceleration},
							thisStart,
							{endState.position, endState.velocity, endState.acceleration},
							thisEnd
							 ),
					 ActionTypes::Transition
					);
				}
			}
		}
	}
}

// TODO: rename since it parses all actions at given timeslot
double Jocs::parseAction(const nlohmann::json::reference data, double lastTime){
	auto actionsArray = data[ACTION_ROOT_KEY];
	assert(actionsArray.is_array());
	double startTime = data[ACTION_TIME_KEY];
	double endTime = 0.0;

	for(unsigned i = 0; i < actionsArray.size(); i++) {
		auto actionsArrayElement = actionsArray[i];

		double duration = actionsArrayElement[DURATION_KEY];

		unsigned type = convertToActionType(actionsArrayElement[ACTION_TYPE_KEY]);
		assert(actionsArrayElement[DRONE_ARRAY_KEY].is_array());

		auto drones = actionsArrayElement[DRONE_ARRAY_KEY];
		double conversionFactor = needConvertToMeters ? FEET_TO_METERS : 1.0;
		endTime += lastTime + startTime + duration;
		assert(drones.is_array());

		for (unsigned j = 0; j < drones.size(); j++) {
			unsigned drone = drones[j][ID_KEY];
			Point startOffset(drones[j][DRONE_START_OFF_KEY][0],drones[j][DRONE_START_OFF_KEY][1],drones[j][DRONE_START_OFF_KEY][2]);
			Point endOffset(drones[j][DRONE_END_OFF_KEY][0],drones[j][DRONE_END_OFF_KEY][1],drones[j][DRONE_END_OFF_KEY][2]);
			startOffset*=conversionFactor;
			endOffset*=conversionFactor;
			switch (type) {
				case ActionTypes::Transition: {
					// Actual calculation will be processed after this loop
					actions[drone].push_back(new EmptyAction(drone, lastTime + startTime, lastTime + startTime + duration));
					break;
				}
				case ActionTypes::Line: {
					Point start(
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][2]);
					start*=conversionFactor;
					Point end(
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][2]);
					end*=conversionFactor;
					actions[drone].push_back(new MotionAction(
							drone, new LinearTrajectory(start + startOffset, lastTime + startTime, end + endOffset, lastTime + startTime + duration), ActionTypes::Line));
					break;
				}
				case ActionTypes::Circle: {
					Point origin(
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][2]);
					origin*=conversionFactor;
					double radius = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_RADIUS_KEY];
					double theta1 = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_THETA1_KEY];
					radius*=conversionFactor;
					double theta2 = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_THETA2_KEY];
					if(needConvertToRadians) {
						theta1 = theta1 * DEGREES_TO_RADIANS;
						theta2 = theta2 * DEGREES_TO_RADIANS;
					}
					// TODO: use separate offset key for circle and hover
					actions[drone].push_back(new MotionAction(
							drone,
							new CircleTrajectory(origin + startOffset, radius, theta1, lastTime+startTime, theta2, lastTime + startTime + duration),
							ActionTypes::Circle
					));
					break;
				}
				case ActionTypes::Hover:{
					Point hoverPoint(
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][2]
					);
					hoverPoint*=conversionFactor;
					// TODO: use separate offset key for circle and hover
					actions[drone].push_back(new MotionAction(
							drone,
							new LinearTrajectory(hoverPoint + startOffset, lastTime +  startTime, hoverPoint + endOffset, lastTime + startTime + duration),
							ActionTypes::Hover
					));
					break;
				}
				default: {
					break;
				}
			}
		}
	}
	return endTime;
}

ActionTypes Jocs::convertToActionType(const std::string& data){
	if(data == "transition")
		return ActionTypes::Transition;
	else if (data == "line")
		return ActionTypes::Line;
	else if (data == "circle")
		return ActionTypes::Circle;
	else if (data == "hover")
		return ActionTypes::Hover;
	return ActionTypes::None;
}
}
<commit_msg>Made error messages for time discontinuity better<commit_after>//
// Created by kyle on 10/12/16.
//
#include "tansa/jocsParser.h"
#include <regex>
#include <algorithm>
namespace tansa {
const std::string Jocs::HOME_KEY = "startPosition";
const std::string Jocs::ID_KEY = "id";

const std::string Jocs::UNITS_KEY = "units";
const std::string Jocs::LENGTH_KEY = "length";
const std::string Jocs::TIME_KEY = "time";
const std::string Jocs::ANGLE_KEY = "angle";

const std::string Jocs::THEATER_VOLUME_KEY = "theater_volume";
const std::string Jocs::MIN_KEY = "min";
const std::string Jocs::MAX_KEY = "max";

const std::string Jocs::REPEAT_KEY = "repeat";

const std::string Jocs::CHOREOGRAPHY_KEY = "chor";
const std::string Jocs::ACTION_TIME_KEY = "time";

const std::string Jocs::ACTION_ROOT_KEY = "action";
const std::string Jocs::ACTION_TYPE_KEY = "type";
const std::string Jocs::DURATION_KEY = "duration";

const std::string Jocs::DRONE_ARRAY_KEY = "drones";
const std::string Jocs::DRONE_START_OFF_KEY = "startOffset";
const std::string Jocs::DRONE_END_OFF_KEY = "endOffset";
const std::string Jocs::DRONE_OFF_KEY = "totalOffset"; // TODO: use this for circles and hovers

const std::string Jocs::ACTION_DATA_KEY = "data";
const std::string Jocs::STARTPOS_KEY = "startPoint";
const std::string Jocs::ENDPOS_KEY = "endPoint";
const std::string Jocs::HOVER_KEY = "hoverPoint";
const std::string Jocs::CIRCLE_ORIGIN_KEY = "originPoint";
const std::string Jocs::CIRCLE_RADIUS_KEY = "radius";
const std::string Jocs::CIRCLE_THETA1_KEY = "theta1";
const std::string Jocs::CIRCLE_THETA2_KEY = "theta2";

const double Jocs::FEET_TO_METERS = 0.3048;
const double Jocs::DEGREES_TO_RADIANS = M_PI/180.0;

Jocs Jocs::Parse(std::string jocsPath) {
	ifstream jocsStream(jocsPath);
	std::string jocsData((std::istreambuf_iterator<char>(jocsStream)), std::istreambuf_iterator<char>());
	//For some reason this regex didn't like the end of line $...but does work without it
	assert(jocsData.find("//") == std::string::npos);
	auto rawJson = nlohmann::json::parse(jocsData);
	auto units = rawJson[UNITS_KEY];
	bool needConvertToMeters = (units[LENGTH_KEY] == "feet");
	bool needConvertToRadians = (units[ANGLE_KEY] == "degrees");
	unsigned repeat = rawJson[REPEAT_KEY];
	auto ret = Jocs(needConvertToMeters, needConvertToRadians, repeat);
	ret.parseActions(rawJson);
	auto actions = ret.GetActions();
	auto homes = ret.GetHomes();
	auto floatComp = [](double a, double b) -> bool { return fabs(a-b) < 0.1; };
	auto pointComp = [](Point a, Point b) -> bool { return fabs((a-b).norm()) < 0.1; };
	try {
		for (unsigned j = 0; j < actions.size(); j++) {
			auto startPoint = homes[j];
			double startTime = 0.0;
			//Sort actions for each drone based on start time
			std::sort(actions[j].begin(), actions[j].end(),
					  [](Action *const &lhs, Action *const &rhs) { return lhs->GetStartTime() < rhs->GetStartTime(); });
			for (unsigned i = 0; i < actions[j].size(); i++) {
				//Check temporal continuity
				Action *a = actions[j][i];
				double sTime = a->GetStartTime();
				double eTime = a->GetEndTime();
				if (!floatComp(sTime, startTime)) {
					throw std::runtime_error(
							"Time Discontinuity for Drone: " + std::to_string(j) + " with start time: " +
							std::to_string(sTime) + ". Last command ended at : " + std::to_string(startTime));
				}
				startTime = eTime;
				//Check spatial continuity
				if (a->GetActionType() != ActionTypes::Light) {
					auto ma = static_cast<MotionAction *>(a);
					auto actionStart = ma->GetStartPoint();
					if (!pointComp(actionStart, startPoint)) {
						throw std::runtime_error(
								"Spatial Discontinuity for Drone: " + std::to_string(j) + ". Jumping from point: " +
								"[" + std::to_string(startPoint.x()) + " " + std::to_string(startPoint.y()) + " " +
								std::to_string(startPoint.z()) + "]" +
								" to point: " "[" + std::to_string(actionStart.x()) + " " +
								std::to_string(actionStart.y()) + " " + std::to_string(actionStart.z()) + "]" + "\n"
								+ "at start time: " + std::to_string(sTime)
						);
					}
					startPoint = ma->GetEndPoint();
				}
			}
		}
	} catch (std::runtime_error e){
		std::cerr << e.what() << std::endl;

	}
	return ret;
}

void Jocs::parseActions(const nlohmann::json &data) {

	auto actionsJson = data[CHOREOGRAPHY_KEY];
	auto drones = data[DRONE_ARRAY_KEY];
	assert(drones.is_array());
	assert(actionsJson.is_array());
	auto droneLength = drones.size();
	homes.resize(droneLength);
	double conversionFactor = needConvertToMeters ? FEET_TO_METERS : 1.0;
	for(unsigned i = 0; i < droneLength; i++){
		homes[i] = Point(drones[i][HOME_KEY][0], drones[i][HOME_KEY][1], drones[i][HOME_KEY][2])*conversionFactor;
	}

	auto length = actionsJson.size();
	//allocate space for each subarray for each drone.
	actions.resize(droneLength);
	// For each drone, gather actions in a vector and add as entry in "actions" 2d vector
	double lastTime = 0.0;
	for(unsigned k = 0; k < repeat; k++) {
		for (unsigned i = 0; i < length; i++) {
			if (i == length - 1) {
				lastTime = parseAction(actionsJson[i], lastTime);
			} else {
				parseAction(actionsJson[i], lastTime);
			}
		}
	}
	// Go back and review actions such that transitions can be created with polynomial trajectories
	for (unsigned i = 0; i < actions.size(); i++) {
		// Each entry in "actions" has a vector full of actions for that drone
		for (unsigned j = 0; j < actions[i].size(); j++) {
			if (!actions[i][j]->IsCalculated()) {
				double thisStart = actions[i][j]->GetStartTime();
				double thisEnd = actions[i][j]->GetEndTime();
				if (j == 0) {
					MotionAction *next = static_cast<MotionAction *>(actions[i][j + 1]);
					auto endState = next->GetPathState(next->GetStartTime());
					delete actions[i][j];
					actions[i][j] = new MotionAction(i,
													 PolynomialTrajectory::compute(
															 {homes[i]},
															 thisStart,
															 {endState.position, endState.velocity,
															  endState.acceleration},
															 thisEnd
													 ),
													 ActionTypes::Transition
					);
				} else if (j == (actions[i].size() - 1)) {
					//TODO: Handle the case of the last action being a transition, where our ending velocity and acceleration are 0 and destination is home.
				} else {

					// Calculate previous and next motion to generate what's needed for the transition
					MotionAction *prev = static_cast<MotionAction *>(actions[i][j - 1]);
					MotionAction *next = static_cast<MotionAction *>(actions[i][j + 1]);
					// Get states from the previous and next state that were found
					auto startState = prev->GetPathState(prev->GetEndTime());
					auto endState = next->GetPathState(next->GetStartTime());
					// Cleanup object and replace with a new MotionAction
					delete actions[i][j];
					actions[i][j] = new MotionAction(i, PolynomialTrajectory::compute(
							{startState.position, startState.velocity, startState.acceleration},
							thisStart,
							{endState.position, endState.velocity, endState.acceleration},
							thisEnd
							 ),
					 ActionTypes::Transition
					);
				}
			}
		}
	}
}

// TODO: rename since it parses all actions at given timeslot
double Jocs::parseAction(const nlohmann::json::reference data, double lastTime){
	auto actionsArray = data[ACTION_ROOT_KEY];
	assert(actionsArray.is_array());
	double startTime = data[ACTION_TIME_KEY];
	double endTime = 0.0;

	for(unsigned i = 0; i < actionsArray.size(); i++) {
		auto actionsArrayElement = actionsArray[i];

		double duration = actionsArrayElement[DURATION_KEY];

		unsigned type = convertToActionType(actionsArrayElement[ACTION_TYPE_KEY]);
		assert(actionsArrayElement[DRONE_ARRAY_KEY].is_array());

		auto drones = actionsArrayElement[DRONE_ARRAY_KEY];
		double conversionFactor = needConvertToMeters ? FEET_TO_METERS : 1.0;
		endTime += lastTime + startTime + duration;
		assert(drones.is_array());

		for (unsigned j = 0; j < drones.size(); j++) {
			unsigned drone = drones[j][ID_KEY];
			Point startOffset(drones[j][DRONE_START_OFF_KEY][0],drones[j][DRONE_START_OFF_KEY][1],drones[j][DRONE_START_OFF_KEY][2]);
			Point endOffset(drones[j][DRONE_END_OFF_KEY][0],drones[j][DRONE_END_OFF_KEY][1],drones[j][DRONE_END_OFF_KEY][2]);
			startOffset*=conversionFactor;
			endOffset*=conversionFactor;
			switch (type) {
				case ActionTypes::Transition: {
					// Actual calculation will be processed after this loop
					actions[drone].push_back(new EmptyAction(drone, lastTime + startTime, lastTime + startTime + duration));
					break;
				}
				case ActionTypes::Line: {
					Point start(
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][STARTPOS_KEY][2]);
					start*=conversionFactor;
					Point end(
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][ENDPOS_KEY][2]);
					end*=conversionFactor;
					actions[drone].push_back(new MotionAction(
							drone, new LinearTrajectory(start + startOffset, lastTime + startTime, end + endOffset, lastTime + startTime + duration), ActionTypes::Line));
					break;
				}
				case ActionTypes::Circle: {
					Point origin(
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][CIRCLE_ORIGIN_KEY][2]);
					origin*=conversionFactor;
					double radius = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_RADIUS_KEY];
					double theta1 = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_THETA1_KEY];
					radius*=conversionFactor;
					double theta2 = actionsArrayElement[ACTION_DATA_KEY][CIRCLE_THETA2_KEY];
					if(needConvertToRadians) {
						theta1 = theta1 * DEGREES_TO_RADIANS;
						theta2 = theta2 * DEGREES_TO_RADIANS;
					}
					// TODO: use separate offset key for circle and hover
					actions[drone].push_back(new MotionAction(
							drone,
							new CircleTrajectory(origin + startOffset, radius, theta1, lastTime+startTime, theta2, lastTime + startTime + duration),
							ActionTypes::Circle
					));
					break;
				}
				case ActionTypes::Hover:{
					Point hoverPoint(
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][0],
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][1],
							actionsArrayElement[ACTION_DATA_KEY][HOVER_KEY][2]
					);
					hoverPoint*=conversionFactor;
					// TODO: use separate offset key for circle and hover
					actions[drone].push_back(new MotionAction(
							drone,
							new LinearTrajectory(hoverPoint + startOffset, lastTime +  startTime, hoverPoint + endOffset, lastTime + startTime + duration),
							ActionTypes::Hover
					));
					break;
				}
				default: {
					break;
				}
			}
		}
	}
	return endTime;
}

ActionTypes Jocs::convertToActionType(const std::string& data){
	if(data == "transition")
		return ActionTypes::Transition;
	else if (data == "line")
		return ActionTypes::Line;
	else if (data == "circle")
		return ActionTypes::Circle;
	else if (data == "hover")
		return ActionTypes::Hover;
	return ActionTypes::None;
}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 MIPS Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Korey Sewell
 *
 */

#include "cpu/inorder/resources/graduation_unit.hh"
#include "debug/InOrderGraduation.hh"

using namespace ThePipeline;

GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
                               int res_latency, InOrderCPU *_cpu,
                               ThePipeline::Params *params)
    : Resource(res_name, res_id, res_width, res_latency, _cpu),
      lastNonSpecTick(0)
{
    for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
        nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
        nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
    }
}

void
GraduationUnit::execute(int slot_num)
{
    ResourceRequest* grad_req = reqs[slot_num];
    DynInstPtr inst = reqs[slot_num]->inst;
    ThreadID tid = inst->readTid();
    int stage_num = inst->curSkedEntry->stageNum;

    switch (grad_req->cmd)
    {
      case GraduateInst:
        {
            if (lastNonSpecTick == curTick()) {
                DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
                        "Only 1 nonspec inst. per cycle can graduate.\n");
                grad_req->done(false);
                return;
            }

            // Handle Any Faults Before Graduating Instruction
            if (inst->fault != NoFault) {
                DPRINTF(Fault, "[sn:%i]: fault %s found for %s\n",
                        inst->seqNum, inst->fault->name(),
                        inst->instName());
                inst->setSquashInfo(stage_num);
                setupSquash(inst, stage_num, tid);
                cpu->trapContext(inst->fault, tid, inst);
                grad_req->done(false);
                return;
            }

            DPRINTF(InOrderGraduation,
                    "[tid:%i]:[sn:%i]: Graduating instruction %s.\n",
                    tid, inst->seqNum, inst->instName());

            // Release Non-Speculative "Block" on instructions that could not
            // execute because there was a non-speculative inst. active.
            // @TODO: Fix this functionality. Probably too conservative.
            if (inst->isNonSpeculative()) {
                *nonSpecInstActive[tid] = false;
                DPRINTF(InOrderGraduation,
                        "[tid:%i] Non-speculative inst [sn:%i] graduated\n",
                        tid, inst->seqNum);
                lastNonSpecTick = curTick();
            }

            if (inst->traceData) {
                inst->traceData->setStageCycle(stage_num, curTick());
            }

            // Tell CPU that instruction is finished processing
            cpu->instDone(inst, tid);

            grad_req->done();
        }
        break;

      default:
        fatal("Unrecognized command to %s", resName);
    }

}
<commit_msg>inorder: optionally track faulting instructions<commit_after>/*
 * Copyright (c) 2007 MIPS Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Korey Sewell
 *
 */

#include "cpu/inorder/resources/graduation_unit.hh"
#include "debug/InOrderGraduation.hh"

using namespace ThePipeline;

GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
                               int res_latency, InOrderCPU *_cpu,
                               ThePipeline::Params *params)
    : Resource(res_name, res_id, res_width, res_latency, _cpu),
      lastNonSpecTick(0)
{
    for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
        nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
        nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
    }
}

void
GraduationUnit::execute(int slot_num)
{
    ResourceRequest* grad_req = reqs[slot_num];
    DynInstPtr inst = reqs[slot_num]->inst;
    ThreadID tid = inst->readTid();
    int stage_num = inst->curSkedEntry->stageNum;

    switch (grad_req->cmd)
    {
      case GraduateInst:
        {
            if (lastNonSpecTick == curTick()) {
                DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
                        "Only 1 nonspec inst. per cycle can graduate.\n");
                grad_req->done(false);
                return;
            }

            // Handle Any Faults Before Graduating Instruction
            if (inst->fault != NoFault) {
                DPRINTF(Fault, "[sn:%i]: fault %s found for %s\n",
                        inst->seqNum, inst->fault->name(),
                        inst->instName());
                inst->setSquashInfo(stage_num);
                setupSquash(inst, stage_num, tid);

                if (inst->traceData && DTRACE(ExecFaulting)) {
                    inst->traceData->setStageCycle(stage_num, curTick());
                    inst->traceData->setFetchSeq(inst->seqNum);
                    inst->traceData->dump();
                    delete inst->traceData;
                    inst->traceData = NULL;
                }

                cpu->trapContext(inst->fault, tid, inst);
                grad_req->done(false);
                return;
            }

            DPRINTF(InOrderGraduation,
                    "[tid:%i]:[sn:%i]: Graduating instruction %s.\n",
                    tid, inst->seqNum, inst->instName());

            // Release Non-Speculative "Block" on instructions that could not
            // execute because there was a non-speculative inst. active.
            // @TODO: Fix this functionality. Probably too conservative.
            if (inst->isNonSpeculative()) {
                *nonSpecInstActive[tid] = false;
                DPRINTF(InOrderGraduation,
                        "[tid:%i] Non-speculative inst [sn:%i] graduated\n",
                        tid, inst->seqNum);
                lastNonSpecTick = curTick();
            }

            if (inst->traceData) {
                inst->traceData->setStageCycle(stage_num, curTick());
            }

            // Tell CPU that instruction is finished processing
            cpu->instDone(inst, tid);

            grad_req->done();
        }
        break;

      default:
        fatal("Unrecognized command to %s", resName);
    }

}
<|endoftext|>


<commit_before>/*
 * PresentationLog.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "PresentationLog.hpp"

#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <core/Error.hpp>
#include <core/DateTime.hpp>
#include <core/StringUtils.hpp>
#include <core/SafeConvert.hpp>
#include <core/FileSerializer.hpp>

#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/session/RSessionUtils.hpp>

#include "PresentationState.hpp"

using namespace core;

namespace session {
namespace modules {
namespace presentation {

Log& log()
{
   static Log instance;
   return instance;
}

Error Log::initialize()
{

   // connect to console events
   using namespace boost;
   using namespace session::module_context;

   events().onConsolePrompt.connect(boost::bind(&Log::onConsolePrompt,
                                                this, _1));
   events().onConsoleInput.connect(boost::bind(&Log::onConsoleInput,
                                               this, _1));
   events().onConsoleOutput.connect(boost::bind(&Log::onConsoleOutput,
                                                this, _1, _2));

   return Success();
}

void Log::recordCommand(int slideIndex, const Command& command)
{
   if (command.name() == "console-input")
   {
      std::string params = boost::algorithm::trim_copy(command.params());
      slideDeckInputCommands_[slideIndex].insert(params);
   }
   else if (command.name() == "help-topic")
   {
      slideHelpTopics_[slideIndex] = command.params();
   }
   else if (command.name() == "help-doc")
   {
      slideHelpDocs_[slideIndex] = command.params();
   }
}

void Log::onSlideDeckChanged(const SlideDeck& slideDeck)
{
   slideDeckInputCommands_.clear();
   slideTypes_.clear();

   slideHelpTopics_ = std::vector<std::string>(slideDeck.slides().size());
   slideHelpDocs_ = std::vector<std::string>(slideDeck.slides().size());

   const std::vector<Slide>& slides = slideDeck.slides();
   for (std::size_t i = 0; i<slides.size(); i++)
   {
      slideTypes_.push_back(slides[i].type());

      const std::vector<Command>& commands = slides[i].commands();
      BOOST_FOREACH(const Command& command, commands)
      {
         recordCommand(i, command);
      }

      const std::vector<AtCommand>& atCommands = slides[i].atCommands();
      BOOST_FOREACH(const AtCommand& atCommand, atCommands)
      {
         recordCommand(i, atCommand.command());
      }
   }
}

void Log::onSlideIndexChanged(int index)
{
   currentSlideIndex_ = index;

   append(NavigationEntry,
          presentation::state::filePath(),
          currentSlideIndex_,
          currentSlideType(),
          currentSlideHelpTopic(),
          currentSlideHelpDoc(),
          "",
          "");
}

void Log::onConsolePrompt(const std::string& prompt)
{
   if (!presentation::state::isActive())
      return;

   // ignore if this isn't the default prompt
   if (!r::session::utils::isDefaultPrompt(prompt))
      return;

   if (!consoleInputBuffer_.empty())
   {
      std::string input = boost::algorithm::trim_copy(
                            boost::algorithm::join(consoleInputBuffer_, "\n"));
      std::string errors = boost::algorithm::trim_copy(
                            boost::algorithm::join(errorOutputBuffer_, "\n"));

      // check to see if this command was one of the ones instrumented
      // by the current slide
      if (slideDeckInputCommands_[currentSlideIndex_].count(input) == 0)
      {
         append(InputEntry,
                presentation::state::filePath(),
                currentSlideIndex_,
                currentSlideType(),
                currentSlideHelpTopic(),
                currentSlideHelpDoc(),
                input,
                errors);
      }
   }

   consoleInputBuffer_.clear();
   errorOutputBuffer_.clear();
}

void Log::onConsoleInput(const std::string& text)
{
   if (!presentation::state::isActive())
      return;

   consoleInputBuffer_.push_back(text);
}

void Log::onConsoleOutput(module_context::ConsoleOutputType type,
                     const std::string& output)
{
   if (!presentation::state::isActive())
      return;

   if (type == module_context::ConsoleOutputError)
      errorOutputBuffer_.push_back(output);

}

namespace {

std::string csvString(std::string str)
{
   boost::algorithm::replace_all(str, "\n", "\\n");
   boost::algorithm::replace_all(str, "\"", "\"\"");
   return "\"" + str + "\"";
}

std::string timestamp()
{
   // generate timestamp
   using namespace boost::posix_time;
   ptime time = microsec_clock::universal_time();
   std::string dateTime = date_time::format(time, "%Y-%m-%dT%H:%M:%SZ");
   return dateTime;
}

Error ensureTargetFile(const std::string& filename,
                       const std::string& header,
                       FilePath* pTargetFile)
{
   using namespace module_context;
   FilePath presDir =  userScratchPath().childPath("presentation");
   Error error = presDir.ensureDirectory();
   if (error)
      return error;

   *pTargetFile = presDir.childPath(filename);
   if (!pTargetFile->exists())
   {
      Error error = core::writeStringToFile(*pTargetFile, header + "\n");
      if (error)
         return error;
   }

   return Success();
}

} // anonymous namespace

std::string Log::currentSlideType() const
{
   if (currentSlideIndex_ < slideTypes_.size())
      return slideTypes_[currentSlideIndex_];
   else
      return "default";
}

std::string Log::currentSlideHelpTopic() const
{
   if (currentSlideIndex_ < slideHelpTopics_.size())
      return slideHelpTopics_[currentSlideIndex_];
   else
      return "";
}

std::string Log::currentSlideHelpDoc() const
{
   if (currentSlideIndex_ < slideHelpDocs_.size())
      return slideHelpDocs_[currentSlideIndex_];
   else
      return "";
}

void Log::append(EntryType type,
                 const FilePath& presPath,
                 int slideIndex,
                 const std::string& slideType,
                 const std::string& helpTopic,
                 const std::string& helpDoc,
                 const std::string& input,
                 const std::string& errors)
{
   // ensure target file
   FilePath logFilePath;
   Error error = ensureTargetFile(
            "presentation-log-v1.csv",
            "type, timestamp, presentation, slide, slide-type, help-topic, "
            "help-doc, input, errors\n",
            &logFilePath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // generate entry
   std::vector<std::string> fields;
   fields.push_back((type == NavigationEntry) ? "Navigation" : "Input");
   fields.push_back(timestamp());
   fields.push_back(csvString(module_context::createAliasedPath(presPath)));
   fields.push_back(safe_convert::numberToString(slideIndex));
   fields.push_back(slideType);
   fields.push_back(csvString(helpTopic));
   fields.push_back(csvString(helpDoc));
   fields.push_back(csvString(input));
   fields.push_back(csvString(errors));
   std::string entry = boost::algorithm::join(fields, ",");

   // append entry
   error = core::appendToFile(logFilePath, entry + "\n");
   if (error)
      LOG_ERROR(error);
}

void Log::recordFeedback(const std::string& feedback)
{
   // ensure target file
   FilePath feedbackFilePath;
   Error error = ensureTargetFile("feedback-v1.csv",
                                  "timestamp, presentation, slide, feedback\n",
                                  &feedbackFilePath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // generate entry
   std::vector<std::string> fields;
   fields.push_back(timestamp());
   fields.push_back(csvString(module_context::createAliasedPath(
                                          presentation::state::filePath())));
   fields.push_back(safe_convert::numberToString(currentSlideIndex_));
   fields.push_back(csvString(feedback));
   std::string entry = boost::algorithm::join(fields, ",");

   // append entry
   error = core::appendToFile(feedbackFilePath, entry + "\n");
   if (error)
      LOG_ERROR(error);
}

} // namespace presentation
} // namespace modules
} // namesapce session

<commit_msg>use namespace alias for boost::algorithm<commit_after>/*
 * PresentationLog.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "PresentationLog.hpp"

#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <core/Error.hpp>
#include <core/DateTime.hpp>
#include <core/StringUtils.hpp>
#include <core/SafeConvert.hpp>
#include <core/FileSerializer.hpp>

#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/session/RSessionUtils.hpp>

#include "PresentationState.hpp"

using namespace core;

namespace session {
namespace modules {
namespace presentation {

Log& log()
{
   static Log instance;
   return instance;
}

Error Log::initialize()
{

   // connect to console events
   using namespace boost;
   using namespace session::module_context;

   events().onConsolePrompt.connect(boost::bind(&Log::onConsolePrompt,
                                                this, _1));
   events().onConsoleInput.connect(boost::bind(&Log::onConsoleInput,
                                               this, _1));
   events().onConsoleOutput.connect(boost::bind(&Log::onConsoleOutput,
                                                this, _1, _2));

   return Success();
}

void Log::recordCommand(int slideIndex, const Command& command)
{
   if (command.name() == "console-input")
   {
      std::string params = boost::algorithm::trim_copy(command.params());
      slideDeckInputCommands_[slideIndex].insert(params);
   }
   else if (command.name() == "help-topic")
   {
      slideHelpTopics_[slideIndex] = command.params();
   }
   else if (command.name() == "help-doc")
   {
      slideHelpDocs_[slideIndex] = command.params();
   }
}

void Log::onSlideDeckChanged(const SlideDeck& slideDeck)
{
   slideDeckInputCommands_.clear();
   slideTypes_.clear();

   slideHelpTopics_ = std::vector<std::string>(slideDeck.slides().size());
   slideHelpDocs_ = std::vector<std::string>(slideDeck.slides().size());

   const std::vector<Slide>& slides = slideDeck.slides();
   for (std::size_t i = 0; i<slides.size(); i++)
   {
      slideTypes_.push_back(slides[i].type());

      const std::vector<Command>& commands = slides[i].commands();
      BOOST_FOREACH(const Command& command, commands)
      {
         recordCommand(i, command);
      }

      const std::vector<AtCommand>& atCommands = slides[i].atCommands();
      BOOST_FOREACH(const AtCommand& atCommand, atCommands)
      {
         recordCommand(i, atCommand.command());
      }
   }
}

void Log::onSlideIndexChanged(int index)
{
   currentSlideIndex_ = index;

   append(NavigationEntry,
          presentation::state::filePath(),
          currentSlideIndex_,
          currentSlideType(),
          currentSlideHelpTopic(),
          currentSlideHelpDoc(),
          "",
          "");
}

void Log::onConsolePrompt(const std::string& prompt)
{
   if (!presentation::state::isActive())
      return;

   // ignore if this isn't the default prompt
   if (!r::session::utils::isDefaultPrompt(prompt))
      return;

   if (!consoleInputBuffer_.empty())
   {
      using namespace boost::algorithm;
      std::string input = trim_copy(join(consoleInputBuffer_, "\n"));
      std::string errors = trim_copy(join(errorOutputBuffer_, "\n"));

      // check to see if this command was one of the ones instrumented
      // by the current slide
      if (slideDeckInputCommands_[currentSlideIndex_].count(input) == 0)
      {
         append(InputEntry,
                presentation::state::filePath(),
                currentSlideIndex_,
                currentSlideType(),
                currentSlideHelpTopic(),
                currentSlideHelpDoc(),
                input,
                errors);
      }
   }

   consoleInputBuffer_.clear();
   errorOutputBuffer_.clear();
}

void Log::onConsoleInput(const std::string& text)
{
   if (!presentation::state::isActive())
      return;

   consoleInputBuffer_.push_back(text);
}

void Log::onConsoleOutput(module_context::ConsoleOutputType type,
                     const std::string& output)
{
   if (!presentation::state::isActive())
      return;

   if (type == module_context::ConsoleOutputError)
      errorOutputBuffer_.push_back(output);

}

namespace {

std::string csvString(std::string str)
{
   boost::algorithm::replace_all(str, "\n", "\\n");
   boost::algorithm::replace_all(str, "\"", "\"\"");
   return "\"" + str + "\"";
}

std::string timestamp()
{
   // generate timestamp
   using namespace boost::posix_time;
   ptime time = microsec_clock::universal_time();
   std::string dateTime = date_time::format(time, "%Y-%m-%dT%H:%M:%SZ");
   return dateTime;
}

Error ensureTargetFile(const std::string& filename,
                       const std::string& header,
                       FilePath* pTargetFile)
{
   using namespace module_context;
   FilePath presDir =  userScratchPath().childPath("presentation");
   Error error = presDir.ensureDirectory();
   if (error)
      return error;

   *pTargetFile = presDir.childPath(filename);
   if (!pTargetFile->exists())
   {
      Error error = core::writeStringToFile(*pTargetFile, header + "\n");
      if (error)
         return error;
   }

   return Success();
}

} // anonymous namespace

std::string Log::currentSlideType() const
{
   if (currentSlideIndex_ < slideTypes_.size())
      return slideTypes_[currentSlideIndex_];
   else
      return "default";
}

std::string Log::currentSlideHelpTopic() const
{
   if (currentSlideIndex_ < slideHelpTopics_.size())
      return slideHelpTopics_[currentSlideIndex_];
   else
      return "";
}

std::string Log::currentSlideHelpDoc() const
{
   if (currentSlideIndex_ < slideHelpDocs_.size())
      return slideHelpDocs_[currentSlideIndex_];
   else
      return "";
}

void Log::append(EntryType type,
                 const FilePath& presPath,
                 int slideIndex,
                 const std::string& slideType,
                 const std::string& helpTopic,
                 const std::string& helpDoc,
                 const std::string& input,
                 const std::string& errors)
{
   // ensure target file
   FilePath logFilePath;
   Error error = ensureTargetFile(
            "presentation-log-v1.csv",
            "type, timestamp, presentation, slide, slide-type, help-topic, "
            "help-doc, input, errors\n",
            &logFilePath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // generate entry
   std::vector<std::string> fields;
   fields.push_back((type == NavigationEntry) ? "Navigation" : "Input");
   fields.push_back(timestamp());
   fields.push_back(csvString(module_context::createAliasedPath(presPath)));
   fields.push_back(safe_convert::numberToString(slideIndex));
   fields.push_back(slideType);
   fields.push_back(csvString(helpTopic));
   fields.push_back(csvString(helpDoc));
   fields.push_back(csvString(input));
   fields.push_back(csvString(errors));
   std::string entry = boost::algorithm::join(fields, ",");

   // append entry
   error = core::appendToFile(logFilePath, entry + "\n");
   if (error)
      LOG_ERROR(error);
}

void Log::recordFeedback(const std::string& feedback)
{
   // ensure target file
   FilePath feedbackFilePath;
   Error error = ensureTargetFile("feedback-v1.csv",
                                  "timestamp, presentation, slide, feedback\n",
                                  &feedbackFilePath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // generate entry
   std::vector<std::string> fields;
   fields.push_back(timestamp());
   fields.push_back(csvString(module_context::createAliasedPath(
                                          presentation::state::filePath())));
   fields.push_back(safe_convert::numberToString(currentSlideIndex_));
   fields.push_back(csvString(feedback));
   std::string entry = boost::algorithm::join(fields, ",");

   // append entry
   error = core::appendToFile(feedbackFilePath, entry + "\n");
   if (error)
      LOG_ERROR(error);
}

} // namespace presentation
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>//===-- EmitFunctions.cpp - interface to insert instrumentation --*- C++ -*--=//
//
// This inserts a global constant table with function pointers all along
//
//===----------------------------------------------------------------------===//

//#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
//#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Instrumentation/EmitFunctions.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include <iostream>
#include <fstream>

using std::vector;

struct EmitFunctionTable : public Pass {
  const char *getPassName() const { return "EmitFunctionTablePass"; }

  bool run(Module &M);
};

//  Create a new pass to add function table
//
Pass *createEmitFunctionTablePass() {
  return new EmitFunctionTable();
}

//Per Module pass for inserting function table
bool EmitFunctionTable::run(Module &M){
  vector<const Type*> vType;
  vector<Constant *> vConsts;
  for(Module::iterator MI = M.begin(), ME = M.end(); MI!=ME; ++MI){
    Function *F = MI;
    if(F->size()<=1) continue;
    ConstantPointerRef *cpref = ConstantPointerRef::get(F);
    vType.push_back(MI->getType());
    vConsts.push_back(cpref);
  }

  StructType *sttype = StructType::get(vType);
  ConstantStruct *cstruct = ConstantStruct::get(sttype, vConsts);

  GlobalVariable *gb = new GlobalVariable(cstruct->getType(), true, true,
                                          cstruct, "llvmFunctionTable");
  M.getGlobalList().push_back(gb);
  return true;  // Always modifies function
}
<commit_msg>* Cleanup pass * The global variable cannot be internal or else we cannot use it! * Always add a function to the table, even if it only has a single basic   block.<commit_after>//===-- EmitFunctions.cpp - interface to insert instrumentation --*- C++ -*--=//
//
// This inserts a global constant table with function pointers all along
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Instrumentation/EmitFunctions.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"

using std::vector;

struct EmitFunctionTable : public Pass {
  const char *getPassName() const { return "EmitFunctionTablePass"; }

  bool run(Module &M);
};

// Create a new pass to add function table
//
Pass *createEmitFunctionTablePass() {
  return new EmitFunctionTable();
}

// Per Module pass for inserting function table
bool EmitFunctionTable::run(Module &M){
  vector<const Type*> vType;
  vector<Constant *> vConsts;
  for(Module::iterator MI = M.begin(), ME = M.end(); MI!=ME; ++MI)
    if (!MI->isExternal()) {
      ConstantPointerRef *CP = ConstantPointerRef::get(MI);
      vType.push_back(MI->getType());
      vConsts.push_back(CP);
    }

  StructType *sttype = StructType::get(vType);
  ConstantStruct *cstruct = ConstantStruct::get(sttype, vConsts);

  GlobalVariable *gb = new GlobalVariable(cstruct->getType(), true, false,
                                          cstruct, "llvmFunctionTable");
  M.getGlobalList().push_back(gb);
  return true;  // Always modifies program
}
<|endoftext|>


<commit_before><commit_msg>Check event status before notify<commit_after><|endoftext|>


<commit_before>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2020 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __YLIKUUTIO_ONTOLOGY_ENTITY_FACTORY_HPP_INCLUDED
#define __YLIKUUTIO_ONTOLOGY_ENTITY_FACTORY_HPP_INCLUDED

#include "variable_struct.hpp"
#include "world_struct.hpp"
#include "scene_struct.hpp"
#include "shader_struct.hpp"
#include "material_struct.hpp"
#include "species_struct.hpp"
#include "object_struct.hpp"
#include "symbiosis_struct.hpp"
#include "holobiont_struct.hpp"
#include "vector_font_struct.hpp"
#include "text_struct.hpp"
#include "text3D_struct.hpp"
#include "console_struct.hpp"
#include "font_struct.hpp"
#include "lisp_function_struct.hpp"
#include "camera_struct.hpp"
#include "compute_task_struct.hpp"
#include "brain_struct.hpp"

// Include standard headers
#include <cstddef>   // std::size_t
#include <memory>    // std::make_shared, std::shared_ptr
#include <string>    // std::string

namespace yli::ontology
{
    class Entity;
    class Variable;
    class Universe;
    class World;
    class Scene;
    class Shader;
    class Material;
    class Species;
    class Object;
    class VectorFont;
    class Text3D;
    class Font2D;
    class Console;
    class ComputeTask;
    class Brain;

    class EntityFactory
    {
        public:
            // constructor.
            EntityFactory(yli::ontology::Universe* const universe);

            EntityFactory(const EntityFactory&) = delete;            // Delete copy constructor.
            EntityFactory& operator=(const EntityFactory&) = delete; // Delete copy assignment.

            // destructor.
            ~EntityFactory();

            yli::ontology::Universe* get_universe() const;

            yli::ontology::Entity* create_variable(const yli::ontology::VariableStruct& variable_struct) const;
            yli::ontology::Entity* create_world(const yli::ontology::WorldStruct& world_struct) const;
            yli::ontology::Entity* create_scene(const yli::ontology::SceneStruct& scene_struct) const;
            yli::ontology::Entity* create_shader(const yli::ontology::ShaderStruct& shader_struct) const;
            yli::ontology::Entity* create_material(const yli::ontology::MaterialStruct& material_struct) const;
            yli::ontology::Entity* create_species(const yli::ontology::SpeciesStruct& species_struct) const;
            yli::ontology::Entity* create_object(const yli::ontology::ObjectStruct& object_struct) const;
            yli::ontology::Entity* create_symbiosis(const yli::ontology::SymbiosisStruct& symbiosis_struct) const;
            yli::ontology::Entity* create_holobiont(const yli::ontology::HolobiontStruct& object_struct) const;
            yli::ontology::Entity* create_vector_font(const yli::ontology::VectorFontStruct& vector_font_struct) const;
            yli::ontology::Entity* create_text2d(const yli::ontology::TextStruct& text_struct) const;
            yli::ontology::Entity* create_text3d(const yli::ontology::Text3DStruct& text3D_struct) const;
            yli::ontology::Entity* create_font2d(const yli::ontology::FontStruct& font_struct) const;
            yli::ontology::Entity* create_console(const yli::ontology::ConsoleStruct& console_struct) const;
            yli::ontology::Entity* create_lisp_function(const yli::ontology::LispFunctionStruct& lisp_function_struct) const;
            yli::ontology::Entity* create_camera(const yli::ontology::CameraStruct& camera_struct) const;
            yli::ontology::Entity* create_compute_task(const yli::ontology::ComputeTaskStruct& compute_task_struct) const;
            yli::ontology::Entity* create_brain(const yli::ontology::BrainStruct& brain_struct) const;
            yli::ontology::Entity* create_callback_engine_entity() const;

        private:
            yli::ontology::Universe* universe;
    };
}

#endif
<commit_msg>Replace `#include` lines with forward declarations.<commit_after>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2020 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __YLIKUUTIO_ONTOLOGY_ENTITY_FACTORY_HPP_INCLUDED
#define __YLIKUUTIO_ONTOLOGY_ENTITY_FACTORY_HPP_INCLUDED

// Include standard headers
#include <cstddef>   // std::size_t
#include <memory>    // std::make_shared, std::shared_ptr
#include <string>    // std::string

namespace yli::ontology
{
    class Entity;
    class Variable;
    class Universe;
    class World;
    class Scene;
    class Shader;
    class Material;
    class Species;
    class Object;
    class VectorFont;
    class Text3D;
    class Font2D;
    class Console;
    class ComputeTask;
    class Brain;
    struct VariableStruct;
    struct WorldStruct;
    struct SceneStruct;
    struct ShaderStruct;
    struct MaterialStruct;
    struct SpeciesStruct;
    struct ObjectStruct;
    struct SymbiosisStruct;
    struct HolobiontStruct;
    struct VectorFontStruct;
    struct FontStruct;
    struct TextStruct;
    struct Text3DStruct;
    struct ConsoleStruct;
    struct LispFunctionStruct;
    struct CameraStruct;
    struct ComputeTaskStruct;
    struct BrainStruct;

    class EntityFactory
    {
        public:
            // constructor.
            EntityFactory(yli::ontology::Universe* const universe);

            EntityFactory(const EntityFactory&) = delete;            // Delete copy constructor.
            EntityFactory& operator=(const EntityFactory&) = delete; // Delete copy assignment.

            // destructor.
            ~EntityFactory();

            yli::ontology::Universe* get_universe() const;

            yli::ontology::Entity* create_variable(const yli::ontology::VariableStruct& variable_struct) const;
            yli::ontology::Entity* create_world(const yli::ontology::WorldStruct& world_struct) const;
            yli::ontology::Entity* create_scene(const yli::ontology::SceneStruct& scene_struct) const;
            yli::ontology::Entity* create_shader(const yli::ontology::ShaderStruct& shader_struct) const;
            yli::ontology::Entity* create_material(const yli::ontology::MaterialStruct& material_struct) const;
            yli::ontology::Entity* create_species(const yli::ontology::SpeciesStruct& species_struct) const;
            yli::ontology::Entity* create_object(const yli::ontology::ObjectStruct& object_struct) const;
            yli::ontology::Entity* create_symbiosis(const yli::ontology::SymbiosisStruct& symbiosis_struct) const;
            yli::ontology::Entity* create_holobiont(const yli::ontology::HolobiontStruct& object_struct) const;
            yli::ontology::Entity* create_vector_font(const yli::ontology::VectorFontStruct& vector_font_struct) const;
            yli::ontology::Entity* create_text2d(const yli::ontology::TextStruct& text_struct) const;
            yli::ontology::Entity* create_text3d(const yli::ontology::Text3DStruct& text3D_struct) const;
            yli::ontology::Entity* create_font2d(const yli::ontology::FontStruct& font_struct) const;
            yli::ontology::Entity* create_console(const yli::ontology::ConsoleStruct& console_struct) const;
            yli::ontology::Entity* create_lisp_function(const yli::ontology::LispFunctionStruct& lisp_function_struct) const;
            yli::ontology::Entity* create_camera(const yli::ontology::CameraStruct& camera_struct) const;
            yli::ontology::Entity* create_compute_task(const yli::ontology::ComputeTaskStruct& compute_task_struct) const;
            yli::ontology::Entity* create_brain(const yli::ontology::BrainStruct& brain_struct) const;
            yli::ontology::Entity* create_callback_engine_entity() const;

        private:
            yli::ontology::Universe* universe;
    };
}

#endif
<|endoftext|>


<commit_before><commit_msg>Bugfix x 3: null terminator of `char` array is taken into count.<commit_after><|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------

Copyright (c) 2010 Nigel Atkinson

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 <scriptingsystem.h>
#include <OgreLogManager.h>
#include <inputeventdata.h>
#include <windoweventdata.h>
#include <animationeventdata.h>
#include <luaresource.h>
#include <gameentity.h>
#include <version.h>
#include <LuaBridge.h>

void bindOgre( lua_State* L ); // From ogrebind.cpp
/*
void bindAnimation( lua_State* L ); // From animationbind.cpp
void bindNavigationMesh( lua_State* L); // From navmeshbind.cpp
*/
void bindGorilla( lua_State *L ); // From gorillabind.cpp

template<class D, class B>
D* downcast( B* ptr )
{
    return dynamic_cast<D*>( ptr );
}

int ScriptingSystem::GUID = 0;

void queueEventThunk( Event& event, lua_State *L )
{
    lua_pushlightuserdata( L, (void *)&ScriptingSystem::GUID );
    lua_gettable( L, LUA_REGISTRYINDEX );

    ScriptingSystem* scriptingSystem = static_cast<ScriptingSystem*>(lua_touserdata( L, -1 ));

    if( scriptingSystem )
    {
        scriptingSystem->queueEvent( EventPtr( new Event(event) ) );
    }
    else
    {
        Ogre::LogManager::getSingleton().stream() << "Error queuing event from Lua; could not retrieve scripting system instance";
    }
}

int luaLibraryLoader( lua_State *L )
{
    if( ! lua_isstring( L, 1 ) )
    {
        luaL_error( L, "luaLibraryLoader: Expected string for first parameter" );
    }

    std::string libraryFile = lua_tostring( L, 1 );
    // In order to be compatible with the normal Lua file loader,
    // translate '.' to the file system seperator character.
    // In this case (An ogre resource) '/'
    while( libraryFile.find('.') != std::string::npos )
        libraryFile.replace( libraryFile.find('.'), 1, "/" );

    libraryFile += ".lua";

    if( ! Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup( libraryFile ) )
    {
        // Could not find the file.
        std::string errMessage = "\n  no file '" + libraryFile + "' found in Ogre resource archives.";
        lua_pushstring( L, errMessage.c_str() );
    }
    else
    {
        LuaResourcePtr library = LuaResourceManager::getSingleton().load( libraryFile, "General" );

        if( luaL_loadbuffer( L, library->getScriptSource().c_str(), library->calculateSize(), libraryFile.c_str() ) )
        {
            luaL_error( L, "Error loading library '%s' from resource archive.\n%s", libraryFile.c_str(), lua_tostring( L, -1 ) );
        }
    }
    return 1;
}

void installLibraryLoader( lua_State *L )
{
    // Insert the c++ func 'luaLibraryLoader' into package.loaders.
    // Inserted at the start of the table in order to take precedence.
    lua_getglobal( L, "table" );
    lua_getfield( L, -1, "insert" );
    lua_remove( L, -2 );    // table
    lua_getglobal( L, "package" );
    lua_getfield( L, -1, "searchers" );
    lua_remove( L, -2 );    // package
    lua_pushnumber( L, 1 ); // index where to insert into loaders table
    lua_pushcfunction( L, luaLibraryLoader );
    if( lua_pcall( L, 3, 0, 0 ) )
        Ogre::LogManager::getSingleton().stream() << lua_tostring( L, 1);
}

void getClassMembers( lua_State* L, luabridge::LuaRef ret )
{

    // List keys where they don't start with underscore.
    lua_pushnil( L );
    while( lua_next( L, -2 ) )
    {
        lua_pushvalue( L, -2 ); // Push copy of key.
        const char *key = lua_tostring( L, -1 );

        if( key )
        {
            if( key[0] != '_' )
            {
                ret.append( key );
            }
        }

        lua_pop( L, 2 ); // Key copy and value
    }
    // List properties
    lua_pushstring( L, "__propget" );
    lua_rawget( L, -2 );
    if( lua_istable( L, -1 ) )
    {
        lua_pushnil( L );
        while( lua_next( L, -2 ) )
        {
            lua_pushvalue( L, -2 ); // Push copy of key.
            const char *key = lua_tostring( L, -1 );

            if( key )
            {
                ret.append( key );
            }

            lua_pop( L, 2 ); // Key copy and value
        }
    }
    lua_pop( L, 1 ); // __propget table

    return;
}

int getClassInfo( lua_State* L )
{
    luabridge::LuaRef ret = luabridge::newTable( L );

    if( lua_istable( L, 1 ) )
    {
        // Class Type
        lua_getmetatable( L, 1 );

        // Static members.
        getClassMembers( L, ret );

        // Regular members.
        lua_pushstring( L, "__class" );
        lua_rawget( L, -2 );

        if( lua_istable( L, -1 ) )
        {
            getClassMembers( L, ret );
        }
    }
    else if( lua_isuserdata( L, 1 ) )
    {
        // Class instance
        lua_getmetatable( L, 1 );

        getClassMembers( L, ret );
    }

    // Just return an empty table if not a class.
    ret.push( L );

    return 1;
}

void ScriptingSystem::shutdown()
{
    if( mL )
        lua_close( mL );
    mL = 0;
}

void ScriptingSystem::initialise()
{
    mL = luaL_newstate();

    luaL_openlibs( mL );

    lua_pushlightuserdata( mL, (void *)&GUID );
    lua_pushlightuserdata( mL, this );
    lua_settable( mL, LUA_REGISTRYINDEX );

    bind();
    bindOgre( mL );
    /*
    bindGameEntityClasses( mL );
    bindAnimation( mL );
    bindNavigationMesh( mL );
    */
    bindGorilla( mL );

    using namespace luabridge;

    LuaResourcePtr mainlua = LuaResourceManager::getSingleton().load( "main.lua" );

    if( luaL_loadbuffer( mL,
                mainlua->getScriptSource().c_str(),
                mainlua->calculateSize(), "main.lua" ) || lua_pcall( mL, 0, LUA_MULTRET, 0) )
    {
        Ogre::LogManager::getSingleton().stream() << " ****************************** ";
        Ogre::LogManager::getSingleton().stream() << " *** main.lua failed to run     ";
        Ogre::LogManager::getSingleton().stream() << " *** " << lua_tostring( mL, -1 );
        Ogre::LogManager::getSingleton().stream() << " ****************************** ";
    }
}

void ScriptingSystem::bind()
{
    using namespace luabridge;

    installLibraryLoader( mL );

    getGlobalNamespace( mL )
        .addCFunction( "getClassInfo", &getClassInfo )
        .beginNamespace( "Engine" )
        .beginClass<Event>( "Event" )
            .addConstructor<void (*) (const char*)>()
            .addData( "type", &Event::type )
            .addData( "data", &Event::data )
            .addStaticFunction( "hash", &Event::hash )
        .endClass()
        .addFunction( "queueEvent", &queueEventThunk )
        .beginClass<EventData>( "EventData" )
        .endClass()
        .deriveClass<InputEventData, EventData>( "InputEventData" )
            .addConstructor<void (*) (void)>()
            .addStaticFunction( "downcast", &downcast<InputEventData, EventData> )
            .addData( "x", &InputEventData::x )
            .addData( "y", &InputEventData::y )
            .addData( "buttons", &InputEventData::parm )
            .addProperty( "text", &InputEventDataBindingHelper::getText, &InputEventDataBindingHelper::setText )
            .addProperty( "key",  &InputEventDataBindingHelper::getKey,  &InputEventDataBindingHelper::setKey  )
        .endClass()
        .deriveClass<WindowEventData, EventData>( "WindowEventData" )
            .addStaticFunction( "downcast", &downcast<WindowEventData, EventData> )
            .addData( "width", &WindowEventData::width )
            .addData( "height", &WindowEventData::height )
        .endClass()
        /*
        .deriveClass<AnimationEventData, EventData>( "AnimationEventData" )
            .addData( "animation", &AnimationEventData::animation )
        .endClass()
        */
        .addFunction( "versionString", versionString )
    .endNamespace();
}

bool ScriptingSystem::EventNotification( EventPtr event )
{
    luabridge::LuaRef notify = luabridge::getGlobal( mL, "EventNotification");
    luabridge::LuaRef ret( mL );

    if( notify )
    {
        try
        {
            ret = notify( *event );
            if( ret == true )
                return true;
        }
        catch( luabridge::LuaException& e )
        {
            Ogre::LogManager::getSingleton().stream() << e.what();
        }
    }

    return false;
}

bool ScriptingSystem::frameStarted(const Ogre::FrameEvent& evt)
{
    luabridge::LuaRef func = luabridge::getGlobal( mL, "FrameStarted" );

    try
    {
        // If the function is not defined, don't worry about it.
        if( func )
            func( evt.timeSinceLastFrame );
    }
    catch( luabridge::LuaException& e )
    {
        Ogre::LogManager::getSingleton().stream() << e.what();
    }

    return true;
}

bool ScriptingSystem::frameEnded(const Ogre::FrameEvent& evt)
{
    luabridge::LuaRef func = luabridge::getGlobal( mL, "FrameEnded" );

    try
    {
        // If the function is not defined, don't worry about it.
        if( func )
            func( evt.timeSinceLastFrame );
    }
    catch( luabridge::LuaException& e )
    {
        Ogre::LogManager::getSingleton().stream() << e.what();
    }

    // Do a Lua garbage collection.
    lua_gc( mL, LUA_GCSTEP, 1 );

    return true;
}
<commit_msg>Catch __gc metamethod errors on tables with try catch block<commit_after>/*
-----------------------------------------------------------------------------

Copyright (c) 2010 Nigel Atkinson

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 <scriptingsystem.h>
#include <OgreLogManager.h>
#include <inputeventdata.h>
#include <windoweventdata.h>
#include <animationeventdata.h>
#include <luaresource.h>
#include <gameentity.h>
#include <version.h>
#include <LuaBridge.h>

void bindOgre( lua_State* L ); // From ogrebind.cpp
/*
void bindAnimation( lua_State* L ); // From animationbind.cpp
void bindNavigationMesh( lua_State* L); // From navmeshbind.cpp
*/
void bindGorilla( lua_State *L ); // From gorillabind.cpp

template<class D, class B>
D* downcast( B* ptr )
{
    return dynamic_cast<D*>( ptr );
}

int ScriptingSystem::GUID = 0;

void queueEventThunk( Event& event, lua_State *L )
{
    lua_pushlightuserdata( L, (void *)&ScriptingSystem::GUID );
    lua_gettable( L, LUA_REGISTRYINDEX );

    ScriptingSystem* scriptingSystem = static_cast<ScriptingSystem*>(lua_touserdata( L, -1 ));

    if( scriptingSystem )
    {
        scriptingSystem->queueEvent( EventPtr( new Event(event) ) );
    }
    else
    {
        Ogre::LogManager::getSingleton().stream() << "Error queuing event from Lua; could not retrieve scripting system instance";
    }
}

int luaLibraryLoader( lua_State *L )
{
    if( ! lua_isstring( L, 1 ) )
    {
        luaL_error( L, "luaLibraryLoader: Expected string for first parameter" );
    }

    std::string libraryFile = lua_tostring( L, 1 );
    // In order to be compatible with the normal Lua file loader,
    // translate '.' to the file system seperator character.
    // In this case (An ogre resource) '/'
    while( libraryFile.find('.') != std::string::npos )
        libraryFile.replace( libraryFile.find('.'), 1, "/" );

    libraryFile += ".lua";

    if( ! Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup( libraryFile ) )
    {
        // Could not find the file.
        std::string errMessage = "\n  no file '" + libraryFile + "' found in Ogre resource archives.";
        lua_pushstring( L, errMessage.c_str() );
    }
    else
    {
        LuaResourcePtr library = LuaResourceManager::getSingleton().load( libraryFile, "General" );

        if( luaL_loadbuffer( L, library->getScriptSource().c_str(), library->calculateSize(), libraryFile.c_str() ) )
        {
            luaL_error( L, "Error loading library '%s' from resource archive.\n%s", libraryFile.c_str(), lua_tostring( L, -1 ) );
        }
    }
    return 1;
}

void installLibraryLoader( lua_State *L )
{
    // Insert the c++ func 'luaLibraryLoader' into package.loaders.
    // Inserted at the start of the table in order to take precedence.
    lua_getglobal( L, "table" );
    lua_getfield( L, -1, "insert" );
    lua_remove( L, -2 );    // table
    lua_getglobal( L, "package" );
    lua_getfield( L, -1, "searchers" );
    lua_remove( L, -2 );    // package
    lua_pushnumber( L, 1 ); // index where to insert into loaders table
    lua_pushcfunction( L, luaLibraryLoader );
    if( lua_pcall( L, 3, 0, 0 ) )
        Ogre::LogManager::getSingleton().stream() << lua_tostring( L, 1);
}

void getClassMembers( lua_State* L, luabridge::LuaRef ret )
{

    // List keys where they don't start with underscore.
    lua_pushnil( L );
    while( lua_next( L, -2 ) )
    {
        lua_pushvalue( L, -2 ); // Push copy of key.
        const char *key = lua_tostring( L, -1 );

        if( key )
        {
            if( key[0] != '_' )
            {
                ret.append( key );
            }
        }

        lua_pop( L, 2 ); // Key copy and value
    }
    // List properties
    lua_pushstring( L, "__propget" );
    lua_rawget( L, -2 );
    if( lua_istable( L, -1 ) )
    {
        lua_pushnil( L );
        while( lua_next( L, -2 ) )
        {
            lua_pushvalue( L, -2 ); // Push copy of key.
            const char *key = lua_tostring( L, -1 );

            if( key )
            {
                ret.append( key );
            }

            lua_pop( L, 2 ); // Key copy and value
        }
    }
    lua_pop( L, 1 ); // __propget table

    return;
}

int getClassInfo( lua_State* L )
{
    luabridge::LuaRef ret = luabridge::newTable( L );

    if( lua_istable( L, 1 ) )
    {
        // Class Type
        lua_getmetatable( L, 1 );

        // Static members.
        getClassMembers( L, ret );

        // Regular members.
        lua_pushstring( L, "__class" );
        lua_rawget( L, -2 );

        if( lua_istable( L, -1 ) )
        {
            getClassMembers( L, ret );
        }
    }
    else if( lua_isuserdata( L, 1 ) )
    {
        // Class instance
        lua_getmetatable( L, 1 );

        getClassMembers( L, ret );
    }

    // Just return an empty table if not a class.
    ret.push( L );

    return 1;
}

void ScriptingSystem::shutdown()
{
    if( mL )
        lua_close( mL );
    mL = 0;
}

void ScriptingSystem::initialise()
{
    mL = luaL_newstate();

    luaL_openlibs( mL );

    lua_pushlightuserdata( mL, (void *)&GUID );
    lua_pushlightuserdata( mL, this );
    lua_settable( mL, LUA_REGISTRYINDEX );

    bind();
    bindOgre( mL );
    /*
    bindGameEntityClasses( mL );
    bindAnimation( mL );
    bindNavigationMesh( mL );
    */
    bindGorilla( mL );

    using namespace luabridge;

    LuaResourcePtr mainlua = LuaResourceManager::getSingleton().load( "main.lua" );

    if( luaL_loadbuffer( mL,
                mainlua->getScriptSource().c_str(),
                mainlua->calculateSize(), "main.lua" ) || lua_pcall( mL, 0, LUA_MULTRET, 0) )
    {
        Ogre::LogManager::getSingleton().stream() << " ****************************** ";
        Ogre::LogManager::getSingleton().stream() << " *** main.lua failed to run     ";
        Ogre::LogManager::getSingleton().stream() << " *** " << lua_tostring( mL, -1 );
        Ogre::LogManager::getSingleton().stream() << " ****************************** ";
    }
}

void ScriptingSystem::bind()
{
    using namespace luabridge;

    installLibraryLoader( mL );

    getGlobalNamespace( mL )
        .addCFunction( "getClassInfo", &getClassInfo )
        .beginNamespace( "Engine" )
        .beginClass<Event>( "Event" )
            .addConstructor<void (*) (const char*)>()
            .addData( "type", &Event::type )
            .addData( "data", &Event::data )
            .addStaticFunction( "hash", &Event::hash )
        .endClass()
        .addFunction( "queueEvent", &queueEventThunk )
        .beginClass<EventData>( "EventData" )
        .endClass()
        .deriveClass<InputEventData, EventData>( "InputEventData" )
            .addConstructor<void (*) (void)>()
            .addStaticFunction( "downcast", &downcast<InputEventData, EventData> )
            .addData( "x", &InputEventData::x )
            .addData( "y", &InputEventData::y )
            .addData( "buttons", &InputEventData::parm )
            .addProperty( "text", &InputEventDataBindingHelper::getText, &InputEventDataBindingHelper::setText )
            .addProperty( "key",  &InputEventDataBindingHelper::getKey,  &InputEventDataBindingHelper::setKey  )
        .endClass()
        .deriveClass<WindowEventData, EventData>( "WindowEventData" )
            .addStaticFunction( "downcast", &downcast<WindowEventData, EventData> )
            .addData( "width", &WindowEventData::width )
            .addData( "height", &WindowEventData::height )
        .endClass()
        /*
        .deriveClass<AnimationEventData, EventData>( "AnimationEventData" )
            .addData( "animation", &AnimationEventData::animation )
        .endClass()
        */
        .addFunction( "versionString", versionString )
    .endNamespace();
}

bool ScriptingSystem::EventNotification( EventPtr event )
{
    luabridge::LuaRef notify = luabridge::getGlobal( mL, "EventNotification");
    luabridge::LuaRef ret( mL );

    if( notify )
    {
        try
        {
            ret = notify( *event );
            if( ret == true )
                return true;
        }
        catch( luabridge::LuaException& e )
        {
            Ogre::LogManager::getSingleton().stream() << e.what();
        }
    }

    return false;
}

bool ScriptingSystem::frameStarted(const Ogre::FrameEvent& evt)
{
    luabridge::LuaRef func = luabridge::getGlobal( mL, "FrameStarted" );

    try
    {
        // If the function is not defined, don't worry about it.
        if( func )
            func( evt.timeSinceLastFrame );
    }
    catch( luabridge::LuaException& e )
    {
        Ogre::LogManager::getSingleton().stream() << e.what();
    }

    return true;
}

bool ScriptingSystem::frameEnded(const Ogre::FrameEvent& evt)
{
    luabridge::LuaRef func = luabridge::getGlobal( mL, "FrameEnded" );

    try
    {
        // If the function is not defined, don't worry about it.
        if( func )
            func( evt.timeSinceLastFrame );

        // Do a Lua garbage collection.
        // We do it like this - as LuaRef translates any errors in finalizers
        // to exceptions, which we then catch.
        luabridge::LuaRef gc = luabridge::getGlobal( mL, "collectgarbage" );
        gc( "step" );
    }
    catch( luabridge::LuaException& e )
    {
        Ogre::LogManager::getSingleton().stream() << e.what();
    }

    return true;
}
<|endoftext|>


<commit_before>#include "Marker.hpp"
#include <tf/transform_datatypes.h>
#include <math.h>

Marker::Marker(double xPos, double yPos, double angle, MarkerType t, std::string name) {
	pos.position.x = xPos;
	pos.position.y = yPos;
	pos.orientation = SetQuaternation(0, 0, Deg2Rad(angle));
	type = t;
	markerName = name;
}

Marker::Marker(geometry_msgs::Pose p, MarkerType t, std::string name) {
	pos = p;
	type = t;
	markerName = name;
}

geometry_msgs::Quaternion Marker::SetQuaternation(double roll, double pitch, double yaw) {
	return tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);
}

double Marker::GetX() {
    return pos.position.x;
}

double Marker::GetY() {
    return pos.position.y;
}

double Marker::GetAngle() {
	tf::Quaternion q;
	tf::quaternionMsgToTF(pos.orientation, q);
	q.normalize();
	return Rad2Deg(tf::getYaw(q));
}

MarkerType Marker::GetType() {
    return type;
}

std::string Marker::GetTypeStr() {
	if(type == Shelf) {
		return "Shelf";
	} else if (type == Workstation) {
		return "Workstation";
	} else if (type == Conveyor) {
		return "Conveyor";
	} else if (type == Waypoint) {
		return "Waypoint";
	} else if (type == Precision) {
		return "Precision";
	} else {
		return "Other";
	}
}

std::string Marker::GetName() {
	return markerName;
}

geometry_msgs::Quaternion Marker::GetQuaternation() {
	return pos.orientation;
}

geometry_msgs::Point Marker::GetPoint() {
	return pos.position;
}

geometry_msgs::Pose Marker::GetPose() {
	return pos;
}

double Marker::Rad2Deg(double rad) {
	return (rad * 180.0 / M_PI);
}

double Marker::Deg2Rad(double deg) {
	return (deg * M_PI / 180.0);
}<commit_msg>Added check for nan in ngle<commit_after>#include "Marker.hpp"
#include <tf/transform_datatypes.h>
#include <math.h>

Marker::Marker(double xPos, double yPos, double angle, MarkerType t, std::string name) {
	pos.position.x = xPos;
	pos.position.y = yPos;
	pos.orientation = SetQuaternation(0, 0, Deg2Rad(angle));
	type = t;
	markerName = name;
}

Marker::Marker(geometry_msgs::Pose p, MarkerType t, std::string name) {
	pos = p;
	type = t;
	markerName = name;
}

geometry_msgs::Quaternion Marker::SetQuaternation(double roll, double pitch, double yaw) {
	return tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);
}

double Marker::GetX() {
    return pos.position.x;
}

double Marker::GetY() {
    return pos.position.y;
}

double Marker::GetAngle() {
	tf::Quaternion q;

	tf::quaternionMsgToTF(pos.orientation, q);
	q.normalize();
	double angle = Rad2Deg(tf::getYaw(q));
	if(isnan(angle))
	{
		angle = 0;
	}
	return angle;
}

MarkerType Marker::GetType() {
    return type;
}

std::string Marker::GetTypeStr() {
	if(type == Shelf) {
		return "Shelf";
	} else if (type == Workstation) {
		return "Workstation";
	} else if (type == Conveyor) {
		return "Conveyor";
	} else if (type == Waypoint) {
		return "Waypoint";
	} else if (type == Precision) {
		return "Precision";
	} else {
		return "Other";
	}
}

std::string Marker::GetName() {
	return markerName;
}

geometry_msgs::Quaternion Marker::GetQuaternation() {
	return pos.orientation;
}

geometry_msgs::Point Marker::GetPoint() {
	return pos.position;
}

geometry_msgs::Pose Marker::GetPose() {
	return pos;
}

double Marker::Rad2Deg(double rad) {
	return (rad * 180.0 / M_PI);
}

double Marker::Deg2Rad(double deg) {
	return (deg * M_PI / 180.0);
}
<|endoftext|>