StelObjectP ConstellationMgr::setSelectedStar(const QString& abbreviation)
{
	Constellation * c = findFromAbbreviation(abbreviation);
	if(c != NULL)
	{
		setSelectedConst(c);
		return c->getBrightestStarInConstellation();
	}
	return NULL;
}
/**
 * Calculates birate of the stream.
 *
 * @param bandwidth Bandwidth
 * @param codeRate Code rate
 * @param constellation Constellation
 * @param guardinterval Guard interval
 * @return Bitrate of the stream
 */
BitratePerPID PacketStream::calculateBitRate(const Bandwidth &bandwidth, const CodeRate &codeRate, const Constellation &constellation, const GuardInterval &guardinterval) {
    double maxBitRate = (423.0 / 544) * bandwidth.toValue() * codeRate.toValue();
    maxBitRate *= constellation.toValue() * guardinterval.toValue();
    BitratePerPID bitRatePerPID;
    bitRatePerPID.PID = PID;
    bitRatePerPID.bitrate = maxBitRate * ((double)_packetsInStream / _processedPackets) / 1000000;
    return bitRatePerPID;
}
// Draw constellations art textures
void ConstellationMgr::drawArt(StelRenderer* renderer, StelProjectorP projector) const
{
	renderer->setBlendMode(BlendMode_Add);

	vector < Constellation * >::const_iterator iter;
	SphericalRegionP region = projector->getViewportConvexPolygon();
	for (iter = asterisms.begin(); iter != asterisms.end(); ++iter)
	{
		Constellation* cons = *iter;

		if(NULL == cons->artTexture && !cons->artTexturePath.isEmpty())
		{
			cons->artTexture = renderer->createTexture(cons->artTexturePath);
		}
		if(NULL == cons->artVertices)
		{
			// Tesselate on the plane assuming a tangential projection for the image
			const int resolution = 5;
			cons->generateArtVertices(renderer, resolution);
		}

		cons->drawArtOptim(renderer, projector, *region);
	}
}
void ConstellationMgr::loadLinesAndArt(const QString &fileName, const QString &artfileName, const QString& cultureName)
{
	QFile in(fileName);
	if (!in.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		qWarning() << "Can't open constellation data file" << fileName  << "for culture" << cultureName;
		Q_ASSERT(0);
	}

	int totalRecords=0;
	QString record;
	QRegExp commentRx("^(\\s*#.*|\\s*)$");
	while (!in.atEnd())
	{
		record = QString::fromUtf8(in.readLine());
		if (!commentRx.exactMatch(record))
			totalRecords++;
	}
	in.seek(0);

	// delete existing data, if any
	vector < Constellation * >::iterator iter;
	for (iter = asterisms.begin(); iter != asterisms.end(); ++iter)
		delete(*iter);

	asterisms.clear();
	Constellation *cons = NULL;

	// read the file, adding a record per non-comment line
	int currentLineNumber = 0;	// line in file
	int readOk = 0;			// count of records processed OK
	while (!in.atEnd())
	{
		record = QString::fromUtf8(in.readLine());
		currentLineNumber++;
		if (commentRx.exactMatch(record))
			continue;

		cons = new Constellation;
		if(cons->read(record, hipStarMgr))
		{
			cons->artFader.setMaxValue(artIntensity);
			cons->setFlagArt(artDisplayed);
			cons->setFlagBoundaries(boundariesDisplayed);
			cons->setFlagLines(linesDisplayed);
			cons->setFlagLabels(namesDisplayed);
			asterisms.push_back(cons);
			++readOk;
		}
		else
		{
			qWarning() << "ERROR reading constellation rec at line " << currentLineNumber << "for culture" << cultureName;
			delete cons;
		}
	}
	in.close();
	qDebug() << "Loaded" << readOk << "/" << totalRecords << "constellation records successfully for culture" << cultureName;

	// Set current states
	setFlagArt(artDisplayed);
	setFlagLines(linesDisplayed);
	setFlagLabels(namesDisplayed);
	setFlagBoundaries(boundariesDisplayed);

	// It's possible to have no art - just constellations
	if (artfileName.isNull() || artfileName.isEmpty())
		return;
	QFile fic(artfileName);
	if (!fic.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		qWarning() << "Can't open constellation art file" << fileName  << "for culture" << cultureName;
		return;
	}

	totalRecords=0;
	while (!fic.atEnd())
	{
		record = QString::fromUtf8(fic.readLine());
		if (!commentRx.exactMatch(record))
			totalRecords++;
	}
	fic.seek(0);

	// Read the constellation art file with the following format :
	// ShortName texture_file x1 y1 hp1 x2 y2 hp2
	// Where :
	// shortname is the international short name (i.e "Lep" for Lepus)
	// texture_file is the graphic file of the art texture
	// x1 y1 are the x and y texture coordinates in pixels of the star of hipparcos number hp1
	// x2 y2 are the x and y texture coordinates in pixels of the star of hipparcos number hp2
	// The coordinate are taken with (0,0) at the top left corner of the image file
	QString shortname;
	QString texfile;
	unsigned int x1, y1, x2, y2, x3, y3, hp1, hp2, hp3;
	QString tmpstr;

	currentLineNumber = 0;	// line in file
	readOk = 0;		// count of records processed OK

	while (!fic.atEnd())
	{
		++currentLineNumber;
		record = QString::fromUtf8(fic.readLine());
		if (commentRx.exactMatch(record))
			continue;

		// prevent leaving zeros on numbers from being interpretted as octal numbers
		record.replace(" 0", " ");
		QTextStream rStr(&record);
		rStr >> shortname >> texfile >> x1 >> y1 >> hp1 >> x2 >> y2 >> hp2 >> x3 >> y3 >> hp3;
		if (rStr.status()!=QTextStream::Ok)
		{
			qWarning() << "ERROR parsing constellation art record at line" << currentLineNumber << "of art file for culture" << cultureName;
			continue;
		}

		// Draw loading bar
// 		lb.SetMessage(q_("Loading Constellation Art: %1/%2").arg(currentLineNumber).arg(totalRecords));
// 		lb.Draw((float)(currentLineNumber)/totalRecords);

		cons = NULL;
		cons = findFromAbbreviation(shortname);
		if (!cons)
		{
			qWarning() << "ERROR in constellation art file at line" << currentLineNumber << "for culture" << cultureName
					   << "constellation" << shortname << "unknown";
		}
		else
		{
			QString texturePath(texfile);
			try
			{
				texturePath = StelFileMgr::findFile("skycultures/"+cultureName+"/"+texfile);
			}
			catch (std::runtime_error& e)
			{
				// if the texture isn't found in the skycultures/[culture] directory,
				// try the central textures diectory.
				qWarning() << "WARNING, could not locate texture file " << texfile
					 << " in the skycultures/" << cultureName
					 << " directory...  looking in general textures/ directory...";
				try
				{
					texturePath = StelFileMgr::findFile(QString("textures/")+texfile);
				}
				catch(exception& e2)
				{
					qWarning() << "ERROR: could not find texture, " << texfile << ": " << e2.what();
				}
			}

			cons->artTexture = StelApp::getInstance().getTextureManager().createTextureThread(texturePath);

			int texSizeX, texSizeY;
			if (cons->artTexture==NULL || !cons->artTexture->getDimensions(texSizeX, texSizeY))
			{
				qWarning() << "Texture dimension not available";
			}

			StelCore* core = StelApp::getInstance().getCore();
			Vec3d s1 = hipStarMgr->searchHP(hp1)->getJ2000EquatorialPos(core);
			Vec3d s2 = hipStarMgr->searchHP(hp2)->getJ2000EquatorialPos(core);
			Vec3d s3 = hipStarMgr->searchHP(hp3)->getJ2000EquatorialPos(core);

			// To transform from texture coordinate to 2d coordinate we need to find X with XA = B
			// A formed of 4 points in texture coordinate, B formed with 4 points in 3d coordinate
			// We need 3 stars and the 4th point is deduced from the other to get an normal base
			// X = B inv(A)
			Vec3d s4 = s1 + ((s2 - s1) ^ (s3 - s1));
			Mat4d B(s1[0], s1[1], s1[2], 1, s2[0], s2[1], s2[2], 1, s3[0], s3[1], s3[2], 1, s4[0], s4[1], s4[2], 1);
			Mat4d A(x1, texSizeY - y1, 0.f, 1.f, x2, texSizeY - y2, 0.f, 1.f, x3, texSizeY - y3, 0.f, 1.f, x1, texSizeY - y1, texSizeX, 1.f);
			Mat4d X = B * A.inverse();

			// Tesselate on the plan assuming a tangential projection for the image
			static const int nbPoints=5;
			QVector<Vec2f> texCoords;
			texCoords.reserve(nbPoints*nbPoints*6);
			for (int j=0;j<nbPoints;++j)
			{
				for (int i=0;i<nbPoints;++i)
				{
					texCoords << Vec2f(((float)i)/nbPoints, ((float)j)/nbPoints);
					texCoords << Vec2f(((float)i+1.f)/nbPoints, ((float)j)/nbPoints);
					texCoords << Vec2f(((float)i)/nbPoints, ((float)j+1.f)/nbPoints);
					texCoords << Vec2f(((float)i+1.f)/nbPoints, ((float)j)/nbPoints);
					texCoords << Vec2f(((float)i+1.f)/nbPoints, ((float)j+1.f)/nbPoints);
					texCoords << Vec2f(((float)i)/nbPoints, ((float)j+1.f)/nbPoints);
				}
			}

			QVector<Vec3d> contour;
			contour.reserve(texCoords.size());
			foreach (const Vec2f& v, texCoords)
				contour << X * Vec3d(v[0]*texSizeX, v[1]*texSizeY, 0.);

			cons->artPolygon.vertex=contour;
			cons->artPolygon.texCoords=texCoords;
			cons->artPolygon.primitiveType=StelVertexArray::Triangles;

			Vec3d tmp(X * Vec3d(0.5*texSizeX, 0.5*texSizeY, 0.));
			tmp.normalize();
			Vec3d tmp2(X * Vec3d(0., 0., 0.));
			tmp2.normalize();
			cons->boundingCap.n=tmp;
			cons->boundingCap.d=tmp*tmp2;
			++readOk;
		}
	}

	qDebug() << "Loaded" << readOk << "/" << totalRecords << "constellation art records successfully for culture" << cultureName;
	fic.close();
}
// Load line and art data from files
int ConstellationMgr::loadLinesAndArt(const string &skyCultureDir)
{

	string fileName = skyCultureDir + "/constellationship.fab";
	string artfileName = skyCultureDir + "/constellationsart.fab";
	string boundaryfileName = skyCultureDir + "/boundaries.dat";

	std::ifstream inf(fileName.c_str());

	if (!inf.is_open()) {
		Log.write("Constellation_Mgr::loadLinesAndArt can't open constellation data file "+ fileName, cLog::eLOG_TYPE_ERROR);
		return -1;
	}

	// delete existing data, if any
	//~ if( SharedData::Instance()->DB() ) {
		//~ dbCursor<ObjectRecord> cursor(dbCursorForUpdate);
		//~ dbQuery q;
		//~ q = "type=",ObjectRecord::OBJECT_CONSTELLATION;
		//~ if( cursor.select(q) )
			//~ cursor.removeAllSelected();
		//~ SharedData::Instance()->DB()->commit();
	//~ }

	vector < Constellation * >::iterator iter;
	for (iter = asterisms.begin(); iter != asterisms.end(); ++iter) {
		delete(*iter);
	}
	asterisms.clear();
	selected.clear();

	Constellation *cons = NULL;

	string record;
	int line=0;
	while (!inf.eof() && std::getline(inf, record)) {
		line++;
		if (record.size()!=0 && record[0]=='#')
			continue;
		cons = new Constellation;

		if (cons->read(record, hipStarMgr)) {
			asterisms.push_back(cons);
		} else {
			//cerr << "ERROR on line " << line << " of " << fileName.c_str() << endl;
			Log.write("ConstellationMgr::loadLinesAndArt on line " + Utility::intToString(line) + " of " + fileName, cLog::eLOG_TYPE_ERROR);
			delete cons;
		}
	}
	inf.close();

	// Set current states
	setFlagArt(flagArt);
	setFlagLines(flagLines);
	setFlagNames(flagNames);
	setFlagBoundaries(flagBoundaries);


	FILE *fic = fopen(artfileName.c_str(), "r");
	if (!fic) {
//		cerr << "Can't open " << artfileName.c_str() << endl;
		Log.write("ConstellationMgr::loadLinesAndArt Can't open " + artfileName, cLog::eLOG_TYPE_ERROR);
		return 0; // no art, but still loaded constellation data
	}
	fclose(fic);

	// Read the constellation art file with the following format :
	// ShortName texture_file x1 y1 hp1 x2 y2 hp2
	// Where :
	// shortname is the international short name (i.e "Lep" for Lepus)
	// texture_file is the graphic file of the art texture
	// x1 y1 are the x and y texture coordinates in pixels of the star of hipparcos number hp1
	// x2 y2 are the x and y texture coordinates in pixels of the star of hipparcos number hp2
	// The coordinate are taken with (0,0) at the top left corner of the image file
	string shortname;
	string texfile;
	unsigned int x1, y1, x2, y2, x3, y3, hp1, hp2, hp3;
	float fx1, fy1, fx2, fy2, fx3, fy3; // read floats to allow proportional image points to allow image sizes to vary as needed
	int texW, texH; // art texture dimensions

	// Read in constellation art information
	// Note: Stellarium 0.10.3 allows more than 3 alignment points, here only first 3 are used.

	ifstream artFile(artfileName.c_str());
	if (!artFile.is_open()) {
		//cerr << "Can't open file" << artFile << endl;
		Log.write("ConstellationMgr::loadLinesAndArt Can't open " + artfileName, cLog::eLOG_TYPE_ERROR);
		return 0;
	}

	while (!artFile.eof() && std::getline(artFile, record)) {

		if ( record != "") {
			stringstream in(record);
			in >> shortname >> texfile;

			if(in.fail()) {
				//cerr << "Error parsing constellation art record:\n" << record << endl;
				Log.write("ConstellationMgr::loadLinesAndArt Error parsing constellation art record " + record, cLog::eLOG_TYPE_ERROR);
				continue;
			}

			// TODO add better error checking
			if(shortname!="" && shortname[0]!='#') {
				in >> fx1 >> fy1 >> hp1;
				in >> fx2 >> fy2 >> hp2;
				in >> fx3 >> fy3 >> hp3;
			} else {
				continue;