// Draw the names of all the constellations
void ConstellationMgr::drawNames(StelRenderer* renderer, StelProjectorP projector, QFont& font) const
{
	renderer->setBlendMode(BlendMode_Alpha);
	vector < Constellation * >::const_iterator iter;
	for (iter = asterisms.begin(); iter != asterisms.end(); iter++)
	{
		// Check if in the field of view
		if (projector->projectCheck((*iter)->XYZname, (*iter)->XYname))
		{
			(*iter)->drawName(renderer, font);\
		}
	}
}
예제 #2
0
void Exoplanets::drawPointer(StelCore* core, StelRenderer* renderer, StelProjectorP projector)
{
	const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Exoplanet");
	if (!newSelected.empty())
	{
		const StelObjectP obj = newSelected[0];
		Vec3d pos=obj->getJ2000EquatorialPos(core);

		Vec3d screenpos;
		// Compute 2D pos and return if outside screen
		if (!projector->project(pos, screenpos))
			return;

		const Vec3f& c(obj->getInfoColor());
		renderer->setGlobalColor(c[0],c[1],c[2]);
		texPointer->bind();
		renderer->setBlendMode(BlendMode_Alpha);
		renderer->drawTexturedRect(screenpos[0] - 13.0f, screenpos[1] - 13.0f, 26.0f, 
		                           26.0f, StelApp::getInstance().getTotalRunTime() * 40.0f);
	}
}
예제 #3
0
void Constellation::drawBoundaryOptim(StelRenderer* renderer, StelProjectorP projector) const
{
	if (boundaryFader.getInterstate() < 0.001)
	{
		return;
	}

	renderer->setBlendMode(BlendMode_Alpha);
	renderer->setGlobalColor(boundaryColor[0], boundaryColor[1], 
	                         boundaryColor[2], boundaryFader.getInterstate());

	int size = singleSelected ? isolatedBoundarySegments.size() 
	                          : sharedBoundarySegments.size();

	const SphericalCap& viewportHalfspace = projector->getBoundingCap();

	for (int i = 0; i < size; i++)
	{
		std::vector<Vec3f>* points = singleSelected ? isolatedBoundarySegments[i] 
		                                            : sharedBoundarySegments[i];

		for (int j = 0; j < static_cast<int>(points->size()) - 1; j++)
		{
			const Vec3f pt1 = points->at(j) ;
			const Vec3f pt2 = points->at(j +1);
			if (pt1 * pt2 > 0.9999999f)
			{
				continue;
			}
			const Vec3d ptd1(pt1[0], pt1[1], pt1[2]);
			const Vec3d ptd2(pt2[0], pt2[1], pt2[2]);
			StelCircleArcRenderer(renderer, projector)
				.drawGreatCircleArc(ptd1, ptd2, &viewportHalfspace);
		}
	}
}
// 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);
	}
}
예제 #5
0
bool AngleMeasure::handleMouseMoves(int x, int y, Qt::MouseButtons)
{
	if (dragging)
	{
		const StelProjectorP prj = StelApp::getInstance().getCore()->getProjection(StelCore::FrameEquinoxEqu);
		prj->unProject(x,y,endPoint);
		{ // Nick Fedoseev patch: improve click match
		   Vec3d win;
		   prj->project(endPoint,win);
		   float dx = x - win.v[0];
		   float dy = y - win.v[1];
		   prj->unProject(x+dx, y+dy, endPoint);
		}
		const StelProjectorP prjHor = StelApp::getInstance().getCore()->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
		prjHor->unProject(x,y,endPointHor);
		calculateEnds();
		lineVisible = true;
		return true;
	}
	else
		return false;
}
예제 #6
0
void AngleMeasure::handleMouseClicks(class QMouseEvent* event)
{
	if (!flagShowAngleMeasure)
	{
		event->setAccepted(false);
		return;
	}

	if (event->type()==QEvent::MouseButtonPress && event->button()==Qt::LeftButton)
	{
		const StelProjectorP prj = StelApp::getInstance().getCore()->getProjection(StelCore::FrameEquinoxEqu);
		prj->unProject(event->x(),event->y(),startPoint);
		{ // Nick Fedoseev patch: improve click match
			Vec3d win;
			prj->project(startPoint,win);
			float dx = event->x() - win.v[0];
			float dy = event->y() - win.v[1];
			prj->unProject(event->x()+dx, event->y()+dy, startPoint);
		}
		const StelProjectorP prjHor = StelApp::getInstance().getCore()->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
		prjHor->unProject(event->x(),event->y(),startPointHor);


		// first click reset the line... only draw it after we've dragged a little.
		if (!dragging)
		{
			lineVisible = false;
			endPoint = startPoint;
			endPointHor=startPointHor;
		}
		else
			lineVisible = true;

		dragging = true;
		calculateEnds();
		event->setAccepted(true);
		return;
	}
	else if (event->type()==QEvent::MouseButtonRelease && event->button()==Qt::LeftButton)
	{
		dragging = false;
		calculateEnds();
		event->setAccepted(true);
		return;
	}
	else if (event->type()==QEvent::MouseButtonPress && event->button()==Qt::RightButton)
	{
		const StelProjectorP prj = StelApp::getInstance().getCore()->getProjection(StelCore::FrameEquinoxEqu);
		prj->unProject(event->x(),event->y(),endPoint);
		{ // Nick Fedoseev patch: improve click match
			Vec3d win;
			prj->project(endPoint,win);
			float dx = event->x() - win.v[0];
			float dy = event->y() - win.v[1];
			prj->unProject(event->x()+dx, event->y()+dy, endPoint);
		}
		const StelProjectorP prjHor = StelApp::getInstance().getCore()->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
		prjHor->unProject(event->x(),event->y(),endPointHor);
		calculateEnds();
		event->setAccepted(true);
		return;
	}
	event->setAccepted(false);
}
예제 #7
0
void AngleMeasure::drawOne(StelCore *core, const StelCore::FrameType frameType, const StelCore::RefractionMode refractionMode, const Vec3f txtColor, const Vec3f lineColor)
{
	const StelProjectorP prj = core->getProjection(frameType, refractionMode);
	StelPainter painter(prj);
	painter.setFont(font);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	if (lineVisible.getInterstate() > 0.000001f)
	{
		Vec3d xy;
		QString displayedText;
		if (frameType==StelCore::FrameEquinoxEqu)
		{
			if (prj->project(perp1EndPoint,xy))
			{
				painter.setColor(txtColor[0], txtColor[1], txtColor[2], lineVisible.getInterstate());
				if (flagShowPA)
					displayedText = QString("%1 (%2%3)").arg(calculateAngle(), messagePA, calculatePositionAngle(startPoint, endPoint));
				else
					displayedText = calculateAngle();
				painter.drawText(xy[0], xy[1], displayedText, 0, 15, 15);
			}
		}
		else
		{
			if (prj->project(perp1EndPointHor,xy))
			{
				painter.setColor(txtColor[0], txtColor[1], txtColor[2], lineVisible.getInterstate());
				if (flagShowHorizontalPA)
					displayedText = QString("%1 (%2%3)").arg(calculateAngle(true), messagePA, calculatePositionAngle(startPointHor, endPointHor));
				else
					displayedText = calculateAngle(true);
				painter.drawText(xy[0], xy[1], displayedText, 0, 15, -5);
			}
		}

		glDisable(GL_TEXTURE_2D);
		// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH. But it looks much better.
		#ifdef GL_LINE_SMOOTH
		if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
			glEnable(GL_LINE_SMOOTH);
		#endif

		// main line is a great circle
		painter.setColor(lineColor[0], lineColor[1], lineColor[2], lineVisible.getInterstate());
		if (frameType==StelCore::FrameEquinoxEqu)
		{
			painter.drawGreatCircleArc(startPoint, endPoint, NULL);

			// End lines
			painter.drawGreatCircleArc(perp1StartPoint, perp1EndPoint, NULL);
			painter.drawGreatCircleArc(perp2StartPoint, perp2EndPoint, NULL);
		}
		else
		{
			painter.drawGreatCircleArc(startPointHor, endPointHor, NULL);

			// End lines
			painter.drawGreatCircleArc(perp1StartPointHor, perp1EndPointHor, NULL);
			painter.drawGreatCircleArc(perp2StartPointHor, perp2EndPointHor, NULL);
		}
		#ifdef GL_LINE_SMOOTH
		if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
			glDisable(GL_LINE_SMOOTH);
		#endif
	}
	if (messageFader.getInterstate() > 0.000001f)
	{
		painter.setColor(txtColor[0], txtColor[1], txtColor[2], messageFader.getInterstate());
		int x = 83;
		int y = 120;
		int ls = painter.getFontMetrics().lineSpacing();
		painter.drawText(x, y, messageEnabled);
		y -= ls;
		painter.drawText(x, y, messageLeftButton);
		y -= ls;
		painter.drawText(x, y, messageRightButton);
	}
	glDisable(GL_BLEND);
}
예제 #8
0
bool SkyLabel::draw(StelCore* core, StelRenderer* renderer, StelProjectorP projector)
{
	if(labelFader.getInterstate() <= 0.0)
		return false;

	Vec3d objectPos = labelObject->getJ2000EquatorialPos(core);
	Vec3d labelXY;

	projector->project(objectPos, labelXY);
	renderer->setFont(labelFont);

	double xOffset(0.);
	double yOffset(0.);
	char hJustify = 'c';
	char vJustify = 'c';

	if (labelSide.toUpper().contains("N"))
	{
		yOffset = 1.0;
		vJustify = 'b'; // bottom justify text
	}
	else if (labelSide.toUpper().contains("S"))
	{
		yOffset = -1.0;
		vJustify = 't'; // top justufy text
	}

	if (labelSide.toUpper().contains("E"))
	{
		xOffset = 1.0;
		hJustify = 'l'; // right justify text
	}
	else if (labelSide.toUpper().contains("W"))
	{
		xOffset = -1.0;
		hJustify = 'r'; // left justify text
	}

	if (labelDistance >= 0.0)
	{
		xOffset *= labelDistance;
		yOffset *= labelDistance;
	}
	else
	{
		float shift = 4.0f + labelObject->getAngularSize(core) * M_PI / 180.0f *
		              projector->getPixelPerRadAtCenter() / 1.8f;
		// use the object size
		xOffset *= shift;
		yOffset *= shift;
	}

	QFontMetrics fontMetrics(labelFont);
	const float jxOffset = hJustify == 'r' ? fontMetrics.width(labelText) :
	                       hJustify == 'c' ? fontMetrics.width(labelText) * 0.5 :
	                                         0.0;
	const float jyOffset = vJustify == 't' ? fontMetrics.height() :
	                       vJustify == 'c' ? fontMetrics.height() * 0.5 :
	                                         0.0;

	renderer->setGlobalColor(labelColor[0], labelColor[1], 
	                         labelColor[2], labelFader.getInterstate());
	renderer->drawText(TextParams(labelXY[0] + xOffset - jxOffset, 
	                              labelXY[1] + yOffset - jyOffset, 
	                              labelText).useGravity());

	if (labelStyle == SkyLabel::Line)
	{
		renderer->setBlendMode(BlendMode_Alpha);

		// screen coordinates of object
		Vec3d objXY;
		projector->project(objectPos, objXY);

		double lineEndX = labelXY[0]+xOffset;
		double lineEndY = labelXY[1]+yOffset;



		if (vJustify == 'b')
			lineEndY -= 5;
		else if (vJustify == 't')
			lineEndY += 5;
				
		if (hJustify == 'l')
			lineEndX -= 5;
		else if (hJustify == 'r')
			lineEndX += 5;
				
		renderer->setGlobalColor(labelColor[0], labelColor[1], labelColor[2],
		                         labelFader.getInterstate());

		renderer->drawLine(lineEndX,lineEndY,objXY[0], objXY[1]);
	}

	return true;
}
예제 #9
0
void PointerCoordinates::draw(StelCore *core)
{
	if (!isEnabled())
		return;

	const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000, StelCore::RefractionAuto);
	StelPainter sPainter(prj);
	sPainter.setColor(textColor[0], textColor[1], textColor[2], 1.f);
	font.setPixelSize(getFontSize());
	sPainter.setFont(font);

	QPoint p = StelMainView::getInstance().getMousePos(); // get screen coordinates of mouse cursor
	Vec3d mousePosition;
	float wh = prj->getViewportWidth()/2.; // get half of width of the screen
	float hh = prj->getViewportHeight()/2.; // get half of height of the screen
	float mx = p.x()-wh; // point 0 in center of the screen, axis X directed to right
	float my = p.y()-hh; // point 0 in center of the screen, axis Y directed to bottom
	// calculate position of mouse cursor via position of center of the screen (and invert axis Y)
	// If coordinates are invalid, don't draw them.
	bool coordsValid=false;
	coordsValid = prj->unProject(prj->getViewportPosX()+wh+mx, prj->getViewportPosY()+hh+1-my, mousePosition);
	{ // Nick Fedoseev patch
		Vec3d win;
		prj->project(mousePosition,win);
		float dx = prj->getViewportPosX()+wh+mx - win.v[0];
		float dy = prj->getViewportPosY()+hh+1-my - win.v[1];
		coordsValid = prj->unProject(prj->getViewportPosX()+wh+mx+dx, prj->getViewportPosY()+hh+1-my+dy, mousePosition);
	}
	if (!coordsValid)
		return;

	bool withDecimalDegree = StelApp::getInstance().getFlagShowDecimalDegrees();
	bool useSouthAzimuth = StelApp::getInstance().getFlagSouthAzimuthUsage();

	QString coordsSystem, cxt, cyt;
	double cx, cy;
	switch (getCurrentCoordinateSystem())
	{
		case RaDecJ2000:
		{
			StelUtils::rectToSphe(&cx,&cy,mousePosition); // Calculate RA/DE (J2000.0) and show it...
			coordsSystem = qc_("RA/Dec (J2000.0)", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(cx, 5, false, true);
				cyt = StelUtils::radToDecDegStr(cy);
			}
			else
			{
				cxt = StelUtils::radToHmsStr(cx, true);
				cyt = StelUtils::radToDmsStr(cy, true);
			}
			break;
		}
		case RaDec:
		{
			StelUtils::rectToSphe(&cx,&cy,core->j2000ToEquinoxEqu(mousePosition)); // Calculate RA/DE and show it...
			coordsSystem = qc_("RA/Dec", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(cx, 5, false, true);
				cyt = StelUtils::radToDecDegStr(cy);
			}
			else
			{
				cxt = StelUtils::radToHmsStr(cx, true);
				cyt = StelUtils::radToDmsStr(cy, true);
			}
			break;
		}
		case AltAzi:
		{
			StelUtils::rectToSphe(&cy,&cx,core->j2000ToAltAz(mousePosition, StelCore::RefractionAuto));
			float direction = 3.; // N is zero, E is 90 degrees
			if (useSouthAzimuth)
				direction = 2.;
			cy = direction*M_PI - cy;
			if (cy > M_PI*2)
				cy -= M_PI*2;

			coordsSystem = qc_("Az/Alt", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(cy);
				cyt = StelUtils::radToDecDegStr(cx);
			}
			else
			{
				cxt = StelUtils::radToDmsStr(cy);
				cyt = StelUtils::radToDmsStr(cx);
			}
			break;
		}
		case Galactic:
		{
			StelUtils::rectToSphe(&cx,&cy,core->j2000ToGalactic(mousePosition)); // Calculate galactic position and show it...
			coordsSystem = qc_("Gal. Long/Lat", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(cx);
				cyt = StelUtils::radToDecDegStr(cy);
			}
			else
			{
				cxt = StelUtils::radToDmsStr(cx, true);
				cyt = StelUtils::radToDmsStr(cy, true);
			}
			break;
		}
		case Ecliptic:
		{
			double lambda, beta;
			StelUtils::rectToSphe(&cx,&cy,core->j2000ToEquinoxEqu(mousePosition));
			StelUtils::equToEcl(cx, cy, core->getCurrentPlanet()->getRotObliquity(core->getJDE()), &lambda, &beta); // Calculate ecliptic position and show it...
			if (lambda<0) lambda+=2.0*M_PI;
			coordsSystem = qc_("Ecl. Long/Lat", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(lambda);
				cyt = StelUtils::radToDecDegStr(beta);
			}
			else
			{
				cxt = StelUtils::radToDmsStr(lambda, true);
				cyt = StelUtils::radToDmsStr(beta, true);
			}
			break;
		}
		case EclipticJ2000:
		{
			double lambda, beta;
			StelUtils::rectToSphe(&cx,&cy, mousePosition);
			StelUtils::equToEcl(cx, cy, core->getCurrentPlanet()->getRotObliquity(2451545.0), &lambda, &beta); // Calculate ecliptic position and show it...
			if (lambda<0) lambda+=2.0*M_PI;
			coordsSystem = qc_("Ecl. Long/Lat (J2000.0)", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				cxt = StelUtils::radToDecDegStr(lambda);
				cyt = StelUtils::radToDecDegStr(beta);
			}
			else
			{
				cxt = StelUtils::radToDmsStr(lambda, true);
				cyt = StelUtils::radToDmsStr(beta, true);
			}
			break;
		}
		case HourAngle:
		{
			Vec3d v = core->j2000ToAltAz(mousePosition, StelCore::RefractionAuto);
			StelUtils::rectToSphe(&cx,&cy,Mat4d::zrotation(-core->getLocalSiderealTime())*core->altAzToEquinoxEqu(v, StelCore::RefractionOff));
			cx = 2.*M_PI-cx;
			coordsSystem = qc_("HA/Dec", "abbreviated in the plugin");
			if (withDecimalDegree)
			{
				double ha_sidereal = cx*12/M_PI;
				if (ha_sidereal>24.)
					ha_sidereal -= 24.;
				cxt = QString("%1h").arg(ha_sidereal, 0, 'f', 5);
				cyt = StelUtils::radToDecDegStr(cy);

			}
			else
			{
				cxt = StelUtils::radToHmsStr(cx);
				cyt = StelUtils::radToDmsStr(cy);
			}
			break;		
		}
	}

	QString coordsText = QString("%1: %2/%3").arg(coordsSystem).arg(cxt).arg(cyt);
	sPainter.drawText(getCoordinatesPlace(coordsText).first, getCoordinatesPlace(coordsText).second, coordsText);
}
예제 #10
0
void SkyLine::draw(StelCore *core) const
{
	if (!fader.getInterstate())
		return;

	StelProjectorP prj = core->getProjection(frameType, frameType!=StelCore::FrameAltAz ? StelCore::RefractionAuto : StelCore::RefractionOff);

	// Get the bounding halfspace
	const SphericalCap& viewPortSphericalCap = prj->getBoundingCap();

	// Initialize a painter and set openGL state
	StelPainter sPainter(prj);
	sPainter.setColor(color[0], color[1], color[2], fader.getInterstate());
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode

	Vec4f textColor(color[0], color[1], color[2], 0);		
	textColor[3]=fader.getInterstate();

	ViewportEdgeIntersectCallbackData userData(&sPainter);	
	sPainter.setFont(font);
	userData.textColor = textColor;	
	userData.text = label;
	/////////////////////////////////////////////////
	// Draw the line
	SphericalCap meridianSphericalCap(Vec3d(0,0,1), 0);	
	Vec3d fpt(1,0,0);
	if (line_type==MERIDIAN)
	{
		meridianSphericalCap.n.set(0,1,0);
	}

	Vec3d p1, p2;
	if (!SphericalCap::intersectionPoints(viewPortSphericalCap, meridianSphericalCap, p1, p2))
	{
		if ((viewPortSphericalCap.d<meridianSphericalCap.d && viewPortSphericalCap.contains(meridianSphericalCap.n))
			|| (viewPortSphericalCap.d<-meridianSphericalCap.d && viewPortSphericalCap.contains(-meridianSphericalCap.n)))
		{
			// The meridian is fully included in the viewport, draw it in 3 sub-arcs to avoid length > 180.
			const Mat4d& rotLon120 = Mat4d::rotation(meridianSphericalCap.n, 120.*M_PI/180.);
			Vec3d rotFpt=fpt;
			rotFpt.transfo4d(rotLon120);
			Vec3d rotFpt2=rotFpt;
			rotFpt2.transfo4d(rotLon120);
			sPainter.drawGreatCircleArc(fpt, rotFpt, NULL, viewportEdgeIntersectCallback, &userData);
			sPainter.drawGreatCircleArc(rotFpt, rotFpt2, NULL, viewportEdgeIntersectCallback, &userData);
			sPainter.drawGreatCircleArc(rotFpt2, fpt, NULL, viewportEdgeIntersectCallback, &userData);
			return;
		}
		else
			return;
	}


	Vec3d middlePoint = p1+p2;
	middlePoint.normalize();
	if (!viewPortSphericalCap.contains(middlePoint))
		middlePoint*=-1.;

	// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
	sPainter.drawGreatCircleArc(p1, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);
	sPainter.drawGreatCircleArc(p2, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);

// 	// Johannes: use a big radius as a dirty workaround for the bug that the
// 	// ecliptic line is not drawn around the observer, but around the sun:
// 	const Vec3d vv(1000000,0,0);

}
예제 #11
0
//! Draw the sky grid in the current frame
void SkyGrid::draw(const StelCore* core) const
{
	const StelProjectorP prj = core->getProjection(frameType, frameType!=StelCore::FrameAltAz ? StelCore::RefractionAuto : StelCore::RefractionOff);
	if (!fader.getInterstate())
		return;

	bool withDecimalDegree = dynamic_cast<StelGui*>(StelApp::getInstance().getGui())->getFlagShowDecimalDegrees();

	// Look for all meridians and parallels intersecting with the disk bounding the viewport
	// Check whether the pole are in the viewport
	bool northPoleInViewport = false;
	bool southPoleInViewport = false;
	Vec3f win;
	if (prj->project(Vec3f(0,0,1), win) && prj->checkInViewport(win))
		northPoleInViewport = true;
	if (prj->project(Vec3f(0,0,-1), win) && prj->checkInViewport(win))
		southPoleInViewport = true;
	// Get the longitude and latitude resolution at the center of the viewport
	Vec3d centerV;
	prj->unProject(prj->getViewportPosX()+prj->getViewportWidth()/2, prj->getViewportPosY()+prj->getViewportHeight()/2+1, centerV);
	double lon2, lat2;
	StelUtils::rectToSphe(&lon2, &lat2, centerV);

	const double gridStepParallelRad = M_PI/180.*getClosestResolutionDMS(prj->getPixelPerRadAtCenter());
	double gridStepMeridianRad;
	if (northPoleInViewport || southPoleInViewport)
		gridStepMeridianRad = (frameType==StelCore::FrameAltAz || frameType==StelCore::FrameGalactic) ? M_PI/180.* 10. : M_PI/180.* 15.;
	else
	{
		const double closetResLon = (frameType==StelCore::FrameAltAz || frameType==StelCore::FrameGalactic) ? getClosestResolutionDMS(prj->getPixelPerRadAtCenter()*std::cos(lat2)) : getClosestResolutionHMS(prj->getPixelPerRadAtCenter()*std::cos(lat2));
		gridStepMeridianRad = M_PI/180.* ((northPoleInViewport || southPoleInViewport) ? 15. : closetResLon);
	}

	// Get the bounding halfspace
	const SphericalCap& viewPortSphericalCap = prj->getBoundingCap();

	// Compute the first grid starting point. This point is close to the center of the screen
	// and lays at the intersection of a meridien and a parallel
	lon2 = gridStepMeridianRad*((int)(lon2/gridStepMeridianRad+0.5));
	lat2 = gridStepParallelRad*((int)(lat2/gridStepParallelRad+0.5));
	Vec3d firstPoint;
	StelUtils::spheToRect(lon2, lat2, firstPoint);
	firstPoint.normalize();

	// Q_ASSERT(viewPortSphericalCap.contains(firstPoint));

	// Initialize a painter and set openGL state
	StelPainter sPainter(prj);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode
	Vec4f textColor(color[0], color[1], color[2], 0);
	sPainter.setColor(color[0],color[1],color[2], fader.getInterstate());

	textColor*=2;
	textColor[3]=fader.getInterstate();

	sPainter.setFont(font);
	ViewportEdgeIntersectCallbackData userData(&sPainter);
	userData.textColor = textColor;
	userData.frameType = frameType;

	/////////////////////////////////////////////////
	// Draw all the meridians (great circles)
	SphericalCap meridianSphericalCap(Vec3d(1,0,0), 0);
	Mat4d rotLon = Mat4d::zrotation(gridStepMeridianRad);
	Vec3d fpt = firstPoint;
	Vec3d p1, p2;
	int maxNbIter = (int)(M_PI/gridStepMeridianRad);
	int i;
	for (i=0; i<maxNbIter; ++i)
	{
		StelUtils::rectToSphe(&lon2, &lat2, fpt);
		userData.raAngle = lon2;

		meridianSphericalCap.n = fpt^Vec3d(0,0,1);
		meridianSphericalCap.n.normalize();
		if (!SphericalCap::intersectionPoints(viewPortSphericalCap, meridianSphericalCap, p1, p2))
		{
			if (viewPortSphericalCap.d<meridianSphericalCap.d && viewPortSphericalCap.contains(meridianSphericalCap.n))
			{
				// The meridian is fully included in the viewport, draw it in 3 sub-arcs to avoid length > 180.
				const Mat4d& rotLon120 = Mat4d::rotation(meridianSphericalCap.n, 120.*M_PI/180.);
				Vec3d rotFpt=fpt;
				rotFpt.transfo4d(rotLon120);
				Vec3d rotFpt2=rotFpt;
				rotFpt2.transfo4d(rotLon120);
				sPainter.drawGreatCircleArc(fpt, rotFpt, NULL, viewportEdgeIntersectCallback, &userData);
				sPainter.drawGreatCircleArc(rotFpt, rotFpt2, NULL, viewportEdgeIntersectCallback, &userData);
				sPainter.drawGreatCircleArc(rotFpt2, fpt, NULL, viewportEdgeIntersectCallback, &userData);
				fpt.transfo4d(rotLon);
				continue;
			}
			else
				break;
		}

		Vec3d middlePoint = p1+p2;
		middlePoint.normalize();
		if (!viewPortSphericalCap.contains(middlePoint))
			middlePoint*=-1.;

		// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
		sPainter.drawGreatCircleArc(p1, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);
		sPainter.drawGreatCircleArc(p2, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);

		fpt.transfo4d(rotLon);
	}

	if (i!=maxNbIter)
	{
		rotLon = Mat4d::zrotation(-gridStepMeridianRad);
		fpt = firstPoint;
		fpt.transfo4d(rotLon);
		for (int j=0; j<maxNbIter-i; ++j)
		{
			StelUtils::rectToSphe(&lon2, &lat2, fpt);
			userData.raAngle = lon2;

			meridianSphericalCap.n = fpt^Vec3d(0,0,1);
			meridianSphericalCap.n.normalize();
			if (!SphericalCap::intersectionPoints(viewPortSphericalCap, meridianSphericalCap, p1, p2))
				break;

			Vec3d middlePoint = p1+p2;
			middlePoint.normalize();
			if (!viewPortSphericalCap.contains(middlePoint))
				middlePoint*=-1;

			sPainter.drawGreatCircleArc(p1, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);
			sPainter.drawGreatCircleArc(p2, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);

			fpt.transfo4d(rotLon);
		}
	}

	/////////////////////////////////////////////////
	// Draw all the parallels (small circles)
	SphericalCap parallelSphericalCap(Vec3d(0,0,1), 0);
	rotLon = Mat4d::rotation(firstPoint^Vec3d(0,0,1), gridStepParallelRad);
	fpt = firstPoint;
	maxNbIter = (int)(M_PI/gridStepParallelRad)-1;
	for (i=0; i<maxNbIter; ++i)
	{
		StelUtils::rectToSphe(&lon2, &lat2, fpt);
		if (withDecimalDegree)
			userData.text = StelUtils::radToDecDegStr(lat2);
		else
			userData.text = StelUtils::radToDmsStrAdapt(lat2);

		parallelSphericalCap.d = fpt[2];
		if (parallelSphericalCap.d>0.9999999)
			break;

		const Vec3d rotCenter(0,0,parallelSphericalCap.d);
		if (!SphericalCap::intersectionPoints(viewPortSphericalCap, parallelSphericalCap, p1, p2))
		{
			if ((viewPortSphericalCap.d<parallelSphericalCap.d && viewPortSphericalCap.contains(parallelSphericalCap.n))
				|| (viewPortSphericalCap.d<-parallelSphericalCap.d && viewPortSphericalCap.contains(-parallelSphericalCap.n)))
			{
				// The parallel is fully included in the viewport, draw it in 3 sub-arcs to avoid lengths >= 180 deg
				static const Mat4d rotLon120 = Mat4d::zrotation(120.*M_PI/180.);
				Vec3d rotFpt=fpt;
				rotFpt.transfo4d(rotLon120);
				Vec3d rotFpt2=rotFpt;
				rotFpt2.transfo4d(rotLon120);
				sPainter.drawSmallCircleArc(fpt, rotFpt, rotCenter, viewportEdgeIntersectCallback, &userData);
				sPainter.drawSmallCircleArc(rotFpt, rotFpt2, rotCenter, viewportEdgeIntersectCallback, &userData);
				sPainter.drawSmallCircleArc(rotFpt2, fpt, rotCenter, viewportEdgeIntersectCallback, &userData);
				fpt.transfo4d(rotLon);
				continue;
			}
			else
				break;
		}

		// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
		Vec3d middlePoint = p1-rotCenter+p2-rotCenter;
		middlePoint.normalize();
		middlePoint*=(p1-rotCenter).length();
		middlePoint+=rotCenter;
		if (!viewPortSphericalCap.contains(middlePoint))
		{
			middlePoint-=rotCenter;
			middlePoint*=-1.;
			middlePoint+=rotCenter;
		}

		sPainter.drawSmallCircleArc(p1, middlePoint, rotCenter, viewportEdgeIntersectCallback, &userData);
		sPainter.drawSmallCircleArc(p2, middlePoint, rotCenter, viewportEdgeIntersectCallback, &userData);

		fpt.transfo4d(rotLon);
	}

	if (i!=maxNbIter)
	{
		rotLon = Mat4d::rotation(firstPoint^Vec3d(0,0,1), -gridStepParallelRad);
		fpt = firstPoint;
		fpt.transfo4d(rotLon);
		for (int j=0; j<maxNbIter-i; ++j)
		{
			StelUtils::rectToSphe(&lon2, &lat2, fpt);
			if (withDecimalDegree)
				userData.text = StelUtils::radToDecDegStr(lat2);
			else
				userData.text = StelUtils::radToDmsStrAdapt(lat2);

			parallelSphericalCap.d = fpt[2];
			const Vec3d rotCenter(0,0,parallelSphericalCap.d);
			if (!SphericalCap::intersectionPoints(viewPortSphericalCap, parallelSphericalCap, p1, p2))
			{
				if ((viewPortSphericalCap.d<parallelSphericalCap.d && viewPortSphericalCap.contains(parallelSphericalCap.n))
					 || (viewPortSphericalCap.d<-parallelSphericalCap.d && viewPortSphericalCap.contains(-parallelSphericalCap.n)))
				{
					// The parallel is fully included in the viewport, draw it in 3 sub-arcs to avoid lengths >= 180 deg
					static const Mat4d rotLon120 = Mat4d::zrotation(120.*M_PI/180.);
					Vec3d rotFpt=fpt;
					rotFpt.transfo4d(rotLon120);
					Vec3d rotFpt2=rotFpt;
					rotFpt2.transfo4d(rotLon120);
					sPainter.drawSmallCircleArc(fpt, rotFpt, rotCenter, viewportEdgeIntersectCallback, &userData);
					sPainter.drawSmallCircleArc(rotFpt, rotFpt2, rotCenter, viewportEdgeIntersectCallback, &userData);
					sPainter.drawSmallCircleArc(rotFpt2, fpt, rotCenter, viewportEdgeIntersectCallback, &userData);
					fpt.transfo4d(rotLon);
					continue;
				}
				else
					break;
			}

			// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
			Vec3d middlePoint = p1-rotCenter+p2-rotCenter;
			middlePoint.normalize();
			middlePoint*=(p1-rotCenter).length();
			middlePoint+=rotCenter;
			if (!viewPortSphericalCap.contains(middlePoint))
			{
				middlePoint-=rotCenter;
				middlePoint*=-1.;
				middlePoint+=rotCenter;
			}

			sPainter.drawSmallCircleArc(p1, middlePoint, rotCenter, viewportEdgeIntersectCallback, &userData);
			sPainter.drawSmallCircleArc(p2, middlePoint, rotCenter, viewportEdgeIntersectCallback, &userData);

			fpt.transfo4d(rotLon);
		}
	}
}
예제 #12
0
// Increment/decrement smoothly the vision field and position
void StelMovementMgr::updateMotion(double deltaTime)
{
	updateVisionVector(deltaTime);

	const StelProjectorP proj = core->getProjection(StelCore::FrameJ2000);
	// the more it is zoomed, the lower the moving speed is (in angle)
	double depl=keyMoveSpeed*deltaTime*1000*currentFov;
	double deplzoom=keyZoomSpeed*deltaTime*1000*proj->deltaZoom(currentFov*(M_PI/360.0))*(360.0/M_PI);

	if (flagMoveSlow)
	{
		depl *= 0.2;
		deplzoom *= 0.2;
	}

	if (deltaAz<0)
	{
		deltaAz = -depl/30;
		if (deltaAz<-0.2)
			deltaAz = -0.2;
	}
	else if (deltaAz>0)
	{
		deltaAz = (depl/30);
		if (deltaAz>0.2)
			deltaAz = 0.2;
	}

	if (deltaAlt<0)
	{
		deltaAlt = -depl/30;
		if (deltaAlt<-0.2)
			deltaAlt = -0.2;
	}
	else if (deltaAlt>0)
	{
		deltaAlt = depl/30;
		if (deltaAlt>0.2)
			deltaAlt = 0.2;
	}

	if (deltaFov<0)
	{
		deltaFov = -deplzoom*5;
		if (deltaFov<-0.15*currentFov)
			deltaFov = -0.15*currentFov;
	}
	else if (deltaFov>0)
	{
		deltaFov = deplzoom*5;
		if (deltaFov>20)
			deltaFov = 20;
	}

	if (deltaFov != 0 )
	{
		changeFov(deltaFov);
	}
	panView(deltaAz, deltaAlt);
	updateAutoZoom(deltaTime);
}
예제 #13
0
void SkyLine::draw(StelCore *core) const
{
	if (!fader.getInterstate())
		return;

	StelProjectorP prj = core->getProjection(frameType, frameType!=StelCore::FrameAltAz ? StelCore::RefractionAuto : StelCore::RefractionOff);

	// Get the bounding halfspace
	const SphericalCap& viewPortSphericalCap = prj->getBoundingCap();

	// Initialize a painter and set openGL state
	StelPainter sPainter(prj);
	sPainter.setColor(color[0], color[1], color[2], fader.getInterstate());
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode
	#ifdef GL_LINE_SMOOTH
	if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
		glEnable(GL_LINE_SMOOTH);
	#endif
	Vec4f textColor(color[0], color[1], color[2], 0);		
	textColor[3]=fader.getInterstate();

	ViewportEdgeIntersectCallbackData userData(&sPainter);	
	sPainter.setFont(font);
	userData.textColor = textColor;	
	userData.text = label;
	/////////////////////////////////////////////////
	// Draw the line

	// Precession circles are Small Circles, all others are Great Circles.
	if (line_type==PRECESSIONCIRCLE_N || line_type==PRECESSIONCIRCLE_S)
	{
		const double lat=(line_type==PRECESSIONCIRCLE_S ? -1.0 : 1.0) * (M_PI/2.0-getPrecessionAngleVondrakCurrentEpsilonA());
		SphericalCap declinationCap(Vec3d(0,0,1), std::sin(lat));
		const Vec3d rotCenter(0,0,declinationCap.d);

		Vec3d p1, p2;
		if (!SphericalCap::intersectionPoints(viewPortSphericalCap, declinationCap, p1, p2))
		{
			if ((viewPortSphericalCap.d<declinationCap.d && viewPortSphericalCap.contains(declinationCap.n))
				|| (viewPortSphericalCap.d<-declinationCap.d && viewPortSphericalCap.contains(-declinationCap.n)))
			{
				// The line is fully included in the viewport, draw it in 3 sub-arcs to avoid length > 180.
				Vec3d pt1;
				Vec3d pt2;
				Vec3d pt3;
				const double lon1=0.0;
				const double lon2=120.0*M_PI/180.0;
				const double lon3=240.0*M_PI/180.0;
				StelUtils::spheToRect(lon1, lat, pt1); pt1.normalize();
				StelUtils::spheToRect(lon2, lat, pt2); pt2.normalize();
				StelUtils::spheToRect(lon3, lat, pt3); pt3.normalize();

				sPainter.drawSmallCircleArc(pt1, pt2, rotCenter, viewportEdgeIntersectCallback, &userData);
				sPainter.drawSmallCircleArc(pt2, pt3, rotCenter, viewportEdgeIntersectCallback, &userData);
				sPainter.drawSmallCircleArc(pt3, pt1, rotCenter, viewportEdgeIntersectCallback, &userData);
				#ifdef GL_LINE_SMOOTH
				if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
					glDisable(GL_LINE_SMOOTH);
				#endif
				glDisable(GL_BLEND);
				return;
			}
			else
			{
				#ifdef GL_LINE_SMOOTH
				if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
					glDisable(GL_LINE_SMOOTH);
				#endif
				glDisable(GL_BLEND);
				return;
			}
		}
		// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
		Vec3d middlePoint = p1-rotCenter+p2-rotCenter;
		middlePoint.normalize();
		middlePoint*=(p1-rotCenter).length();
		middlePoint+=rotCenter;
		if (!viewPortSphericalCap.contains(middlePoint))
		{
			middlePoint-=rotCenter;
			middlePoint*=-1.;
			middlePoint+=rotCenter;
		}

		sPainter.drawSmallCircleArc(p1, middlePoint, rotCenter,viewportEdgeIntersectCallback, &userData);
		sPainter.drawSmallCircleArc(p2, middlePoint, rotCenter, viewportEdgeIntersectCallback, &userData);

		// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH
		#ifdef GL_LINE_SMOOTH
		if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
			glDisable(GL_LINE_SMOOTH);
		#endif

		glDisable(GL_BLEND);


		return;
	}

	// All the other "lines" are Great Circles
	SphericalCap meridianSphericalCap(Vec3d(0,0,1), 0);	
	Vec3d fpt(1,0,0);
	if ((line_type==MERIDIAN) || (line_type==COLURE_1))
	{
		meridianSphericalCap.n.set(0,1,0);
	}
	if ((line_type==PRIME_VERTICAL) || (line_type==COLURE_2))
	{
		meridianSphericalCap.n.set(1,0,0);
		fpt.set(0,0,1);
	}

	if (line_type==LONGITUDE)
	{
		Vec3d coord;
		double lambda, beta;
		StelUtils::rectToSphe(&lambda, &beta, core->getCurrentPlanet()->getHeliocentricEclipticPos());
		StelUtils::spheToRect(lambda + M_PI/2., 0., coord);
		meridianSphericalCap.n.set(coord[0],coord[1],coord[2]);
		fpt.set(0,0,1);
	}

	Vec3d p1, p2;
	if (!SphericalCap::intersectionPoints(viewPortSphericalCap, meridianSphericalCap, p1, p2))
	{
		if ((viewPortSphericalCap.d<meridianSphericalCap.d && viewPortSphericalCap.contains(meridianSphericalCap.n))
			|| (viewPortSphericalCap.d<-meridianSphericalCap.d && viewPortSphericalCap.contains(-meridianSphericalCap.n)))
		{
			// The meridian is fully included in the viewport, draw it in 3 sub-arcs to avoid length > 180.
			const Mat4d& rotLon120 = Mat4d::rotation(meridianSphericalCap.n, 120.*M_PI/180.);
			Vec3d rotFpt=fpt;
			rotFpt.transfo4d(rotLon120);
			Vec3d rotFpt2=rotFpt;
			rotFpt2.transfo4d(rotLon120);
			sPainter.drawGreatCircleArc(fpt, rotFpt, NULL, viewportEdgeIntersectCallback, &userData);
			sPainter.drawGreatCircleArc(rotFpt, rotFpt2, NULL, viewportEdgeIntersectCallback, &userData);
			sPainter.drawGreatCircleArc(rotFpt2, fpt, NULL, viewportEdgeIntersectCallback, &userData);
			return;
		}
		else
			return;
	}


	Vec3d middlePoint = p1+p2;
	middlePoint.normalize();
	if (!viewPortSphericalCap.contains(middlePoint))
		middlePoint*=-1.;

	// Draw the arc in 2 sub-arcs to avoid lengths > 180 deg
	sPainter.drawGreatCircleArc(p1, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);
	sPainter.drawGreatCircleArc(p2, middlePoint, NULL, viewportEdgeIntersectCallback, &userData);

	// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH
	#ifdef GL_LINE_SMOOTH
	if (QOpenGLContext::currentContext()->format().renderableType()==QSurfaceFormat::OpenGL)
		glDisable(GL_LINE_SMOOTH);
	#endif

	glDisable(GL_BLEND);

// 	// Johannes: use a big radius as a dirty workaround for the bug that the
// 	// ecliptic line is not drawn around the observer, but around the sun:
// 	const Vec3d vv(1000000,0,0);

}
예제 #14
0
void Atmosphere::updateGrid(const StelProjectorP projector)
{
	viewport                   = projector->getViewport();
	const float viewportWidth  = projector->getViewportWidth();
	const float viewportHeight = projector->getViewportHeight();
	const float aspectRatio    = viewportWidth / viewportHeight;
	skyResolutionY             = StelApp::getInstance()
	                                     .getSettings()
	                                    ->value("landscape/atmosphereybin", 44)
	                                     .toInt();
	const float resolutionX    = skyResolutionY * 0.5 * sqrt(3.0) * aspectRatio;
	skyResolutionX             = static_cast<int>(floor(0.5 + resolutionX));
	const float stepX          = viewportWidth  / (skyResolutionX - 0.5);
	const float stepY          = viewportHeight / skyResolutionY;
	const float viewportLeft   = projector->getViewportPosX();
	const float viewportBottom = projector->getViewportPosY();

	vertexGrid->unlock();
	vertexGrid->clear();

	// Construct the vertex grid.
	for(int y = 0; y <= skyResolutionY; ++y)
	{
		const float yPos = viewportBottom + y * stepY;
		for (int x = 0; x <= skyResolutionX; ++x)
		{
			const float offset = (x == 0)              ? 0.0f :
			                     (x == skyResolutionX) ? viewportWidth
			                                           : (x - 0.5 * (y & 1)) * stepX;
			const float xPos = viewportLeft + offset;
			vertexGrid->addVertex(Vertex(Vec2f(xPos, yPos), Vec4f()));
		}
	}
	vertexGrid->lock();

	// The grid is (resolutionX + 1) * (resolutionY + 1),
	// so the rows are for 0 to resolutionY-1
	// The last row includes vertices in row resolutionY

	// Construct an index buffer for each row in the grid.
	for(int row = 0; row < skyResolutionY; ++row)
	{
		StelIndexBuffer* buffer; 
		// Reuse previously used row index buffer.
		if(rowIndices.size() > row)
		{
			buffer = rowIndices[row];
			buffer->unlock();
			buffer->clear();
		}
		// Add new row index buffer.
		else
		{
			buffer = renderer->createIndexBuffer(IndexType_U16);
			rowIndices.append(buffer);
		}

		uint g0 = row       * (1 + skyResolutionX);
		uint g1 = (row + 1) * (1 + skyResolutionX);
		for (int col = 0; col <= skyResolutionX; ++col)
		{
			buffer->addIndex(g0++);
			buffer->addIndex(g1++);
		}
		buffer->lock();

		Q_ASSERT_X(buffer->length() == (skyResolutionX + 1) * 2, Q_FUNC_INFO,
		           "Unexpected grid row index buffer size");
	}

	Q_ASSERT_X(rowIndices.size() >= skyResolutionY, Q_FUNC_INFO,
	           "Not enough row index buffers");
}
예제 #15
0
// returns true if visible
// Assumes that we are in local frame
void Meteor::draw(const StelCore* core, StelPainter& sPainter)
{
    if (!alive)
        return;

    const StelProjectorP proj = sPainter.getProjector();

    Vec3d spos = position;
    Vec3d epos = posTrain;

    // convert to equ
    spos.transfo4d(mmat);
    epos.transfo4d(mmat);

    // convert to local and correct for earth radius [since equ and local coordinates in stellarium use same 0 point!]
    spos = core->equinoxEquToAltAz( spos );
    epos = core->equinoxEquToAltAz( epos );
    spos[2] -= EARTH_RADIUS;
    epos[2] -= EARTH_RADIUS;
    // 1216 is to scale down under 1 for desktop version
    spos/=1216;
    epos/=1216;

    //  qDebug("[%f %f %f] (%d, %d) (%d, %d)\n", position[0], position[1], position[2], (int)start[0], (int)start[1], (int)end[0], (int)end[1]);

    if (train)
    {
        // connect this point with last drawn point
        double tmag = mag*distMultiplier;

        // compute an intermediate point so can curve slightly along projection distortions
        Vec3d posi = posInternal;
        posi[2] = position[2] + (posTrain[2] - position[2])/2;
        posi.transfo4d(mmat);
        posi = core->equinoxEquToAltAz( posi );
        posi[2] -= EARTH_RADIUS;
        posi/=1216;

        // draw dark to light
        Vec4f colorArray[3];
        colorArray[0].set(0,0,0,0);
        colorArray[1].set(1,1,1,tmag*0.5);
        colorArray[2].set(1,1,1,tmag);
        Vec3d vertexArray[3];
        vertexArray[0]=epos;
        vertexArray[1]=posi;
        vertexArray[2]=spos;
        sPainter.setColorPointer(4, GL_FLOAT, colorArray);
        sPainter.setVertexPointer(3, GL_DOUBLE, vertexArray);
        // TODO the crash doesn't appear when the last true is set to false
        sPainter.enableClientStates(true, false, true);
        sPainter.drawFromArray(StelPainter::LineStrip, 3, 0, true);
        sPainter.enableClientStates(false);
    }
    else
    {
        sPainter.setPointSize(1.f);
        Vec3d start;
        proj->project(spos, start);
        sPainter.drawPoint2d(start[0],start[1]);
    }

    train = 1;
}
void StelQGLRenderer::drawText(const TextParams& params)
{
	statistics[TEXT_DRAWS] += 1.0;
	StelQGLTextureBackend* currentTexture = currentlyBoundTextures[0];

	if(params.string_.length() == 0)
	{
		return;
	}

	viewport.enablePainting();
	if(currentFontSet)
	{
		viewport.setFont(currentFont);
	}
	QPainter* painter = viewport.getPainter();
	Q_ASSERT_X(NULL != painter, Q_FUNC_INFO, 
	           "Trying to draw text but painting is disabled");

	QFontMetrics fontMetrics = painter->fontMetrics();

	StelProjectorP projector = NULL == params.projector_
	                         ? StelApp::getInstance().getCore()->getProjection2d() 
	                         : params.projector_;
	Vec3f win;
	if(params.doNotProject_) 
	{
		win = params.position_;
	}
	else if(!projector->project(params.position_, win))
	{
		viewport.disablePainting();
		return;
	}

	const int x = win[0];
	const int y = win[1];

	// Avoid drawing if outside viewport.
	// We do a worst-case approximation as getting exact text dimensions is expensive.
	// We also account for rotation by assuming the worst case in bot X and Y 
	// (culling with a rotating rectangle would be expensive)
	const int cullDistance = 
		std::max(fontMetrics.height(), params.string_.size() * fontMetrics.maxWidth());
	const Vec4i viewXywh = projector->getViewportXywh();
	const int viewMinX = viewXywh[0];
	const int viewMinY = viewXywh[1];
	const int viewMaxX = viewMinX + viewXywh[2];
	const int viewMaxY = viewMinY + viewXywh[3];

	if(y + cullDistance < viewMinY || y - cullDistance > viewMaxY ||
	   x + cullDistance < viewMinX || x - cullDistance > viewMaxX)
	{
		viewport.disablePainting();
		return;
	}

	if(projector->useGravityLabels() && !params.noGravity_)
	{
		drawTextGravityHelper(params, *painter, x, y, projector);
		return;
	}
	
	const int pixelSize   = painter->font().pixelSize();
	// Strings drawn by drawText() can differ by text, font size, or the font itself.
	const QByteArray hash = params.string_.toUtf8() + QByteArray::number(pixelSize) + 
	                        painter->font().family().toUtf8();
	StelQGLTextureBackend* textTexture = textTextureCache.object(hash);

	// No texture in cache for this string, need to draw it.
	if (NULL == textTexture) 
	{
		const QRect extents = fontMetrics.boundingRect(params.string_);

		// Width and height of the text. 
		// Texture width/height is required to be at least equal to this.
		//
		// Both X and Y need to be at least 1 so we don't create an empty image 
		// (doesn't work with textures)
		const int requiredWidth  = std::max(1, extents.width() + 1 + static_cast<int>(0.02f * extents.width()));
		const int requiredHeight = std::max(1, extents.height());
		// Create temporary image and render text into it

		// QImage is used solely to reuse existing QGLTextureBackend constructor 
		// function. QPixmap could be used as well (not sure which is faster, 
		// needs profiling)
		QImage image = areNonPowerOfTwoTexturesSupported() 
		             ? QImage(requiredWidth, requiredHeight, QImage::Format_ARGB32_Premultiplied) 
		             : QImage(StelUtils::smallestPowerOfTwoGreaterOrEqualTo(requiredWidth), 
		                      StelUtils::smallestPowerOfTwoGreaterOrEqualTo(requiredHeight),
		                      QImage::Format_ARGB32);
		image.fill(Qt::transparent);

		QPainter fontPainter(&image);
		fontPainter.setFont(painter->font());
		fontPainter.setRenderHints(QPainter::TextAntialiasing, true);
		fontPainter.setPen(Qt::white);

		// The second argument ensures the text is positioned correctly even if 
		// the image is enlarged to power-of-two.
		fontPainter.drawText(-extents.x(), 
		                     image.height() - requiredHeight - extents.y(), 
		                     params.string_);

		textTexture = StelQGLTextureBackend::constructFromImage
			(this, QString(), TextureParams().filtering(TextureFiltering_Linear), image);
		const QSize size = textTexture->getDimensions();
		if(!textTexture->getStatus() == TextureStatus_Loaded)
		{
			qWarning() << "Texture error: " << textTexture->getErrorMessage();
			Q_ASSERT_X(false, Q_FUNC_INFO, "Failed to construct a text texture");
		}
		textTextureCache.insert(hash, textTexture, 4 * size.width() * size.height());
	}

	// Even if NPOT textures are not supported, we always draw the full rectangle 
	// of the texture. The extra space is fully transparent, so it's not an issue.

	// Shortcut variables to calculate the rectangle.
	const QSize size   = textTexture->getDimensions();
	const float w      = size.width();
	const float h      = size.height();
	const float xShift = params.xShift_;
	const float yShift = params.yShift_;

	const float angleDegrees = 
		params.angleDegrees_ + 
		(params.noGravity_ ? 0.0f : projector->getDefaultAngleForGravityText());
	// Zero out very small angles.
	// 
	// (this could also be used to optimize the case with zero angled
	//  to avoid sin/cos if needed)
	const bool  angled = std::fabs(angleDegrees) >= 1.0f * M_PI / 180.f;
	const float cosr   = angled  ? std::cos(angleDegrees * M_PI / 180.0) : 1.0f;
	const float sinr   = angled  ? std::sin(angleDegrees * M_PI / 180.0) : 0.0f;

	// Corners of the (possibly rotated) texture rectangle.
	const Vec2f ne(round(x + cosr * xShift       - sinr * yShift),
	               round(y + sinr * xShift       + cosr * yShift));
	const Vec2f nw(round(x + cosr * (w + xShift) - sinr * yShift),
	               round(y + sinr * (w + xShift) + cosr * yShift));
	const Vec2f se(round(x + cosr * xShift       - sinr * (h + yShift)),
	               round(y + sinr * xShift       + cosr * (h + yShift)));
	const Vec2f sw(round(x + cosr * (w + xShift) - sinr * (h + yShift)),
	               round(y + sinr * (w + xShift) + cosr * (h + yShift)));

	// Construct the text vertex buffer if it doesn't exist yet, otherwise clear it.
	if(NULL == textBuffer)
	{
		textBuffer = createVertexBuffer<TexturedVertex>(PrimitiveType_TriangleStrip);
	}
	else
	{
		textBuffer->unlock();
		textBuffer->clear();
	}

	textBuffer->addVertex(TexturedVertex(ne, Vec2f(0.0f, 0.0f)));
	textBuffer->addVertex(TexturedVertex(nw, Vec2f(1.0f, 0.0f)));
	textBuffer->addVertex(TexturedVertex(se, Vec2f(0.0f, 1.0f)));
	textBuffer->addVertex(TexturedVertex(sw, Vec2f(1.0f, 1.0f)));
	textBuffer->lock();

	// Draw.
	const BlendMode oldBlendMode = blendMode;
	setBlendMode(BlendMode_Alpha);
	textTexture->bind(0);
	drawVertexBuffer(textBuffer);
	setBlendMode(oldBlendMode);

	// Reset user-bound texture.
	if(NULL != currentTexture)
	{
		currentTexture->bind(0);
	}
	viewport.disablePainting();
}
예제 #17
0
// Draw the Comet and all the related infos : name, circle etc... GZ: Taken from Planet.cpp 2013-11-05 and extended
void Comet::draw(StelCore* core, float maxMagLabels, const QFont& planetNameFont)
{
	if (hidden)
		return;
	if (getEnglishName() == core->getCurrentLocation().planetName)
	{ // GZ moved this up. Maybe even don't do that? E.g., draw tail while riding the comet? Decide later.
		return;
	}

	// The CometOrbit is in fact available in userDataPtr!
	CometOrbit* orbit=(CometOrbit*)userDataPtr;
	Q_ASSERT(orbit);
	if (!orbit->objectDateValid(core->getJDay())) return; // out of useful date range. This allows having hundreds of comet elements.

	if (orbit->getUpdateTails()){
		// Compute lengths and orientations from orbit object, but only if required.
		// TODO: This part should possibly be moved to another thread to keep draw() free from too much computation.

		Vec2f tailFactors=getComaDiameterAndTailLengthAU();
		float gasTailEndRadius=qMax(tailFactors[0], 0.025f*tailFactors[1]) ; // This avoids too slim gas tails for bright comets like Hale-Bopp.
		float gasparameter=gasTailEndRadius*gasTailEndRadius/(2.0f*tailFactors[1]); // parabola formula: z=r²/2p, so p=r²/2z
		// The dust tail is thicker and usually shorter. The factors can be configured in the elements.
		float dustparameter=gasTailEndRadius*gasTailEndRadius*dustTailWidthFactor*dustTailWidthFactor/(2.0f*dustTailLengthFactor*tailFactors[1]);

		// Find valid parameters to create paraboloid vertex arrays: dustTail, gasTail.
		computeParabola(gasparameter, gasTailEndRadius, -0.5f*gasparameter, gastailVertexArr,  gastailTexCoordArr, gastailIndices);
		// This was for a rotated straight parabola:
		//computeParabola(dustparameter, 2.0f*tailFactors[0], -0.5f*dustparameter, dusttailVertexArr, dusttailTexCoordArr, dusttailIndices);
		// Now we make a skewed parabola. Skew factor 15 (last arg) ad-hoc/empirical. TBD later: Find physically correct solution.
		computeParabola(dustparameter, dustTailWidthFactor*gasTailEndRadius, -0.5f*dustparameter, dusttailVertexArr, gastailTexCoordArr, gastailIndices, 25.0f*orbit->getVelocity().length());

		// Note that we use a diameter larger than what the formula returns. A scale factor of 1.2 is ad-hoc/empirical (GZ), but may look better.
		computeComa(1.0f*tailFactors[0]);
		orbit->setUpdateTails(false); // don't update until position has been recalculated elsewhere
	}

	Mat4d mat = Mat4d::translation(eclipticPos) * rotLocalToParent;
/*  // We can remove that - a Comet has no parent except for the sun...
	PlanetP p = parent;
	while (p && p->parent)
	{
		mat = Mat4d::translation(p->eclipticPos) * mat * p->rotLocalToParent;
		p = p->parent;
	}
*/
	// This removed totally the Planet shaking bug!!!
	StelProjector::ModelViewTranformP transfo = core->getHeliocentricEclipticModelViewTransform();
	transfo->combine(mat);

	// Compute the 2D position and check if in the screen
	const StelProjectorP prj = core->getProjection(transfo);
	float screenSz = getAngularSize(core)*M_PI/180.*prj->getPixelPerRadAtCenter();
	float viewport_left = prj->getViewportPosX();
	float viewport_bottom = prj->getViewportPosY();
	if (prj->project(Vec3d(0), screenPos)
		&& screenPos[1]>viewport_bottom - screenSz && screenPos[1] < viewport_bottom + prj->getViewportHeight()+screenSz
		&& screenPos[0]>viewport_left - screenSz && screenPos[0] < viewport_left + prj->getViewportWidth() + screenSz)
	{
		// Draw the name, and the circle if it's not too close from the body it's turning around
		// this prevents name overlapping (ie for jupiter satellites)
		float ang_dist = 300.f*atan(getEclipticPos().length()/getEquinoxEquatorialPos(core).length())/core->getMovementMgr()->getCurrentFov();
		// if (ang_dist==0.f) ang_dist = 1.f; // if ang_dist == 0, the Planet is sun.. --> GZ: we can remove it.

		// by putting here, only draw orbit if Comet is visible for clarity
		drawOrbit(core);  // TODO - fade in here also...

		if (flagLabels && ang_dist>0.25 && maxMagLabels>getVMagnitude(core))
		{
			labelsFader=true;
		}
		else
		{
			labelsFader=false;
		}
		drawHints(core, planetNameFont);

		draw3dModel(core,transfo,screenSz);
	}
	// tails should also be drawn if core is off-screen...
	drawTail(core,transfo,true);  // gas tail
	drawTail(core,transfo,false); // dust tail

	//Coma: this is just a fan disk tilted towards the observer;-)
	drawComa(core, transfo);
	return;
}
예제 #18
0
void StelViewportDistorterFisheyeToSphericMirror::generateDistortion
	(const QSettings& conf, const StelProjectorP& proj, 
	 const double distorterMaxFOV, StelRenderer* renderer)
{
	double gamma;
	loadGenerationParameters(conf, gamma);

	const int cols = maxGridX + 1;
	const int rows = maxGridY + 1;
	
	const float viewScale = 0.5 * newProjectorParams.viewportFovDiameter /
	                        proj->fovToViewScalingFactor(distorterMaxFOV*(M_PI/360.0));

	texCoordGrid = new Vec2f[cols * rows];
	float* heightGrid = new float[cols * rows];
  
	float maxHeight = 0;
	SphericMirrorCalculator calc(conf);
	           
	// Generate grid vertices/texcoords.
	for (int row = 0; row <= maxGridY; row++)
	{
		for (int col = 0; col <= maxGridX; col++)
		{
			Vertex vertex;
			float &height(heightGrid[row * cols + col]);
			
			// Clamp to screen extents.
			vertex.position[0] = (col == 0)        ? 0.f : 
			                     (col == maxGridX) ? screenWidth : 
			                                         (col - 0.5f * (row & 1)) * stepX;
			vertex.position[1] = row * stepY;
			Vec3f v,vX,vY;
			bool rc = calc.retransform((vertex.position[0]-0.5f*screenWidth) / screenHeight,
			                           (vertex.position[1]-0.5f*screenHeight) / screenHeight,
			                           v,vX,vY);

			rc &= proj->forward(v);
			const float x = newProjectorParams.viewportCenter[0] + v[0] * viewScale;
			const float y = newProjectorParams.viewportCenter[1] + v[1] * viewScale;
			height = rc ? (vX^vY).length() : 0.0;

			// sharp image up to the border of the fisheye image, at the cost of
			// accepting clamping artefacts. You can get rid of the clamping
			// artefacts by specifying a viewport size a little less then
			// (1<<n)*(1<<n), for instance 1022*1022. With a viewport size of
			// 512*512 and viewportFovDiameter=512 you will get clamping artefacts
			// in the 3 otherwise black hills on the bottom of the image.

			//      if (x < 0.f) {x=0.f;height=0;}
			//      else if (x > newProjectorParams.viewportXywh[2])
			//          {x=newProjectorParams.viewportXywh[2];height=0;}
			//      if (y < 0.f) {y=0.f;height=0;}
			//      else if (y > newProjectorParams.viewportXywh[3])
			//          {y=newProjectorParams.viewportXywh[3];height=0;}

			vertex.texCoord[0] = x / texture_w;
			vertex.texCoord[1] = y / texture_h;

			texCoordGrid[row * cols + col] = vertex.texCoord;

			vertexGrid->addVertex(vertex);
			maxHeight = qMax(height, maxHeight);
		}
	}
	
	// Generate grid colors. (Separate from previous loop as we need max height)
	for (int row = 0; row <= maxGridY; row++)
	{
		for (int col = 0; col <= maxGridX; col++)
		{
			const int cell = row * cols + col;

			// Getting/setting each vertex is not that efficient, but we only do this 
			// at startup.
			Vertex vertex = vertexGrid->getVertex(cell);
			Vec4f &color(vertex.color);
			const float height = heightGrid[cell];
			const float gray = (height <= 0.0) ? 0.0 : exp(gamma * log(height / maxHeight));
			color[0] = color[1] = color[2] = gray;
			color[3] = 1.0f; 

			vertexGrid->setVertex(cell, vertex);
		}
	}

	constructVertexBuffer(renderer);
	
	delete[] heightGrid;
	
	// FIXME: Comment out with /**/ after testing. --BM
	qDebug() << "StelViewportDistorterFisheyeToSphericMirror():" 
	         << "screen_w:" << this->screenWidth
	         << "screen_h:" << this->screenHeight << endl
	         << "originalProjectorParams.viewportXywh:" 
	         << originalProjectorParams.viewportXywh[0] 
	         << originalProjectorParams.viewportXywh[1] 
	         << originalProjectorParams.viewportXywh[2] 
	         << originalProjectorParams.viewportXywh[3] << endl
	         << "newProjectorParams.viewportXywh:"
	         << newProjectorParams.viewportXywh[0] 
	         << newProjectorParams.viewportXywh[1] 
	         << newProjectorParams.viewportXywh[2]
	         << newProjectorParams.viewportXywh[3] << endl 
	         << "originalProjectorParams.fov:"
	         << originalProjectorParams.fov << endl 
	         << "newProjectorParams.fov:" << newProjectorParams.fov << endl
	         << "originalProjectorParams.viewportCenter:"
	         << originalProjectorParams.viewportCenter[0] 
	         << originalProjectorParams.viewportCenter[1] << endl
	         << "newProjectorParams.viewportCenter:" 
	         << newProjectorParams.viewportCenter[0] 
	         << newProjectorParams.viewportCenter[1] << endl
	         << "originalProjectorParams.viewportFovDiameter:" 
	         << originalProjectorParams.viewportFovDiameter << endl
	         << "newProjectorParams.viewportFovDiameter:"
	         << newProjectorParams.viewportFovDiameter << endl
	         << "originalProjectorParams.zNear,zFar:" 
	         << originalProjectorParams.zNear 
	         << originalProjectorParams.zFar << endl
	         << "newProjectorParams.zNear,zFar:" 
	         << newProjectorParams.zNear 
	         << newProjectorParams.zFar << endl
	         //<< "viewport_texture_offset:" 
	         //<< viewport_texture_offset[0]
	         //<< viewport_texture_offset[1] << endl
	         << "texture_w:" << texture_w << endl
	         << "texture_h:" << texture_h << endl
	         << "max_x:" << maxGridX << endl
	         << "max_y:" << maxGridY;
}
예제 #19
0
void Atmosphere::computeColor
	(double JD, Vec3d sunPos, Vec3d moonPos, float moonPhase, StelCore* core, float eclipseFac,
	 float latitude, float altitude, float temperature, float relativeHumidity)
{
	// We lazily initialize vertex buffer at the first draw, 
	// so we can only call this after that.
	// We also need a renderer reference (again lazily from draw()) to 
	// construct index buffers as they might change at every call to computeColor().
	if(NULL == renderer) {return;}

	const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
	if (viewport != prj->getViewport())
	{
		// The viewport changed: update the number of points in the grid
		updateGrid(prj);
	}

	eclipseFactor = eclipseFac;
	if(eclipseFac < 0.0001f)
		eclipseFactor = 0.0001f;

	// No need to calculate if not visible
	if (!fader.getInterstate())
	{
		averageLuminance = 0.001f + lightPollutionLuminance;
		return;
	}

	// Calculate the atmosphere RGB for each point of the grid
	if (myisnan(sunPos.length()))
		sunPos.set(0.,0.,-1.*AU);
	if (myisnan(moonPos.length()))
		moonPos.set(0.,0.,-1.*AU);

	sunPos.normalize();
	moonPos.normalize();

	float sun_pos[3];
	sun_pos[0] = sunPos[0];
	sun_pos[1] = sunPos[1];
	sun_pos[2] = sunPos[2];

	float moon_pos[3];
	moon_pos[0] = moonPos[0];
	moon_pos[1] = moonPos[1];
	moon_pos[2] = moonPos[2];

	sky.setParamsv(sun_pos, 5.f);

	skyb.setLocation(latitude * M_PI/180., altitude, temperature, relativeHumidity);
	skyb.setSunMoon(moon_pos[2], sun_pos[2]);

	// Calculate the date from the julian day.
	int year, month, day;
	StelUtils::getDateFromJulianDay(JD, &year, &month, &day);
	skyb.setDate(year, month, moonPhase);

	// Variables used to compute the average sky luminance
	double sum_lum = 0.;

	Vec3d point(1., 0., 0.);
	skylightStruct2 b2;
	float lumi;

	vertexGrid->unlock();
	// Compute the sky color for every point above the ground
	for (int i=0; i<(1+skyResolutionX)*(1+skyResolutionY); ++i)
	{
		const Vec2f position = vertexGrid->getVertex(i).position;
		prj->unProject(position[0], position[1], point);

		Q_ASSERT(fabs(point.lengthSquared()-1.0) < 1e-10);

		if (point[2]<=0)
		{
			point[2] = -point[2];
			// The sky below the ground is the symmetric of the one above :
			// it looks nice and gives proper values for brightness estimation
		}

		// Use the Skybright.cpp 's models for brightness which gives better results.
		lumi = skyb.getLuminance(moon_pos[0]*point[0]+moon_pos[1]*point[1]+moon_pos[2]*point[2], 
								 sun_pos[0]*point[0]+sun_pos[1]*point[1]+sun_pos[2]*point[2],
		                         point[2]);
		lumi *= eclipseFactor;
		// Add star background luminance
		lumi += 0.0001;
		// Multiply by the input scale of the ToneConverter (is not done automatically by the xyYtoRGB method called later)
		//lumi*=eye->getInputScale();

		// Add the light pollution luminance AFTER the scaling to avoid scaling it because it is the cause
		// of the scaling itself
		lumi += lightPollutionLuminance;

		// Store for later statistics
		sum_lum+=lumi;

		Q_ASSERT_X(NULL != vertexGrid, Q_FUNC_INFO, 
		           "Vertex buffer not initialized when setting colors");

		// Now need to compute the xy part of the color component
		// This is done in a GLSL shader if possible
		if(NULL != shader)
		{
			// Store the back projected position + luminance in the input color to the shader
			const Vec4f color = Vec4f(point[0], point[1], point[2], lumi);
			vertexGrid->setVertex(i, Vertex(position, color));
			continue;
		}

		// Shaderless fallback
		if (lumi > 0.01)
		{
			// Use the Skylight model for the color
			b2.pos[0] = point[0];
			b2.pos[1] = point[1];
			b2.pos[2] = point[2];
			sky.getxyYValuev(b2);
		}
		else
		{
			// Too dark to see atmosphere color, don't bother computing it
			b2.color[0] = 0.25;
			b2.color[1] = 0.25;
		}

		const Vec4f color = Vec4f(b2.color[0], b2.color[1], lumi, 1.0f);
		vertexGrid->setVertex(i, Vertex(position, color));
	}
	vertexGrid->lock();

	// Update average luminance
	averageLuminance = sum_lum/((1+skyResolutionX)*(1+skyResolutionY));
}
예제 #20
0
void BookmarksDialog::goToBookmark(QString uuid)
{
	if (!uuid.isEmpty())
	{
		bookmark bm = bookmarksCollection.value(uuid);
		if (!bm.jd.isEmpty())
		{
			core->setJD(bm.jd.toDouble());
		}
		if (!bm.location.isEmpty())
		{
			StelLocationMgr* locationMgr = &StelApp::getInstance().getLocationMgr();
			core->moveObserverTo(locationMgr->locationForString(bm.location));
		}

		StelMovementMgr* mvmgr = GETSTELMODULE(StelMovementMgr);
		objectMgr->unSelect();

		bool status = objectMgr->findAndSelect(bm.name);
		float amd = mvmgr->getAutoMoveDuration();
		if (!bm.ra.isEmpty() && !bm.dec.isEmpty() && !status)
		{
			Vec3d pos;
			StelUtils::spheToRect(StelUtils::getDecAngle(bm.ra.trimmed()), StelUtils::getDecAngle(bm.dec.trimmed()), pos);
			if (bm.name.contains("marker", Qt::CaseInsensitive))
			{
				// Add a custom object on the sky
				GETSTELMODULE(CustomObjectMgr)->addCustomObject(bm.name, pos, bm.isVisibleMarker);
				status = objectMgr->findAndSelect(bm.name);
			}
			else
			{
				// The unnamed stars
				StelObjectP sobj;
				const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
				double fov = 5.0;
				if (bm.fov > 0.0)
					fov = bm.fov;

				mvmgr->zoomTo(fov, 0.0);
				mvmgr->moveToJ2000(pos, mvmgr->mountFrameToJ2000(Vec3d(0., 0., 1.)), 0.0);

				QList<StelObjectP> candidates = GETSTELMODULE(StarMgr)->searchAround(pos, 0.5, core);
				if (candidates.empty()) // The FOV is too big, let's reduce it
				{
					mvmgr->zoomTo(0.5*fov, 0.0);
					candidates = GETSTELMODULE(StarMgr)->searchAround(pos, 0.5, core);
				}

				Vec3d winpos;
				prj->project(pos, winpos);
				float xpos = winpos[0];
				float ypos = winpos[1];
				float best_object_value = 1000.f;
				for (const auto& obj : candidates)
				{
					prj->project(obj->getJ2000EquatorialPos(core), winpos);
					float distance = std::sqrt((xpos-winpos[0])*(xpos-winpos[0]) + (ypos-winpos[1])*(ypos-winpos[1]));
					if (distance < best_object_value)
					{
						best_object_value = distance;
						sobj = obj;
					}
				}

				if (sobj)
					status = objectMgr->setSelectedObject(sobj);
			}
		}

		if (status)
		{
			const QList<StelObjectP> newSelected = objectMgr->getSelectedObject();
			if (!newSelected.empty())
			{
				mvmgr->moveToObject(newSelected[0], amd);
				mvmgr->setFlagTracking(true);
			}
		}
	}
}
double StelGeodesicGridDrawer::draw(StelCore* core, int maxSearchLevel)
{
	const StelProjectorP prj = core->getProjection();
	StelPainter sPainter(prj);
	StelGeodesicGrid* geodesicGrid = core->getGeodesicGrid();

	const GeodesicSearchResult* geodesic_search_result = geodesicGrid->search(prj->unprojectViewport(), maxSearchLevel);
	
	glDisable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);	
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode
	core->setCurrentFrame(StelCore::FrameJ2000);	// set 2D coordinate
	sPainter.setColor(0.2,0.3,0.2);
	
	int lev = (int)(7./pow(prj->getFov(), 0.4))+2;
	if (lev>geodesicGrid->getMaxLevel()) 
		lev = geodesicGrid->getMaxLevel();

	lev = maxSearchLevel;
	Vec3d win1, win2;
	int index;
	Vec3d v0, v1, v2;
	{
		GeodesicSearchInsideIterator it1(*geodesic_search_result, lev);
		while((index = it1.next()) >= 0)
		{
			Vec3d center(0);
			geodesicGrid->getTriangleCorners(lev, index, v0, v1, v2);
			prj->project(v0, win1);
			prj->project(v1, win2);
			center += win1;
			sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
			prj->project(v1, win1);
			prj->project(v2, win2);
			sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
			center += win1;
			prj->project(v2, win1);
			prj->project(v0, win2);
			sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
			center += win1;
			center*=0.33333;
			QString str = QString("%1 (%2)").arg(index)
			                                .arg(geodesicGrid->getPartnerTriangle(lev, index));
			glEnable(GL_TEXTURE_2D);
				prj->drawText(font,center[0]-6, center[1]+6, str);
			glDisable(GL_TEXTURE_2D);
		}
	}
	GeodesicSearchBorderIterator it1(*geodesic_search_result, lev);
	while((index = it1.next()) >= 0)
	{
		Vec3d center(0);
		geodesicGrid->getTriangleCorners(lev, index, v0, v1, v2);
		prj->project(v0, win1);
		prj->project(v1, win2);
		center += win1;
		sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
		prj->project(v1, win1);
		prj->project(v2, win2);
		sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
		center += win1;
		prj->project(v2, win1);
		prj->project(v0, win2);
		sPainter.drawLine2d(win1[0],win1[1], win2[0],win2[1]);
		center += win1;
		center*=0.33333;
		QString str = QString("%1 (%2)").arg(index)
		                                .arg(geodesicGrid->getPartnerTriangle(lev, index));
		glEnable(GL_TEXTURE_2D);
			prj->drawText(font,center[0]-6, center[1]+6, str);
		glDisable(GL_TEXTURE_2D);
	}
	
	return 0.;
}