// 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);\ } } }
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); } }
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); } }
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; }
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); }
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); }
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; }
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); }
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); }
//! 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); } } }
// 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); }
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); }
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"); }
// 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(); }
// 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; }
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; }
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)); }
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.; }