/** Draw the robot position in the original image sequence. Need to know the entire camera calibration (and more) for this... **/ QImage showRobotTrackUndistorted( IplImage* img, ///< original avi image const RobotTracker* tracker, ///< robot tracker int flip ///< flip output coords? ) { // Convert from IplImage to QImage... const QSize imgSize( img->width,img->height ); QImage qimage = QImage( imgSize, QImage::Format_RGB888 ); CvMat mtxWrapper; cvInitMatHeader( &mtxWrapper, img->height, img->width, CV_8UC3, qimage.bits() ); cvConvertImage( img, &mtxWrapper, flip ); // Now draw on top of the QImage... QPainter painter(&qimage); painter.setRenderHint(QPainter::Antialiasing, true); QPen penRed( QColor(255,0,0) ); QPen penBlue( QColor(0,0,255) ); QPen penRedGreen( QColor(255,255,0) ); CvPoint2D32f offset = *tracker->GetOffsetParams(); const CameraCalibration* cal = tracker->GetCalibration(); // Draw the path taken so far (but each point needs to be converted from plane, to image co-ordinates) const TrackHistory& history = tracker->GetHistory(); if ( history.size() > 1 ) { CvPoint2D32f pos = history[0].GetPosition(); pos.x += offset.x; pos.y += offset.y; CvPoint2D32f oldPosf = cal->PlaneToImage( pos ); if ( flip ) { oldPosf.y = img->height - oldPosf.y; } CvPoint oldPos = cvPoint( ( int )oldPosf.x, ( int )oldPosf.y ); for ( unsigned int i = 1; i < history.size(); ++i ) { double tdiff = fabs( history[i].t() - history[i - 1].t() ); if ( tdiff > 2000.0 / 3.0 ) { pos = history[i].GetPosition(); pos.x += offset.x; pos.y += offset.y; oldPosf = cal->PlaneToImage( pos ); if ( flip ) { oldPosf.y = img->height - oldPosf.y; } oldPos = cvPoint( ( int )oldPosf.x, ( int )oldPosf.y ); } else { pos = history[i].GetPosition(); pos.x += offset.x; pos.y += offset.y; CvPoint2D32f newPosf = cal->PlaneToImage( pos ); if ( flip ) { newPosf.y = img->height - newPosf.y; } CvPoint newPos = cvPoint( ( int )newPosf.x, ( int )newPosf.y ); //CvScalar colour; //float err = expf( -powf( (1.f-history[i].GetError())/0.5f, 4) ); //float col = 255*err; //colour = CV_RGB( 255,0,0 ); //cvScalar( col, col, 255 ); // if ( err > 0.35f ) // { // colour = cvScalar(0,255,0); // } // else // { // colour = cvScalar(0,0,255); // } //cvLine( img, oldPos, newPos, colour, 1, CV_AA ); penRed.setWidth( 2 ); painter.setPen( penRed ); painter.drawLine( oldPos.x, oldPos.y, newPos.x, newPos.y ); oldPos = newPos; } } } return qimage; }
bool SingleVarStats::OperateModelGraphic(CMdlGraphicWnd &Wnd, CMdlGraphic &Grf) { const COLORREF White = COLORREF(RGB(255,255,255)); const COLORREF Black = COLORREF(RGB(0,0,0)); const COLORREF Blue = COLORREF(RGB(0,0,255)); const COLORREF Cyan = COLORREF(RGB(0,255,255)); const COLORREF Red = COLORREF(RGB(255,0,0)); const COLORREF Green = COLORREF(RGB(0,255,0)); switch (Wnd.m_eTask) { case MGT_Create: Wnd.m_pWnd->SetWindowPos(NULL, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOZORDER); break; case MGT_Size: Wnd.m_pWnd->Invalidate(); break; case MGT_Move: break; case MGT_EraseBkgnd: Wnd.m_bReturn = 0; break; case MGT_Paint: Wnd.m_pPaintDC->FillSolidRect(Wnd.m_ClientRect, Black); Wnd.m_pPaintDC->SetTextColor(Green); CPen penWhite(PS_SOLID, 0, White); CPen penGreen(PS_SOLID, 0, Green); CPen penRed(PS_SOLID, 0, Red); CBrush brushRed(Red); int nTextSize = Wnd.m_TextSize.y; int nBorderSpace = nTextSize; int nTextSpace = 4; int nAxesSpace = 4; #if (_MSC_VER >= 1400) int nTopSpace = nBorderSpace + nTextSize; int nAxesLeft = nBorderSpace + nTextSize + nTextSpace + nAxesSpace; #else int nTopSpace = nBorderSpace + nTextSize + nAxesSpace; int nAxesLeft = nBorderSpace + nAxesSpace; #endif int nCheckSize = nAxesSpace - 1; int minSpace = 10; //Draw axes: int nAxesTop = nTopSpace, nAxesBottom = Wnd.m_ClientRect.bottom - (nBorderSpace + 2 * nTextSize + nTextSpace + nAxesSpace), nAxesRight = Wnd.m_ClientRect.right - (nBorderSpace); if (nAxesBottom - nAxesTop <= 0 || nAxesRight - nAxesLeft <= 0) break; POINT axes[] = { {nAxesLeft, nAxesTop}, {nAxesLeft, nAxesBottom}, {nAxesRight, nAxesBottom} }; CPen* oldPen = Wnd.m_pPaintDC->SelectObject(&penGreen); Wnd.m_pPaintDC->Polyline(axes, 3); int nArrowSize = 3; POINT ArrowTop[] = { {nAxesLeft, nAxesTop - nArrowSize}, {nAxesLeft - nArrowSize, nAxesTop}, {nAxesLeft + nArrowSize, nAxesTop}, {nAxesLeft, nAxesTop - nArrowSize} }; POINT ArrowSide[] = { {nAxesRight + nArrowSize, nAxesBottom}, {nAxesRight, nAxesBottom - nArrowSize}, {nAxesRight, nAxesBottom + nArrowSize}, {nAxesRight + nArrowSize, nAxesBottom} }; Wnd.m_pPaintDC->Polygon(ArrowTop, 4); Wnd.m_pPaintDC->Polygon(ArrowSide, 4); //Draw blocks, and % values above blocks. float blockWidth = (float)(nAxesRight - nAxesLeft) / (lHistoCount + 2); int MaxCount = 0; for (int i = 0; i < lHistoCount + 2; i++) if (pHistoBucketCounts[i] > MaxCount) MaxCount = pHistoBucketCounts[i]; int FullScale = (int)(MaxCount * 1.1); if (FullScale < 1) FullScale = 1; //Avoid divide by zero errors. int nAxesHeight = nAxesBottom - nAxesTop; if (MaxCount > 0) { Wnd.m_pPaintDC->SelectObject(&penRed); CBrush* oldBrush = Wnd.m_pPaintDC->SelectObject(&brushRed); Wnd.m_pPaintDC->SetTextAlign(TA_BOTTOM | TA_CENTER); for (int i = 0; i < lHistoCount + 2; i++) { if (i == 1) { Wnd.m_pPaintDC->SelectObject(&penWhite); Wnd.m_pPaintDC->SelectObject(oldBrush); } if (i == lHistoCount + 1) { Wnd.m_pPaintDC->SelectObject(&penRed); Wnd.m_pPaintDC->SelectObject(&brushRed); } Wnd.m_pPaintDC->Rectangle( nAxesLeft + (int)(i*blockWidth), nAxesBottom - (nAxesHeight * pHistoBucketCounts[i]) / FullScale, nAxesLeft + (int)((i+1)*blockWidth), nAxesBottom); if (lRecordsSinceHistoReset > 0) { double d = 100.0 * pHistoBucketCounts[i] / lRecordsSinceHistoReset; int perc = d - (int)d < 0.5 ? (int) d : (int) d + 1; CString percent; percent.Format("%i%%", perc); Wnd.m_pPaintDC->TextOut(nAxesLeft + (int)((i + 0.5)*blockWidth), nAxesBottom - (nAxesHeight * pHistoBucketCounts[i]) / FullScale - 1, percent); } } Wnd.m_pPaintDC->SelectObject(&penWhite); Wnd.m_pPaintDC->SelectObject(oldBrush); } //Draw checks and axis values: double offset = 0, scale = 1; if (TagCnvFamily[nTagCnvUsed].Valid()) { offset = TagCnvFamily[nTagCnvUsed].Offset(); scale = TagCnvFamily[nTagCnvUsed].Scale(); } Wnd.m_pPaintDC->SetTextAlign(TA_TOP | TA_CENTER); Wnd.m_pPaintDC->SelectObject(&penGreen); int lastLabel = 0; for (int i = 1; i < lHistoCount + 2; i++) { POINT Checkline[] = { {nAxesLeft + (int)(i * blockWidth), nAxesBottom}, {nAxesLeft + (int)(i * blockWidth), nAxesBottom + nCheckSize}}; Wnd.m_pPaintDC->Polyline(Checkline, 2); CString value; if (pHistoBucketBorders[i] < 100) //Because the %.2g formatting doesn't work like it should value.Format("%.2g", pHistoBucketBorders[i] * scale + offset); else if (pHistoBucketBorders[i] < 1E4) value.Format("%.0f", pHistoBucketBorders[i] * scale + offset); else value.Format("%.1e", pHistoBucketBorders[i] * scale + offset); if (nAxesLeft + (int)(i * blockWidth) - lastLabel > Wnd.m_pPaintDC->GetTextExtent(value).cx / 2 + minSpace) { Wnd.m_pPaintDC->TextOut(nAxesLeft + (int)(i * blockWidth), nAxesBottom + nAxesSpace, value); lastLabel = nAxesLeft + (int)(i * blockWidth) + Wnd.m_pPaintDC->GetTextExtent(value).cx / 2; } } Wnd.m_pPaintDC->TextOut(nAxesLeft + (int)((0.5) * blockWidth), nAxesBottom + nAxesSpace + nTextSize, "UR"); Wnd.m_pPaintDC->TextOut(nAxesLeft + (int)((lHistoCount + 1.5) * blockWidth), nAxesBottom + nAxesSpace + nTextSize, "OR"); //Draw labels: CString xLabel, yLabel; if (TagCnvFamily[nTagCnvUsed].Valid() && strcmp(TagCnvFamily[nTagCnvUsed].Name(), "") != 0) xLabel.Format("Value (%s)", TagCnvFamily[nTagCnvUsed].Name()); else xLabel.Format("Value"); yLabel.Format("Count"); Wnd.m_pPaintDC->SetTextAlign(TA_BOTTOM | TA_CENTER); Wnd.m_pPaintDC->TextOut((nAxesLeft + nAxesRight) / 2, Wnd.m_ClientRect.bottom - nBorderSpace, xLabel); #if (_MSC_VER >= 1400) int oldMode = Wnd.m_pPaintDC->SetGraphicsMode(GM_ADVANCED); XFORM rotation = { 0, -1, 1, 0, 0, 0}; XFORM identity = { 1, 0, 0, 1, 0, 0}; BOOL setTransformResult = Wnd.m_pPaintDC->SetWorldTransform(&rotation); Wnd.m_pPaintDC->SetTextAlign(TA_TOP | TA_CENTER); Wnd.m_pPaintDC->TextOut(-(nAxesTop + nAxesBottom) / 2, nBorderSpace, yLabel); Wnd.m_pPaintDC->SelectObject(oldPen); Wnd.m_pPaintDC->SetWorldTransform(&identity); Wnd.m_pPaintDC->SetGraphicsMode(oldMode); #else Wnd.m_pPaintDC->SetTextAlign(TA_TOP | TA_LEFT); Wnd.m_pPaintDC->TextOut(nAxesLeft, nBorderSpace, yLabel); #endif } return true; }
//----------------------------------------------------------------------------- //! //----------------------------------------------------------------------------- void tTideGraph::paintEvent( QPaintEvent* pEvent ) { tTideCurrentGraphBase::paintEvent( pEvent ); int w = contentsRect().width(); int h = contentsRect().height(); QPainter p( this ); p.setRenderHint( QPainter::Antialiasing, true ); p.setClipRect( contentsRect() ); QRect r( QPoint(0,0), contentsRect().size() ); // lets translate the painter so we can work with a 0,0 origin p.save(); p.translate( contentsRect().topLeft() ); //###### 1) Paint background and the daylight area if(m_SunRiseX <= m_SunSetX) { // left night p.fillRect( 0, 0, m_SunRiseX, h, palette().dark() ); // day p.fillRect( m_SunRiseX, 0, m_SunSetX - m_SunRiseX, h, palette().light() ); // right night p.fillRect( m_SunSetX, 0, w - m_SunSetX, h, palette().dark() ); } else if(m_SunRiseX > m_SunSetX) { // left day p.fillRect( 0, 0, m_SunSetX, h, palette().light() ); // night p.fillRect( m_SunSetX, 0, m_SunRiseX - m_SunSetX, h, palette().dark() ); // right day p.fillRect( m_SunRiseX, 0, w - m_SunRiseX, h, palette().light() ); } //###### 2) Add legend backgrounds QColor c = palette().text().color(); c.setAlpha( 127 ); p.fillRect( 0, h - BOTTOM_MARGIN_HEIGHT, w, BOTTOM_MARGIN_HEIGHT, QBrush( c ) ); p.fillRect( 0, 0, LEFT_MARGIN_WIDTH, h, palette().base() ); // we have finished doing work with a 0,0 origin p.restore(); //###### 3) Left depth legend and grid lines p.rotate(-90); p.setRenderHint( QPainter::Antialiasing, false ); c.setAlpha( 63 ); QPen pen( QBrush( c ), 0 ); qreal rangeDiv = GetRangeDivision( tConvert::Instance()->ToUser(UNITS_DEPTH, m_HeightUnits, static_cast<float>(m_GraphConfig.m_DeltaY)) ); float stepSize = tConvert::Instance()->UserToBase( UNITS_DEPTH, static_cast<float>(rangeDiv) ); stepSize = tConvert::Instance()->BaseToSpecifiedUnits(UNITS_DEPTH, m_HeightUnits, stepSize); for( qreal pxY = 0, strY = 0; pxY <= m_GraphConfig.m_MaxY; pxY += stepSize, strY += rangeDiv ) { p.setPen( palette().text().color() ); p.drawText(RotatedTextELeftMargin(0, pxY, 40), Qt::AlignCenter, QString("%1").arg(strY) ); p.setPen( pen ); p.drawLine(RotatedGraphToPixel(0, pxY), RotatedGraphToPixel(1, pxY)); } for( qreal pxY = 0, strY = 0; pxY >= m_GraphConfig.m_MinY; pxY -= stepSize, strY += rangeDiv ) { p.setPen( palette().text().color() ); p.drawText(RotatedTextELeftMargin(0, pxY, 40), Qt::AlignCenter, QString("%1").arg(strY) ); p.setPen( pen ); p.drawLine(RotatedGraphToPixel(0, pxY), RotatedGraphToPixel(1, pxY)); } p.rotate(90); p.drawLine( QPointF( GraphToPixel(0.25, 0).x(), 0 ), QPointF( GraphToPixel(0.25, 0).x(), h ) ); p.drawLine( QPointF( GraphToPixel(0.5, 0).x(), 0 ), QPointF( GraphToPixel(0.5, 0).x(), h ) ); p.drawLine( QPointF( GraphToPixel(0.75, 0).x(), 0 ), QPointF( GraphToPixel(0.75, 0).x(), h ) ); p.setRenderHint( QPainter::Antialiasing, true ); //###### 4) Graph and fill the tides spline QPainterPath path; path.moveTo( GraphToPixel(0, 0) ); for( int i = 0; i < m_TideHeights.size(); ++i ) { // source data is in 10 minute intervals => 1/144 of a day path.lineTo( GraphToPixel( m_TideHeights.at(i).x(), m_TideHeights.at(i).y() ) ); } // Close the path path.lineTo( GraphToPixel(1, 0) ); path.lineTo( GraphToPixel(0, 0) ); //###### 5) Fill graph path QLinearGradient gradient(0,0,0,h); QColor endColor = palette().highlight().color(); endColor.setAlpha( 191 ); QColor midColor = palette().highlight().color().lighter( 130 ); midColor.setAlpha( 191 ); gradient.setColorAt(0.0, endColor); gradient.setColorAt(0.1, endColor); gradient.setColorAt(0.5, midColor); gradient.setColorAt(0.9, endColor); gradient.setColorAt(1.0, endColor); p.fillPath(path, gradient); p.save(); QPen penGraph( palette().base().color() ); penGraph.setWidth(2); p.setPen(penGraph); p.drawPath(path); p.restore(); //###### 6) Draw over with text p.setPen( palette().base().color() ); qSort(m_TideExtremes); for( int i = 0; i < m_TideExtremes.size(); ++i ) { // Convert time into decimal qreal timePos = GetTimeF( m_TideExtremes.at(i).first ); // Draw on height (and compensate for user units) float convertedHeight = tConvert::Instance()->ToUser(UNITS_DEPTH, m_HeightUnits, static_cast<float>(m_TideExtremes.at(i).second) ); QString unitsString = tConvert::Instance()->GetUnitsString( UNITS_DEPTH ); QString heightString = QString("%1 ").arg(convertedHeight, 2, 'f', qAbs(convertedHeight) > 1 ? 1 : 2) + unitsString; QString timeString = m_TideExtremes.at(i).first.toString( tSystemSettings::Instance()->TimeFormatString() ); QRect boundRectHeight = TextBoundingRect( timePos, 0, fontMetrics().width( heightString ), eBottomMarginHeight ); QRect boundRectTime = TextBoundingRect( timePos, 0, fontMetrics().width( timeString ), eBottomMarginTime ); QPen curPen = p.pen(); if( i < m_TideExtremes.size() - 1 ) { if( m_TideExtremes[i].second < m_TideExtremes[i+1].second ) { p.setPen(Qt::red); } } else { if( m_TideExtremes[i].second < m_TideExtremes[i-1].second ) { p.setPen(Qt::red); } } p.drawText( boundRectHeight, Qt::AlignCenter, heightString ); p.drawText( boundRectTime, Qt::AlignCenter, timeString ); p.setPen(curPen); // Draw on time // Draw triangle } //####### 7) Draw on the sun times //(SUN) p.setPen( palette().text().color() ); if(m_SunRiseTime.isValid()) { QString riseString = tr("Sunrise") + " " + m_SunRiseTime.toString( tSystemSettings::Instance()->TimeFormatString() ); QRect boundSunRise = TextBoundingRect( GetTimeF( m_SunRiseTime ), m_GraphConfig.m_MinY, fontMetrics().width( riseString ), eSunTime); p.drawText(boundSunRise, Qt::AlignCenter, riseString ); } if(m_SunSetTime.isValid()) { QString sunsetString = tr("Sunset") + " " + m_SunSetTime.toString( tSystemSettings::Instance()->TimeFormatString() ); QRect boundSunSet = TextBoundingRect( GetTimeF( m_SunSetTime ), m_GraphConfig.m_MinY, fontMetrics().width( sunsetString ), eSunTime); p.drawText(boundSunSet, Qt::AlignCenter, sunsetString ); } //####### 8) Draw the time and height for the present time tDateTime currentDateTime = tDateTime::currentDateTime(); //QDateTime does not know time zone / local time offset. if( m_UseUTCTime ) { currentDateTime = currentDateTime.toUTC(); } if(m_ActiveDate.date() == currentDateTime.date()) { qreal currentTime = GetTimeF( currentDateTime.time() ); qreal height = GetHeightAtTime( currentTime ); float convertedHeight = tConvert::Instance()->ToUser(UNITS_DEPTH, m_HeightUnits, static_cast<float>(height) ); QString unitsString = tConvert::Instance()->GetUnitsString( UNITS_DEPTH ); QString heightString = QString("%1 ").arg(convertedHeight, 2, 'f', qAbs(convertedHeight) > 1 ? 1 : 2) + unitsString; QString timeString = currentDateTime.time().toString( tSystemSettings::Instance()->TimeFormatString() ); QRect boundCurrentHeight = TextBoundingRect( currentTime, 0, fontMetrics().width( heightString ), eCurrentHeight ); QRect boundCurrentTime = TextBoundingRect( currentTime, 0, fontMetrics().width( timeString ), eCurrentTime ); p.setPen( palette().text().color() ); p.drawText( boundCurrentHeight, Qt::AlignCenter, heightString ); p.drawText( boundCurrentTime, Qt::AlignCenter, timeString ); QPen penRed(Qt::red); p.setPen(penRed); p.setRenderHint( QPainter::Antialiasing, false ); p.drawLine( GraphToPixel(currentTime, m_GraphConfig.m_MinY).toPoint(), GraphToPixel(currentTime, m_GraphConfig.m_MaxY).toPoint() - QPoint(0,1) ); } }