Exemplo n.º 1
0
int main(int argc, char *argv[])
{
	// Create the world
	Enki::World world(200, 200);
	
	// Create a Khepera and position it
	Enki::EPuck *ePuck = new Enki::EPuck;
	ePuck->pos = Enki::Point(100, 100);
	ePuck->leftSpeed = 30;
	ePuck->rightSpeed = 20;
	
	// objects are garbage collected by the world on destruction
	world.addObject(ePuck);
	
	Enki::Polygone p;
	const double amount = 9;
	const double radius = 5;
	const double height = 20;
	for (double a = 0; a < 2*M_PI; a += 2*M_PI/amount)
		p.push_back(Enki::Point(radius * cos(a), radius * sin(a)));
	Enki::PhysicalObject* o = new Enki::PhysicalObject;
	Enki::PhysicalObject::Hull hull(Enki::PhysicalObject::Part(p, height));
	o->setCustomHull(hull, 1);
	o->pos = Enki::Point(100, 100);
	o->setColor(Enki::Color(0.4,0.6,0.8));
	world.addObject(o);
	
	// Run for some times
	for (unsigned i=0; i<10; i++)
	{
		// step of 50 ms
		world.step(0.05);
		std::cout << "E-puck pos is (" << ePuck->pos.x << "," << ePuck->pos.y << ")" << std::endl;
	}
}
void TEnkiEnvironment::addCubeWithParameters (double x, double y, Enki::Color color, int objectNumber)
{
  // Создаем полигон, являющийся основнанием куба
  Enki::Polygone p;
  p.push_back(Enki::Point(cubeSize/2.0,cubeSize/2.0));
  p.push_back(Enki::Point(-cubeSize/2.0,cubeSize/2.0));
  p.push_back(Enki::Point(-cubeSize/2.0,-cubeSize/2.0));
  p.push_back(Enki::Point(cubeSize/2.0,-cubeSize/2.0));
  
  Enki::PhysicalObject* o = new Enki::PhysicalObject;
  Enki::PhysicalObject::Hull hull(Enki::PhysicalObject::Part(p, cubeSize)); // Задаем форму куба
  o->setCustomHull(hull, -100000); // Отрицательная масса - то же, что бесконечная, поэтому куб сдвинуть с места будет невозможно                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            ));
  o->collisionElasticity = 0; // Все тепло от столкновения поглощается
  o->setColor(color);    
  o->pos = Enki::Point(x, y);
  o->objectNumber = objectNumber;
  world->addObject(o);
}
// Меняем местами положение кубов (в том числе и в массиве целей)
void TEnkiEnvironment::swapCubesForColors(double r1, double g1, double b1, double r2, double g2, double b2) {
  // Находим кубы в массиве объектов ENKI по их цвету, а затем перекрашиваем их
  std::set<Enki::PhysicalObject *>objects = world->objects;
  std::set<Enki::PhysicalObject *>::iterator someObject;
  for (someObject=objects.begin(); someObject!=objects.end(); ++someObject) {
    Enki::PhysicalObject * actualObject = *someObject;
    Enki::Color color;
    color = actualObject->getColor();
    if ((color.components[0] == r1) && (color.components[1] == g1) && (color.components[2] == b1)) {
      color.components[0] = r2;
      color.components[1] = g2;
      color.components[2] = b2;
      actualObject->setColor(color);
      cout << "found first cube" << std::endl;
    } else if ((color.components[0] == r2) && (color.components[1] == g2) && (color.components[2] == b2)) {
      color.components[0] = r1;
      color.components[1] = g1;
      color.components[2] = b1;
      actualObject->setColor(color);
      cout << "found second cube" << std::endl;
    }
  }
  
  // Находим кубы в массиве объектов среды (который служит для определения достижения целей) и меняем их в нем местами
  /*int firstIndexToSwap = 0;
  int secondIndexToSwap = 0;
  for (int i=0; i<objectsArray.size(); i++) {
    TEnkiObject someEnkiObject = objectsArray[i];
    if ((someEnkiObject.color[0]/255.0 == r1) && (someEnkiObject.color[1]/255.0 == g1) && (someEnkiObject.color[2]/255.0 == b1)) {
      firstIndexToSwap = i;
    } else if ((someEnkiObject.color[0]/255.0 == r2) && (someEnkiObject.color[1]/255.0 == g2) && (someEnkiObject.color[2]/255.0 == b2)) {
      secondIndexToSwap = i;
    }
  }
  
  TEnkiObject storedObject = objectsArray.at(firstIndexToSwap);
  objectsArray.at(firstIndexToSwap) = objectsArray.at(secondIndexToSwap);
  objectsArray.at(secondIndexToSwap) = storedObject;*/
  
}
Exemplo n.º 4
0
int main(int argc, char *argv[])
{
	Q_INIT_RESOURCE(asebaqtabout);
	QApplication app(argc, argv);
	QCoreApplication::setOrganizationName(ASEBA_ORGANIZATION_NAME);
	QCoreApplication::setOrganizationDomain(ASEBA_ORGANIZATION_DOMAIN);
	app.setApplicationName("Playground");
	
	QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
	QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
	
	// Translation support
	QTranslator qtTranslator;
	qtTranslator.load("qt_" + QLocale::system().name());
	app.installTranslator(&qtTranslator);
	
	QTranslator translator;
	translator.load(QString(":/asebaplayground_") + QLocale::system().name());
	app.installTranslator(&translator);
	
	QTranslator aboutTranslator;
	aboutTranslator.load(QString(":/qtabout_") + QLocale::system().name());
	app.installTranslator(&aboutTranslator);
	
	// create document
	QDomDocument domDocument("aseba-playground");
	QString sceneFileName;
	
	// Get cmd line arguments
	bool ask = true;
	if (argc > 1)
	{
		sceneFileName = argv[1];
		ask = false;
	}
	
	// Try to load xml config file
	do
	{
		if (ask)
		{
			QString lastFileName = QSettings("EPFL-LSRO-Mobots", "Aseba Playground").value("last file").toString();
			sceneFileName = QFileDialog::getOpenFileName(0, app.tr("Open Scenario"), lastFileName, app.tr("playground scenario (*.playground)"));
		}
		ask = true;
		
		if (sceneFileName.isEmpty())
		{
			std::cerr << "You must specify a valid setup scenario on the command line or choose one in the file dialog." << std::endl;
			exit(1);
		}
		
		QFile file(sceneFileName);
		if (file.open(QIODevice::ReadOnly))
		{
			QString errorStr;
			int errorLine, errorColumn;
			if (!domDocument.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
			{
				QMessageBox::information(0, "Aseba Playground",
										app.tr("Parse error at file %1, line %2, column %3:\n%4")
										.arg(sceneFileName)
										.arg(errorLine)
										.arg(errorColumn)
										.arg(errorStr));
			}
			else
			{
				QSettings("EPFL-LSRO-Mobots", "Aseba Playground").setValue("last file", sceneFileName);
				break;
			}
		}
	}
	while (true);
	
	// Scan for colors
	typedef QMap<QString, Enki::Color> ColorsMap;
	ColorsMap colorsMap;
	QDomElement colorE = domDocument.documentElement().firstChildElement("color");
	while (!colorE.isNull())
	{
		colorsMap[colorE.attribute("name")] = Enki::Color(
			colorE.attribute("r").toDouble(),
			colorE.attribute("g").toDouble(),
			colorE.attribute("b").toDouble()
		);
		
		colorE = colorE.nextSiblingElement ("color");
	}
	
	// Scan for areas
	typedef QMap<QString, Enki::Polygon> AreasMap;
	AreasMap areasMap;
	QDomElement areaE = domDocument.documentElement().firstChildElement("area");
	while (!areaE.isNull())
	{
		Enki::Polygon p;
		QDomElement pointE = areaE.firstChildElement("point");
		while (!pointE.isNull())
		{
			p.push_back(Enki::Point(
				pointE.attribute("x").toDouble(),
				pointE.attribute("y").toDouble()
			));
			pointE = pointE.nextSiblingElement ("point");
		}
		areasMap[areaE.attribute("name")] = p;
		areaE = areaE.nextSiblingElement ("area");
	}
	
	// Create the world
	QDomElement worldE = domDocument.documentElement().firstChildElement("world");
	Enki::Color worldColor(Enki::Color::gray);
	if (!colorsMap.contains(worldE.attribute("color")))
		std::cerr << "Warning, world walls color " << worldE.attribute("color").toStdString() << " undefined\n";
	else
		worldColor = colorsMap[worldE.attribute("color")];
	Enki::World::GroundTexture groundTexture;
	if (worldE.hasAttribute("groundTexture"))
	{
		const QString groundTextureFileName(QFileInfo(sceneFileName).absolutePath() + QDir::separator() + worldE.attribute("groundTexture"));
		QImage image(groundTextureFileName);
		if (!image.isNull())
		{
			// flip vertically as y-coordinate is inverted in an image
			image = image.mirrored();
			// convert to a specific format and copy the underlying data to Enki
			image = image.convertToFormat(QImage::Format_ARGB32);
			groundTexture.width = image.width();
			groundTexture.height = image.height();
			const uint32_t* imageData(reinterpret_cast<const uint32_t*>(image.constBits()));
			std::copy(imageData, imageData+image.width()*image.height(), std::back_inserter(groundTexture.data));
			// Note: this works in little endian, in big endian data should be swapped
		}
		else
		{
			qDebug() << "Could not load ground texture file named" << groundTextureFileName;
		}
	}
	Enki::World world(
		worldE.attribute("w").toDouble(),
		worldE.attribute("h").toDouble(),
		worldColor,
		groundTexture
	);
	
	// Create viewer
	Enki::PlaygroundViewer viewer(&world, worldE.attribute("energyScoringSystemEnabled", "false").toLower() == "true");
	if (Enki::simulatorEnvironment)
		qDebug() << "A simulator environment already exists, replacing";
	Enki::simulatorEnvironment.reset(new Enki::PlaygroundSimulatorEnvironment(sceneFileName, viewer));
	
	// Zeroconf support to advertise targets
#ifdef ZEROCONF_SUPPORT
	Aseba::QtZeroconf zeroconf;
#endif // ZEROCONF_SUPPORT
	
	// Scan for camera
	QDomElement cameraE = domDocument.documentElement().firstChildElement("camera");
	if (!cameraE.isNull())
	{
		const double largestDim(qMax(world.h, world.w));
		viewer.setCamera(
			QPointF(
				cameraE.attribute("x", QString::number(world.w / 2)).toDouble(),
				cameraE.attribute("y", QString::number(0)).toDouble()
			),
			cameraE.attribute("altitude", QString::number(0.85 * largestDim)).toDouble(),
			cameraE.attribute("yaw", QString::number(-M_PI/2)).toDouble(),
			cameraE.attribute("pitch", QString::number((3*M_PI)/8)).toDouble()
		);
	}
	
	// Scan for walls
	QDomElement wallE = domDocument.documentElement().firstChildElement("wall");
	while (!wallE.isNull())
	{
		Enki::PhysicalObject* wall = new Enki::PhysicalObject();
		if (!colorsMap.contains(wallE.attribute("color")))
			std::cerr << "Warning, color " << wallE.attribute("color").toStdString() << " undefined\n";
		else
			wall->setColor(colorsMap[wallE.attribute("color")]);
		wall->pos.x = wallE.attribute("x").toDouble();
		wall->pos.y = wallE.attribute("y").toDouble();
		wall->setRectangular(
			wallE.attribute("l1").toDouble(),
			wallE.attribute("l2").toDouble(),
			wallE.attribute("h").toDouble(),
			!wallE.attribute("mass").isNull() ? wallE.attribute("mass").toDouble() : -1 // normally -1 because immobile
		);
		if (! wallE.attribute("angle").isNull())
			wall->angle = wallE.attribute("angle").toDouble(); // radians
		world.addObject(wall);
		
		wallE  = wallE.nextSiblingElement ("wall");
	}
	
	// Scan for cylinders
	QDomElement cylinderE = domDocument.documentElement().firstChildElement("cylinder");
	while (!cylinderE.isNull())
	{
		Enki::PhysicalObject* cylinder = new Enki::PhysicalObject();
		if (!colorsMap.contains(cylinderE.attribute("color")))
			std::cerr << "Warning, color " << cylinderE.attribute("color").toStdString() << " undefined\n";
		else
			cylinder->setColor(colorsMap[cylinderE.attribute("color")]);
		cylinder->pos.x = cylinderE.attribute("x").toDouble();
		cylinder->pos.y = cylinderE.attribute("y").toDouble();
		cylinder->setCylindric(
			cylinderE.attribute("r").toDouble(), 
			cylinderE.attribute("h").toDouble(),
			!cylinderE.attribute("mass").isNull() ? cylinderE.attribute("mass").toDouble() : -1 // normally -1 because immobile
		);
		world.addObject(cylinder);
		
		cylinderE = cylinderE.nextSiblingElement("cylinder");
	}
	
	// Scan for feeders
	QDomElement feederE = domDocument.documentElement().firstChildElement("feeder");
	while (!feederE.isNull())
	{
		Enki::EPuckFeeder* feeder = new Enki::EPuckFeeder;
		feeder->pos.x = feederE.attribute("x").toDouble();
		feeder->pos.y = feederE.attribute("y").toDouble();
		world.addObject(feeder);
	
		feederE = feederE.nextSiblingElement ("feeder");
	}
	// TODO: if needed, custom color to feeder
	
	// Scan for doors
	typedef QMap<QString, Enki::SlidingDoor*> DoorsMap;
	DoorsMap doorsMap;
	QDomElement doorE = domDocument.documentElement().firstChildElement("door");
	while (!doorE.isNull())
	{
		Enki::SlidingDoor *door = new Enki::SlidingDoor(
			Enki::Point(
				doorE.attribute("closedX").toDouble(),
				doorE.attribute("closedY").toDouble()
			),
			Enki::Point(
				doorE.attribute("openedX").toDouble(),
				doorE.attribute("openedY").toDouble()
			),
			Enki::Point(
				doorE.attribute("l1").toDouble(),
				doorE.attribute("l2").toDouble()
			),
			doorE.attribute("h").toDouble(),
			doorE.attribute("moveDuration").toDouble()
		);
		if (!colorsMap.contains(doorE.attribute("color")))
			std::cerr << "Warning, door color " << doorE.attribute("color").toStdString() << " undefined\n";
		else
			door->setColor(colorsMap[doorE.attribute("color")]);
		doorsMap[doorE.attribute("name")] = door;
		world.addObject(door);
		
		doorE = doorE.nextSiblingElement ("door");
	}
	
	// Scan for activation, and link them with areas and doors
	QDomElement activationE = domDocument.documentElement().firstChildElement("activation");
	while (!activationE.isNull())
	{
		if (areasMap.find(activationE.attribute("area")) == areasMap.end())
		{
			std::cerr << "Warning, area " << activationE.attribute("area").toStdString() << " undefined\n";
			activationE = activationE.nextSiblingElement ("activation");
			continue;
		}
		
		if (doorsMap.find(activationE.attribute("door")) == doorsMap.end())
		{
			std::cerr << "Warning, door " << activationE.attribute("door").toStdString() << " undefined\n";
			activationE = activationE.nextSiblingElement ("activation");
			continue;
		}
		
		const Enki::Polygon& area = *areasMap.find(activationE.attribute("area"));
		Enki::Door* door = *doorsMap.find(activationE.attribute("door"));
		
		Enki::DoorButton* activation = new Enki::DoorButton(
			Enki::Point(
				activationE.attribute("x").toDouble(),
				activationE.attribute("y").toDouble()
			),
			Enki::Point(
				activationE.attribute("l1").toDouble(),
				activationE.attribute("l2").toDouble()
			),
			area,
			door
		);
		
		world.addObject(activation);
		
		activationE = activationE.nextSiblingElement ("activation");
	}
	
	// load all robots in one loop
	std::map<std::string, RobotType> robotTypes {
		{ "thymio2", { "Thymio II", createRobotSingleVMNode<Enki::DashelAsebaThymio2> } },
		{ "e-puck", { "E-Puck", createRobotSingleVMNode<Enki::DashelAsebaFeedableEPuck> } },
	};
	QDomElement robotE = domDocument.documentElement().firstChildElement("robot");
	unsigned asebaServerCount(0);
	while (!robotE.isNull())
	{
		const auto type(robotE.attribute("type", "thymio2"));
		auto typeIt(robotTypes.find(type.toStdString()));
		if (typeIt != robotTypes.end())
		{
			// retrieve informations
			const auto& cppTypeName(typeIt->second.prettyName);
			const auto qTypeName(QString::fromStdString(cppTypeName));
			auto& countOfThisType(typeIt->second.number);
			const auto qRobotNameRaw(robotE.attribute("name", QString("%1 %2").arg(qTypeName).arg(countOfThisType)));
			const auto qRobotNameFull(QObject::tr("%2 on %3").arg(qRobotNameRaw).arg(QHostInfo::localHostName()));
			const auto cppRobotName(qRobotNameFull.toStdString());
			const unsigned port(robotE.attribute("port", QString("%1").arg(ASEBA_DEFAULT_PORT+asebaServerCount)).toUInt());
			const int16_t nodeId(robotE.attribute("nodeId", "1").toInt());
			
			// create
			const auto& creator(typeIt->second.factory);
#ifdef ZEROCONF_SUPPORT
			auto robot(creator(zeroconf, port, cppRobotName, cppTypeName, nodeId));
#else // ZEROCONF_SUPPORT
			auto robot(creator(port, cppRobotName, cppTypeName, nodeId));
#endif // ZEROCONF_SUPPORT
			asebaServerCount++;
			countOfThisType++;
			
			// setup in the world
			robot->pos.x = robotE.attribute("x").toDouble();
			robot->pos.y = robotE.attribute("y").toDouble();
			robot->angle = robotE.attribute("angle").toDouble();
			world.addObject(robot);
			
			// log
			viewer.log(app.tr("New robot %0 of type %1 on port %2").arg(qRobotNameRaw).arg(qTypeName).arg(port), Qt::white);
		}
		else
			viewer.log("Error, unknown robot type " + type, Qt::red);
		
		robotE = robotE.nextSiblingElement ("robot");
	}
	
	// Scan for external processes
	QList<QProcess*> processes;
	QDomElement procssE(domDocument.documentElement().firstChildElement("process"));
	while (!procssE.isNull())
	{
		QString command(procssE.attribute("command"));
		// create process
		processes.push_back(new QProcess());
		processes.back()->setProcessChannelMode(QProcess::MergedChannels);
		// make sure it is killed when we close the window
		QObject::connect(processes.back(), SIGNAL(started()), &viewer, SLOT(processStarted()));
		QObject::connect(processes.back(), SIGNAL(error(QProcess::ProcessError)), &viewer, SLOT(processError(QProcess::ProcessError)));
		QObject::connect(processes.back(), SIGNAL(readyReadStandardOutput()), &viewer, SLOT(processReadyRead()));
		QObject::connect(processes.back(), SIGNAL(finished(int, QProcess::ExitStatus)), &viewer, SLOT(processFinished(int, QProcess::ExitStatus)));
		// check whether it is a relative command
		bool isRelative(false);
		if (!command.isEmpty() && command[0] == ':')
		{
			isRelative = true;
			command = command.mid(1);
		}
		// process the command into its components
		QStringList args(command.split(" ", QString::SkipEmptyParts));
		if (args.size() == 0)
		{
			viewer.log(app.tr("Missing program in command"), Qt::red);
		}
		else
		{
			const QString program(QDir::toNativeSeparators(args[0]));
			args.pop_front();
			if (isRelative)
				processes.back()->start(QCoreApplication::applicationDirPath() + QDir::separator() + program, args, QIODevice::ReadOnly);
			else
				processes.back()->start(program, args, QIODevice::ReadOnly);
		}
		procssE = procssE.nextSiblingElement("process");
	}
	
	// Show and run
	viewer.setWindowTitle(app.tr("Aseba Playground - Simulate your robots!"));
	viewer.show();
	
	// If D-Bus is used, register the viewer object
	#ifdef HAVE_DBUS
	new Enki::EnkiWorldInterface(&viewer);
	QDBusConnection::sessionBus().registerObject("/world", &viewer);
	QDBusConnection::sessionBus().registerService("ch.epfl.mobots.AsebaPlayground");
	#endif // HAVE_DBUS
	
	// Run the application
	const int exitValue(app.exec());
	
	// Stop and delete ongoing processes
	foreach(QProcess*process,processes)
	{
		process->terminate();
		if (!process->waitForFinished(1000))
			process->kill();
		delete process;
	}
void TEnkiEnvironment::makeGnuplotScriptAndRunIt(std::string graphFilename, double xmin, double xmax, double ymin, double ymax) {
  // Чтобы замкнуть линии в гнуплоте
  std::set<Enki::PhysicalObject *>objects = world->objects;
  std::set<Enki::PhysicalObject *>::iterator someObject;
  for (someObject=objects.begin(); someObject!=objects.end(); ++someObject) {
    Enki::PhysicalObject * actualObject = *someObject;
	if (actualObject != ePuckBot) {
		ofstream objectsFile;
		stringstream buf;
		buf << "C:/enki-log-files/gnuplotObjects" << actualObject->objectNumber << ".txt";
		objectsFile.open(buf.str().c_str());
		objectsFile << actualObject->pos.x-cubeSize/2.0 << "\t" << actualObject->pos.y-cubeSize/2.0 << std::endl;
		objectsFile << actualObject->pos.x-cubeSize/2.0 << "\t" << actualObject->pos.y+cubeSize/2.0 << std::endl;
		objectsFile << actualObject->pos.x+cubeSize/2.0 << "\t" << actualObject->pos.y+cubeSize/2.0 << std::endl;
		objectsFile << actualObject->pos.x+cubeSize/2.0 << "\t" << actualObject->pos.y-cubeSize/2.0 << std::endl;
		objectsFile << actualObject->pos.x-cubeSize/2.0 << "\t" << actualObject->pos.y-cubeSize/2.0 << std::endl;
		objectsFile.close();
    }
  }

  ofstream gnuplotGraphFile;
  gnuplotGraphFile.open((graphFilename).c_str());
  gnuplotGraphFile << "set terminal pdf size 10cm," << 10*(ymax-ymin)/(xmax-xmin) << "cm font 'Times-New-Roman,5'" << std::endl;
  gnuplotGraphFile << "set output '" << graphFilename << ".pdf'" << std::endl;
  gnuplotGraphFile << "set xtics " << static_cast<int>(xmin) <<",50," << static_cast<int>(xmax) << std::endl;
  gnuplotGraphFile << "set ytics " << static_cast<int>(ymin) <<",50," << static_cast<int>(ymax) << std::endl;
  gnuplotGraphFile << "set mxtics 5\nset mytics 5" << std::endl;
  gnuplotGraphFile << "set grid xtics ytics mytics mxtics lt 1 lw 1 linecolor rgb \"gray\"" << std::endl;
  gnuplotGraphFile << "set palette defined ( 0 \"#660099\", 1 \"#0000CC\", 2 \"#3399FF\", 3 \"#00CC00\", 4 \"#FFFF33\", 5 \"#FF6600\", 6 \"#CC0000\" )" << std::endl;
  gnuplotGraphFile << "unset colorbox" << std::endl;
  std::string objectsColorsStrings[10];
  for (someObject=objects.begin(); someObject!=objects.end(); ++someObject) {
    Enki::PhysicalObject * actualObject = *someObject;
    if (actualObject->objectNumber >= 0) {
      const Enki::Color objectColor = actualObject->getColor();
	  std::string rColor = "00";
	  if (objectColor.components[0] == 1.0) {
		  rColor = "FF";
	  }
	  std::string gColor = "00";
	  if (objectColor.components[1] == 1.0) {
		  gColor = "FF";
	  }
	  std::string bColor = "00";
	  if (objectColor.components[2] == 1.0) {
		  bColor = "FF";
	  }
	  objectsColorsStrings[actualObject->objectNumber] = "#" + rColor + gColor + bColor;
      /*if ((objectColor.components[0] == 1.0) && (objectColor.components[1] == 0.0) && (objectColor.components[2] == 0.0)) {
        objectsColorsStrings[actualObject->objectNumber] = "red";
      } else if ((objectColor.components[0] == 1.0) && (objectColor.components[1] == 1.0) && (objectColor.components[2] == 0.0)) {
        objectsColorsStrings[actualObject->objectNumber] = "yellow";
      } else if ((objectColor.components[0] == 0.0) && (objectColor.components[1] == 1.0) && (objectColor.components[2] == 0.0)) {
        objectsColorsStrings[actualObject->objectNumber] = "green";
      } else if ((objectColor.components[0] == 0.0) && (objectColor.components[1] == 0.0) && (objectColor.components[2] == 1.0)) {
        objectsColorsStrings[actualObject->objectNumber] = "blue";
      }*/
    }
  }
  gnuplotGraphFile << "plot " << "[" << static_cast<int>(xmin) << ":" << static_cast<int>(xmax) << "] "
                              << "[" << static_cast<int>(ymin) << ":" << static_cast<int>(ymax) << "] "
                              << "'" << gnuplotOutputString << "'" << " u 1:2:(0.2):3 with circles palette notitle, ";
  for (int i = 0; i < 10; i++) {
	  if (objectsColorsStrings[i].length()) {
		if (i>=1) {
		  gnuplotGraphFile << ", ";
		}
		gnuplotGraphFile << "'C:/enki-log-files/gnuplotObjects" << i << ".txt' with filledcurves notitle linecolor rgb \"" << objectsColorsStrings[i].c_str() << "\"";
	  } else {
		  break;
	  }
  }
  gnuplotGraphFile << std::endl;
  /*<< "'C:/enki-log-files/gnuplotObjects1.txt' with filledcurves notitle linecolor rgb \"" << objectsColorsStrings[0] << "\", "
  << "'C:/enki-log-files/gnuplotObjects2.txt' with filledcurves notitle linecolor rgb \"" << objectsColorsStrings[1] << "\", "
  << "'C:/enki-log-files/gnuplotObjects3.txt' with filledcurves notitle linecolor rgb \"" << objectsColorsStrings[2] << "\", "
  << "'C:/enki-log-files/gnuplotObjects4.txt' with filledcurves notitle linecolor rgb \"" << objectsColorsStrings[3] << "\", " << std::endl;*/
  //gnuplotGraphFile << "__EOF" << std::endl;
  gnuplotGraphFile.close();
  //system(("chmod +x "+graphFilename+".sh").c_str());
  system(("gnuplot "+graphFilename).c_str());
}
void TEnkiEnvironment::loadEnvironment(std::string environmentFilename) {
    // Получаем параметры среды из файла
    std::ifstream environmentFile;
    environmentFile.open(environmentFilename.c_str());
    string tmp_str;
    environmentFile >> tmp_str; // Считываем размеры прямоугольной арены
    xSize = atof(tmp_str.c_str());
    environmentFile >> tmp_str;
    ySize = atof(tmp_str.c_str());
    environmentFile >> tmp_str;
    xBirthMin = atof(tmp_str.c_str());
    environmentFile >> tmp_str;
    xBirthMax = atof(tmp_str.c_str());
    environmentFile >> tmp_str;
    yBirthMin = atof(tmp_str.c_str());
    environmentFile >> tmp_str;
    yBirthMax = atof(tmp_str.c_str());
    environmentFile >> tmp_str; // Считываем количество объектов в среде (по умолчанию - кубы)
    objectsNumber = atoi(tmp_str.c_str());
    for (int i=0; i<objectsNumber; i++) { // Заполняем массив объектов, каждый из которых имеет позицию своего центра и цвет
      TEnkiObject someNewObject = TEnkiObject();
      environmentFile >> tmp_str;
      someNewObject.x = atof(tmp_str.c_str());
      environmentFile >> tmp_str;
      someNewObject.y = atof(tmp_str.c_str());
      environmentFile >> tmp_str;
      someNewObject.color[0] = atof(tmp_str.c_str());
      environmentFile >> tmp_str;
      someNewObject.color[1] = atof(tmp_str.c_str());
      environmentFile >> tmp_str;
      someNewObject.color[2] = atof(tmp_str.c_str());
      objectsArray.push_back(someNewObject);
    }
    environmentFile >> tmp_str;
    goalsNumber = atoi(tmp_str.c_str()); // Считываем количество целей
    for (int i=0; i<goalsNumber; i++) { // Заполняем массив целей, каждая из которых имеет длину последовательности, награду и саму последовательность посещения объектов
      TEnkiAim someNewAim = TEnkiAim();
      environmentFile >> tmp_str;
      someNewAim.aimComplexity = atoi(tmp_str.c_str());
      if (someNewAim.aimComplexity > someNewAim.MAX_AIM_COMPLEXITY) {
        cout << "Warning in TEnkiEnvironment: aim complexity can't be greater than the MAX_AIM_COMPLEXITY. Setting it to the MAX_AIM_COMPLEXITY by force now to avoid crash.";
        someNewAim.aimComplexity = someNewAim.MAX_AIM_COMPLEXITY;
      }
      environmentFile >> tmp_str;
      someNewAim.reward = atof(tmp_str.c_str());
      for (int j=0; j<someNewAim.aimComplexity; j++) {
        environmentFile >> tmp_str;
        someNewAim.actionsSequence[j] = atoi(tmp_str.c_str());
        if (someNewAim.actionsSequence[j] > objectsNumber) {
          cout << "Warning in TEnkiEnvironment: action number can't be greater than the number of objects. Setting it to the number of objects by force now to avoid crash.";
          someNewAim.actionsSequence[j] = objectsNumber;
        }
      }
      goalsArray.push_back(someNewAim);
    }
  
  //Переходим к постройке мира исходя из параметров, полученных из файла
    
  // Создаем саму арену
  world = new Enki::World(xSize, ySize, Enki::Color(0.1, 0.1, 0.1));
  
  // Создаем объекты
  Enki::Polygone p2;
  p2.push_back(Enki::Point(cubeSize/2.0,cubeSize/2.0));
  p2.push_back(Enki::Point(-cubeSize/2.0,cubeSize/2.0));
  p2.push_back(Enki::Point(-cubeSize/2.0,-cubeSize/2.0));
  p2.push_back(Enki::Point(cubeSize/2.0,-cubeSize/2.0));
  
  for (int i = 0; i < objectsNumber; i++)
  {
    Enki::PhysicalObject* o = new Enki::PhysicalObject;
    Enki::PhysicalObject::Hull hull(Enki::PhysicalObject::Part(p2, cubeSize));
    o->setCustomHull(hull, -100000); // Отрицательная масса - то же, что бесконечная, поэтому объекты сдвинуть с места будет невозможно
    o->setColor(Enki::Color(objectsArray.at(i).color[0]/255.0, objectsArray.at(i).color[1]/255.0, objectsArray.at(i).color[2]/255.0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ));
    o->collisionElasticity = 0; // Все тепло от столкновения поглощается
    o->pos = Enki::Point(objectsArray.at(i).x, objectsArray.at(i).y);
    o->objectNumber = i;
    world->addObject(o);
    //objectsInTheWorld.push_back(o);
  }
  
  // Создаем E-PUCK и размещаем его в среде
  ePuckBot = new Enki::EPuck();
  ePuckBot->pos = Enki::Point(4.0, 4.0);
  ePuckBot->angle = 0;
  ePuckBot->leftSpeed = 0;
  ePuckBot->rightSpeed = 0;
  ePuckBot->objectNumber = -1;
  ePuckBot->setColor(Enki::Color(1, 0, 0));
  world->addObject(ePuckBot);
}