void NebulaMgr::drawPointer(const StelCore* core, StelPainter& sPainter) { const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000); const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Nebula"); if (!newSelected.empty()) { const StelObjectP obj = newSelected[0]; Vec3d pos=obj->getJ2000EquatorialPos(core); // Compute 2D pos and return if outside screen if (!prj->projectInPlace(pos)) return; if (StelApp::getInstance().getVisionModeNight()) sPainter.setColor(0.8f,0.0f,0.0f); else sPainter.setColor(0.4f,0.5f,0.8f); texPointer->bind(); sPainter.enableTexture2d(true); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode // Size on screen float size = obj->getAngularSize(core)*M_PI/180.*prj->getPixelPerRadAtCenter(); size+=20.f + 10.f*std::sin(2.f * StelApp::getInstance().getTotalRunTime()); sPainter.drawSprite2dMode(pos[0]-size/2, pos[1]-size/2, 10, 90); sPainter.drawSprite2dMode(pos[0]-size/2, pos[1]+size/2, 10, 0); sPainter.drawSprite2dMode(pos[0]+size/2, pos[1]+size/2, 10, -90); sPainter.drawSprite2dMode(pos[0]+size/2, pos[1]-size/2, 10, -180); } }
// Draw all the Nebulae void NebulaMgr::draw(StelCore* core) { const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000); StelPainter sPainter(prj); StelSkyDrawer* skyDrawer = core->getSkyDrawer(); Nebula::hintsBrightness = hintsFader.getInterstate()*flagShow.getInterstate(); sPainter.enableTexture2d(true); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); // Use a 1 degree margin const double margin = 1.*M_PI/180.*prj->getPixelPerRadAtCenter(); const SphericalRegionP& p = prj->getViewportConvexPolygon(margin, margin); // Print all the nebulae of all the selected zones float maxMagHints = skyDrawer->getLimitMagnitude()*1.2f-2.f+(hintsAmount*1.2f)-2.f; float maxMagLabels = skyDrawer->getLimitMagnitude()-2.f+(labelsAmount*1.2f)-2.f; sPainter.setFont(nebulaFont); DrawNebulaFuncObject func(maxMagHints, maxMagLabels, &sPainter, core, hintsFader.getInterstate()>0.0001); nebGrid.processIntersectingRegions(p, func); if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer()) drawPointer(core, sPainter); }
void Quasar::draw(StelCore* core, StelRenderer* renderer, StelProjectorP projector, StelTextureNew* markerTexture) { StelSkyDrawer* sd = core->getSkyDrawer(); const Vec3f color = sd->indexToColor(BvToColorIndex(bV))*0.75f; Vec3f dcolor = Vec3f(1.2f,0.5f,0.4f); if (StelApp::getInstance().getVisionModeNight()) dcolor = StelUtils::getNightColor(dcolor); float rcMag[2], size, shift; double mag; StelUtils::spheToRect(qRA, qDE, XYZ); mag = getVMagnitude(core, true); if (GETSTELMODULE(Quasars)->getDisplayMode()) { renderer->setBlendMode(BlendMode_Add); renderer->setGlobalColor(dcolor[0], dcolor[1], dcolor[2], 1); markerTexture->bind(); if (labelsFader.getInterstate()<=0.f) { Vec3d win; if(projector->project(XYZ, win)) { renderer->drawTexturedRect(win[0] - 4, win[1] - 4, 8, 8); } } } else { sd->preDrawPointSource(); if (mag <= sd->getLimitMagnitude()) { sd->computeRCMag(mag, rcMag); const Vec3f XYZf(XYZ[0], XYZ[1], XYZ[2]); Vec3f win; if(sd->pointSourceVisible(&(*projector), XYZf, rcMag, false, win)) { sd->drawPointSource(win, rcMag, sd->indexToColor(BvToColorIndex(bV))); } renderer->setGlobalColor(color[0], color[1], color[2], 1.0f); size = getAngularSize(NULL)*M_PI/180.*projector->getPixelPerRadAtCenter(); shift = 6.f + size/1.8f; if (labelsFader.getInterstate()<=0.f) { renderer->drawText(TextParams(XYZ, projector, designation).shift(shift, shift).useGravity()); } } sd->postDrawPointSource(projector); } }
void TelescopeControl::draw(StelCore* core) { const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000); StelPainter sPainter(prj); sPainter.setFont(labelFont); reticleTexture->bind(); foreach (const TelescopeClientP& telescope, telescopeClients) { if (telescope->isConnected() && telescope->hasKnownPosition()) { Vec3d XY; if (prj->projectCheck(telescope->getJ2000EquatorialPos(core), XY)) { //Telescope circles appear synchronously with markers if (circleFader.getInterstate() >= 0) { sPainter.setColor(circleColor[0], circleColor[1], circleColor[2], circleFader.getInterstate()); glDisable(GL_TEXTURE_2D); foreach (double circle, telescope->getOculars()) { sPainter.drawCircle(XY[0], XY[1], 0.5 * prj->getPixelPerRadAtCenter() * (M_PI/180) * (circle)); } glEnable(GL_TEXTURE_2D); } if (reticleFader.getInterstate() >= 0) { glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); sPainter.setColor(reticleColor[0], reticleColor[1], reticleColor[2], reticleFader.getInterstate()); sPainter.drawSprite2dMode(XY[0],XY[1],15.f); glDisable(GL_TEXTURE_2D); } if (labelFader.getInterstate() >= 0) { sPainter.setColor(labelColor[0], labelColor[1], labelColor[2], labelFader.getInterstate()); //TODO: Different position of the label if circles are shown? //TODO: Remove magic number (text spacing) sPainter.drawText(XY[0], XY[1], telescope->getNameI18n(), 0, 6 + 10, -4, false); //Same position as the other objects: doesn't work, telescope label overlaps object label //sPainter.drawText(XY[0], XY[1], scope->getNameI18n(), 0, 10, 10, false); reticleTexture->bind(); } } }
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; }
//! 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); } } }
// 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; }