void CTrack::Rotate(int x, int y, int iStartRotateX, int iStartRotateY) { double fCenterX, fCenterY; m_StartMatrix.Transform(m_ptCenter, fCenterX, fCenterY); CPoint ptStart(iStartRotateX, iStartRotateY); double fStartX, fStartY; m_StartMatrix.Transform(ptStart, fStartX, fStartY); double old_angle = GetAngle(fCenterX, fCenterY, fStartX, fStartY); double new_angle = GetAngle(fCenterX, fCenterY, x, y); double angle = old_angle - new_angle; double anglex = (m_bRotateConstrainX ? 0.0 : angle); double angley = (m_bRotateConstrainY ? 0.0 : angle); m_Matrix = m_StartMatrix; m_Matrix.Rotate(anglex, angley, fCenterX, fCenterY); #ifdef READOUT m_fReadoutAngleX = m_fReadoutAngle1X + angle; m_fReadoutAngleY = m_fReadoutAngle1Y + angle; while (m_fReadoutAngleX < 0) m_fReadoutAngleX += 360.0; while (m_fReadoutAngleY < 0) m_fReadoutAngleY += 360.0; while (m_fReadoutAngleX >= 360.0) m_fReadoutAngleX -= 360.0; while (m_fReadoutAngleY >= 360.0) m_fReadoutAngleY -= 360.0; if (m_fReadoutAngleX != m_fReadoutAngleY) ReadOutF(IDS_ROTATEXY, 2, m_fReadoutAngleX, m_fReadoutAngleY); else ReadOutF(IDS_ROTATE, 1, m_fReadoutAngleX); #endif READOUT }
void MyGesture::removeRedundantEndPoints(vector<Vec4i> newDefects, MyInputImgStruct *m){ /*** * DOC: */ Vec4i Temp; int startidx, endidx, faridx, startidx2, endidx2; float Tolerance = bRect_Width/6; for(int i=0; i<newDefects.size(); i++) { for(int j=i; j<newDefects.size(); j++) { startidx = newDefects[i][0]; Point ptStart(contours[cIdx][startidx]); endidx = newDefects[i][1]; Point ptEnd(contours[cIdx][endidx]); startidx2 = newDefects[j][0]; Point ptStart2(contours[cIdx][startidx2]); endidx2 = newDefects[j][1]; Point ptEnd2(contours[cIdx][endidx2]); if(distanceP2P(ptStart, ptEnd2) < Tolerance) { contours[cIdx][startidx] = ptEnd2; break; } if(distanceP2P(ptEnd, ptStart2) < Tolerance) { contours[cIdx][startidx2] = ptEnd; } } } }//ENDOF Method: removeRedundantEndPoints(newDefects, *m)
//рисует центр прибора использу¤ цвет фона void CAnalogMeter::DrawChord(const CRect& Bounds) { if(!m_swGrid) return; CRect Circle = Bounds; CBrush* pBrushOld = NULL; CPen* pPenOld = NULL; CBrush chord_brush; CPen chord_pen; chord_brush.CreateSolidBrush((~m_colorBGround)&0xFFFFFF); chord_pen.CreatePen(PS_NULL,0,(~m_colorBGround)&0xFFFFFF); int r = m_nRadiusPix / 5; Circle.DeflateRect(r,r,r,r); CPoint ptStart(ROUND(m_nCXPix + m_nRadiusPix*sin(m_dLimitAngleRad)), ROUND(m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad))); CPoint ptEnd(m_nLeftLimitXPix, m_nLeftLimitYPix); pBrushOld = m_dcGrid.SelectObject(&chord_brush); pPenOld = m_dcGrid.SelectObject(&chord_pen); m_dcGrid.Chord(Circle,ptStart,ptEnd); m_dcGrid.SelectObject(pPenOld); m_dcGrid.SelectObject(pBrushOld); }
void MyGesture::getFingerTips(MyInputImgStruct *m){ /*** *@DOC: Gets which of the remaining Defect points are the finger tips * and returns it into the vector FingerTips **/ FingerTips.clear(); int i = 0; vector<Vec4i>::iterator d = Defects[cIdx].begin(); while(d != Defects[cIdx].end()) { Vec4i& v = (*d); int startidx = v[0]; Point ptStart(contours[cIdx][startidx]); int endidx = v[1]; Point ptEnd(contours[cIdx][endidx]); int faridx = v[2]; Point ptFar(contours[cIdx][faridx]); if(i==0){ FingerTips.push_back(ptStart); i++; } FingerTips.push_back(ptEnd); d++; i++; }//ENDOF while() if(FingerTips.size() == 0) { checkForOneFinger(m); } } //ENDOF Method: getFingerTips(MyInputImgStruct *m)
void condefects(vector<Vec4i>convexityDefectsSet, vector<Point> mycontour, Mat& drawing){ for (int cDefIt = 0; cDefIt < convexityDefectsSet.size(); cDefIt++) { int startIdx = convexityDefectsSet[cDefIt].val[0]; Point ptStart(mycontour[startIdx]); int endIdx = convexityDefectsSet[cDefIt].val[1]; Point ptEnd(mycontour[endIdx]); int defectPtIdx = convexityDefectsSet[cDefIt].val[2]; Point ptFar(mycontour[defectPtIdx]); double depth = (double)convexityDefectsSet[cDefIt].val[3] / 256.0f; // see documentation link below why this circle(drawing, ptStart, 5, CV_RGB(255, 0, 0), 2, 8); circle(drawing, ptEnd, 5, CV_RGB(255, 0, 0), 2, 8); circle(drawing, ptFar, 5, CV_RGB(255, 0, 0), 2, 8); // do something with *contour[defectPtIdx]*.. This is e.g. the defect point. } }
BOOL COXSplashWnd::LoadBitmapFile(LPCTSTR lpszFileName, COLORREF crBorder /* = CLR_DEFAULT */, LPPOINT pStartPoint /* = NULL */, BYTE nTolerance /* = 0 */) { if(!m_dib.LoadFile(lpszFileName,TRUE)) return FALSE; // (2) determine bitmap's shaping region m_crBorder = crBorder; m_nTolerance = nTolerance; if(m_crBorder==CLR_NONE) { m_rgn.DeleteObject(); return TRUE; } CPoint ptStart(0,0); if (pStartPoint != NULL) ptStart = *pStartPoint; if (m_crBorder == CLR_DEFAULT) { m_crBorder = m_dib.GetPixel(ptStart); if (m_crBorder == CLR_INVALID) { TRACE0("COXSplashWnd::LoadBitmap(): invalid starting point, (0,0) will be used instead.\r\n"); m_crBorder = m_dib.GetPixel(0,0); } } if(m_crBorder != CLR_INVALID) { m_crBorderR = GetRValue(m_crBorder); m_crBorderG = GetGValue(m_crBorder); m_crBorderB = GetBValue(m_crBorder); if (BuildRegion(ptStart)) return TRUE; } m_rgn.DeleteObject(); return FALSE; }
void MyGesture::eleminateDefects(MyInputImgStruct *m){ /*** * @DOC: Takes all the defect points into vector d. Loops through d and * measures the P2P distance between the Defect Points and decides whether * the Point will be dismissed or kept based on l>0.4lbb and Theta>85' **/ int tolerance = bRect_Height/5; float angleTol = 95; vector<Vec4i> newDefects; int startidx, endidx, faridx; vector<Vec4i>::iterator d = Defects[cIdx].begin(); while(d != Defects[cIdx].end()) { Vec4i& v = (*d); startidx = v[0]; Point ptStart(contours[cIdx][startidx]); endidx = v[1]; Point ptEnd(contours[cIdx][endidx]); faridx = v[2]; Point ptFar(contours[cIdx][faridx]); if((distanceP2P(ptStart, ptFar) > tolerance) && (distanceP2P(ptEnd, ptFar) > tolerance) && (getAngle(ptStart, ptFar, ptEnd) < angleTol)){ if(ptEnd.y > (bRect.y + bRect.height - bRect.height/4)) {/*Do Nothing*/} else if(ptStart.y > (bRect.y + bRect.height - bRect.height/4)) {/*Do Nothing*/} else { newDefects.push_back(v); } } d++; }//ENDOF While() numOfDefects = newDefects.size(); Defects[cIdx].swap(newDefects); removeRedundantEndPoints(Defects[cIdx], m); } //ENDOF Method: eleminateDefects(MyInputImgStruct *m)
void HandDetector::FindConvexityDefects(vector<Vec4i> ConvexityDefectSet, vector<Point> HandContour, Mat& LiveFrame, Point2f COM, int TiltAngle) { vector<Point> FingerTips; Point2f HandCenter; float radius; int fingers=0; //minEnclosingCircle(HandContour,HandCenter,radius); //Rect contourRect = boundingRect(HandContour); //circle(LiveFrame,HandCenter,10,CV_RGB(0,0,255),2,8); //rectangle(LiveFrame, contourRect, Scalar(0,0,255), 3); //vector<Point> palmCircle; for (int i = 0; i < ConvexityDefectSet.size(); i++) { int startId = ConvexityDefectSet[i].val[0]; Point ptStart(HandContour[startId]); int endId = ConvexityDefectSet[i].val[1]; Point ptEnd(HandContour[endId]); int farId = ConvexityDefectSet[i].val[2]; Point ptFar(HandContour[farId]); double depth = (double)((ConvexityDefectSet[i].val[3]) / 256); //for getting real pixel values //cout << "depth" << depth << endl; //display start points //circle(original,ptStart,5,CV_RGB(255,0,0),2,8); //display all end points //circle(original, ptEnd, 5, CV_RGB(255, 255, 0), 2, 8); //display all far points //circle(LiveFrame,ptFar,5,CV_RGB(255,255,0),2,8); //circle(LiveFrame, HandCenter, radius, cv::Scalar(0,255,255),2); if (depth > 10 && ptStart.y < COM.y)// { circle(LiveFrame,ptStart,5,CV_RGB(255,0,0),2,8); //circle(LiveFrame, ptStart, 4, CV_RGB(255, 0,0), 4); FingerTips.push_back(ptStart); fingers++; //palmCircle.push_back(ptStart); } } if(mMouseControl) { InitMouseControl(LiveFrame,FingerTips,COM,TiltAngle); } if(mSwipeON) { Point tempCOM; tempCOM.x = COM.x; tempCOM.y = COM.y; mSwipeGesture.SwipeInit(tempCOM, LiveFrame); } //cout<<"Fingers = "<<fingers<<endl; }
void CMyDlg::OnCreateLine() { // TODO: Add your control notification handler code here acDocManager->lockDocument(curDoc()); int i; int m, n; char *buf = (char*)malloc(20); AcDbObjectId LineId; AcDbLine *pLine = NULL; //块表 AcDbBlockTable *pTb = NULL; //块表记录 AcDbBlockTableRecord *pTbr = NULL; //层表 AcDbLayerTable *pLyr = NULL; //层表记录 AcDbLayerTableRecord* pLyrr = NULL; //图形数据库 AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase(); Acad::ErrorStatus es; CListCtrl *pListCtr = (CListCtrl *)GetDlgItem( IDC_LIST1 ); //设置随机数种子 srand(time(NULL)); //更新数据 UpdateData(TRUE); m_VecSize += m_Edit5; m_xVec.resize(m_VecSize); m_yVec.resize(m_VecSize); //acutPrintf("%d\n", m_Edit1); es = pDb->getLayerTable(pLyr, AcDb::kForWrite); //以写的方式打开层表 es = pDb->getBlockTable(pTb, AcDb::kForRead); //以读的方式打开块表 es = pTb->getAt(ACDB_MODEL_SPACE, pTbr, AcDb::kForWrite);//以写的方式打开块表记录 //创建图层GalLineTest if (!pLyr->has("GalLineTest")) { pLyrr = new AcDbLayerTableRecord; //创建层记录 pLyrr->setName("GalLineTest"); //设置名字 //pLyrr->setColor(color); //设置颜色 //pLyrr->setLineWeight(lnWt); //设置线宽 if (Acad::eOk != pLyr->add(pLyrr)) //添加该层记录到层表 { //添加失败 delete pLyrr; //释放内存 pLyr->close(); //关闭层表 } //关闭层表记录 pLyrr->close(); } //关闭层表 pLyr->close(); //生成点坐标 for (i = 0; i < m_Edit5; ++i) { if ((m_Edit2 != 0) && (m_Edit4 != 0)) { m_xVec[i] = rand() % m_Edit2 + m_Edit1; m_yVec[i] = rand() % m_Edit4 + m_Edit3; } else { m_xVec[i] = 0; m_yVec[i] = 0; } } //遍历点坐标 for (m = 0; m < m_Edit5; ++m) { for (n = (m+1); n < m_Edit5; ++n) { if ((m_xVec[m] != m_xVec[n]) && (m_yVec[m] != m_yVec[n])) { AcGePoint3d ptStart(m_xVec[m], m_yVec[m], 0); AcGePoint3d ptEnd(m_xVec[n], m_yVec[n], 0); pLine = new AcDbLine(ptStart, ptEnd); //pLine->setColor(); pLine->setLayer("GalLineTest"); //创建线段 es = pTbr->appendAcDbEntity(LineId, pLine); if (Acad::eOk == es) { ++m_lLineCnt; } //acutPrintf("%d\n", LineId); sprintf(buf, "%d", LineId); m_ListCtr.InsertItem(m_Row, buf); buf = itoa(pLine->colorIndex(), buf, 10); m_ListCtr.SetItemText(m_Row, 1, buf); buf = itoa(LineLength(m_xVec[m], m_yVec[m], m_xVec[n], m_yVec[n]), buf, 10); m_ListCtr.SetItemText(m_Row, 2, buf); ++m_Row; pLine->close(); //关闭实体 } } } pTbr->close(); //关闭块表记录 pTb->close(); //关闭块表 acDocManager->unlockDocument(curDoc()); free(buf); }
Mat CameraInteraction::Testmm(Mat frame){ vector<vector<Point> > contours; //Update the current background model and get the foreground if(backgroundFrame>0) {bg.operator ()(frame,fore);backgroundFrame--;} else {bg.operator()(frame,fore,0);} //Get background image to display it bg.getBackgroundImage(back); //Enhance edges in the foreground by applying erosion and dilation erode(fore,fore,Mat()); dilate(fore,fore,Mat()); //Find the contours in the foreground findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE); for(int i=0;i<contours.size();i++) //Ignore all small insignificant areas if(contourArea(contours[i])>=5000) { //Draw contour vector<vector<Point> > tcontours; tcontours.push_back(contours[i]); drawContours(frame,tcontours,-1,cv::Scalar(0,0,255),2); //Detect Hull in current contour vector<vector<Point> > hulls(1); vector<vector<int> > hullsI(1); convexHull(Mat(tcontours[0]),hulls[0],false); convexHull(Mat(tcontours[0]),hullsI[0],false); drawContours(frame,hulls,-1,cv::Scalar(0,255,0),2); //Find minimum area rectangle to enclose hand RotatedRect rect=minAreaRect(Mat(tcontours[0])); //Find Convex Defects vector<Vec4i> defects; if(hullsI[0].size()>0) { Point2f rect_points[4]; rect.points( rect_points ); for( int j = 0; j < 4; j++ ) line( frame, rect_points[j], rect_points[(j+1)%4], Scalar(255,0,0), 1, 8 ); Point rough_palm_center; convexityDefects(tcontours[0], hullsI[0], defects); if(defects.size()>=3) { vector<Point> palm_points; for(int j=0;j<defects.size();j++) { int startidx=defects[j][0]; Point ptStart( tcontours[0][startidx] ); int endidx=defects[j][1]; Point ptEnd( tcontours[0][endidx] ); int faridx=defects[j][2]; Point ptFar( tcontours[0][faridx] ); //Sum up all the hull and defect points to compute average rough_palm_center+=ptFar+ptStart+ptEnd; palm_points.push_back(ptFar); palm_points.push_back(ptStart); palm_points.push_back(ptEnd); } //Get palm center by 1st getting the average of all defect points, this is the rough palm center, //Then U chose the closest 3 points ang get the circle radius and center formed from them which is the palm center. rough_palm_center.x/=defects.size()*3; rough_palm_center.y/=defects.size()*3; Point closest_pt=palm_points[0]; vector<pair<double,int> > distvec; for(int i=0;i<palm_points.size();i++) distvec.push_back(make_pair(dist(rough_palm_center,palm_points[i]),i)); sort(distvec.begin(),distvec.end()); //Keep choosing 3 points till you find a circle with a valid radius //As there is a high chance that the closes points might be in a linear line or too close that it forms a very large circle pair<Point,double> soln_circle; for(int i=0;i+2<distvec.size();i++) { Point p1=palm_points[distvec[i+0].second]; Point p2=palm_points[distvec[i+1].second]; Point p3=palm_points[distvec[i+2].second]; soln_circle=circleFromPoints(p1,p2,p3);//Final palm center,radius if(soln_circle.second!=0) break; } //Find avg palm centers for the last few frames to stabilize its centers, also find the avg radius palm_centers.push_back(soln_circle); if(palm_centers.size()>10) palm_centers.erase(palm_centers.begin()); Point palm_center; double radius=0; for(int i=0;i<palm_centers.size();i++) { palm_center+=palm_centers[i].first; radius+=palm_centers[i].second; } palm_center.x/=palm_centers.size(); palm_center.y/=palm_centers.size(); radius/=palm_centers.size(); //Draw the palm center and the palm circle //The size of the palm gives the depth of the hand circle(frame,palm_center,5,Scalar(144,144,255),3); circle(frame,palm_center,radius,Scalar(144,144,255),2); //Detect fingers by finding points that form an almost isosceles triangle with certain thesholds int no_of_fingers=0; for(int j=0;j<defects.size();j++) { int startidx=defects[j][0]; Point ptStart( tcontours[0][startidx] ); int endidx=defects[j][1]; Point ptEnd( tcontours[0][endidx] ); int faridx=defects[j][2]; Point ptFar( tcontours[0][faridx] ); //X o--------------------------o Y double Xdist=sqrt(dist(palm_center,ptFar)); double Ydist=sqrt(dist(palm_center,ptStart)); double length=sqrt(dist(ptFar,ptStart)); double retLength=sqrt(dist(ptEnd,ptFar)); //Play with these thresholds to improve performance if(length<=3*radius&&Ydist>=0.4*radius&&length>=10&&retLength>=10&&max(length,retLength)/min(length,retLength)>=0.8) if(min(Xdist,Ydist)/max(Xdist,Ydist)<=0.8) { if((Xdist>=0.1*radius&&Xdist<=1.3*radius&&Xdist<Ydist)||(Ydist>=0.1*radius&&Ydist<=1.3*radius&&Xdist>Ydist)) line( frame, ptEnd, ptFar, Scalar(0,255,0), 1 ),no_of_fingers++; } } no_of_fingers=min(5,no_of_fingers); qDebug()<<"NO OF FINGERS: "<<no_of_fingers; //mouseTo(palm_center.x,palm_center.y);//Move the cursor corresponding to the palm if(no_of_fingers<4)//If no of fingers is <4 , click , else release // mouseClick(); qDebug()<<"Test"; else // mouseRelease(); qDebug()<<"Hola"; } } } if(backgroundFrame>0) putText(frame, "Recording Background", cvPoint(30,30), FONT_HERSHEY_COMPLEX_SMALL, 0.8, cvScalar(200,200,250), 1, CV_AA); // imshow("Framekj",frame); // imshow("Background",back); return frame; }
static void test_CPoint() { CPoint empty; ok(empty.x == 0, "Expected x to be 0, was %ld\n", empty.x); ok(empty.y == 0, "Expected y to be 0, was %ld\n", empty.y); CPoint ptTopLeft(0, 0); POINT ptHere; ptHere.x = 35; ptHere.y = 95; CPoint ptMFCHere(ptHere); SIZE sHowBig; sHowBig.cx = 300; sHowBig.cy = 10; CPoint ptMFCBig(sHowBig); DWORD dwSize; dwSize = MAKELONG(35, 95); CPoint ptFromDouble(dwSize); ok_point(ptFromDouble, ptMFCHere); CPoint ptStart(100, 100); ptStart.Offset(35, 35); CPoint ptResult(135, 135); ok_point(ptStart, ptResult); ptStart = CPoint(100, 100); POINT pt; pt.x = 35; pt.y = 35; ptStart.Offset(pt); ok_point(ptStart, ptResult); ptStart = CPoint(100, 100); SIZE size; size.cx = 35; size.cy = 35; ptStart.Offset(size); ok_point(ptStart, ptResult); CPoint ptFirst(256, 128); CPoint ptTest(256, 128); ok_point(ptFirst, ptTest); pt.x = 256; pt.y = 128; ok_point(ptTest, pt); ptTest = CPoint(111, 333); nok_point(ptFirst, ptTest); pt.x = 333; pt.y = 111; nok_point(ptTest, pt); ptStart = CPoint(100, 100); CSize szOffset(35, 35); ptStart += szOffset; ok_point(ptResult, ptStart); ptStart = CPoint(100, 100); ptStart += size; ok_point(ptResult, ptStart); ptStart = CPoint(100, 100); ptStart -= szOffset; ptResult = CPoint(65, 65); ok_point(ptResult, ptStart); ptStart = CPoint(100, 100); ptStart -= size; ok_point(ptResult, ptStart); ptStart = CPoint(100, 100); CPoint ptEnd; ptEnd = ptStart + szOffset; ptResult = CPoint(135, 135); ok_point(ptResult, ptEnd); ptEnd = ptStart + size; ok_point(ptResult, ptEnd); ptEnd = ptStart + pt; ptResult = CPoint(433, 211); ok_point(ptResult, ptEnd); ptEnd = ptStart - szOffset; ptResult = CPoint(65, 65); ok_point(ptResult, ptEnd); ptEnd = ptStart - size; ok_point(ptResult, ptEnd); szOffset = ptStart - pt; CSize expected(-233, -11); ok_size(szOffset, expected); ptStart += pt; ptResult = CPoint(433, 211); ok_point(ptResult, ptStart); ptStart -= pt; ptResult = CPoint(100, 100); ok_point(ptResult, ptStart); ptTest = CPoint(35, 35); ptTest = -ptTest; CPoint ptNeg(-35, -35); ok_point(ptTest, ptNeg); RECT rc = { 1, 2, 3, 4 }; CRect rcres = ptStart + &rc; CRect rcexp(101, 102, 103, 104); ok_rect(rcexp, rcres); rcres = ptStart - &rc; rcexp = CRect(-99, -98, -97, -96); ok_rect(rcexp, rcres); }
void MyGraph::DrawSeriesPie(CDC& dc) const { VALIDATE; ASSERT_VALID(&dc); // Determine width of pie display area (pie and space). int nSeriesSpace(0); int seriesCount = GetNonZeroSeriesCount(); int horizontalSpace(0); if (m_saLegendLabels.GetSize()) { // With legend box. horizontalSpace = m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2); int nPieAndSpaceWidth(horizontalSpace / (seriesCount ? seriesCount : 1)); // Height is limiting factor. if (nPieAndSpaceWidth > m_nYAxisHeight - (GAP_PIXELS * 2)) { nSeriesSpace = (m_nYAxisHeight - (GAP_PIXELS * 2)); } else { // Width is limiting factor. nSeriesSpace = nPieAndSpaceWidth; } } else { // No legend box. horizontalSpace = m_nXAxisWidth; // Height is limiting factor. if (m_nXAxisWidth > m_nYAxisHeight * (seriesCount ? seriesCount : 1)) { nSeriesSpace = m_nYAxisHeight; } else { // Width is limiting factor. nSeriesSpace = m_nXAxisWidth / (seriesCount ? seriesCount : 1); } } // Make pies be centered horizontally int xOrigin = m_ptOrigin.x + GAP_PIXELS + (horizontalSpace - nSeriesSpace * seriesCount) / 2; // Create font for labels. CFont fontLabels; int pointFontHeight = max(m_rcGraph.Height() / Y_AXIS_LABEL_DIVISOR, MIN_FONT_SIZE); VERIFY(fontLabels.CreatePointFont(pointFontHeight, _T("Arial"), &dc)); CFont* pFontOld = dc.SelectObject(&fontLabels); ASSERT_VALID(pFontOld); // Draw each pie. int nPie(0); int nRadius((int) (nSeriesSpace * INTERSERIES_PERCENT_USED / 2.0)); POSITION pos(m_olMyGraphSeries.GetHeadPosition()); while (pos) { MyGraphSeries* pSeries = m_olMyGraphSeries.GetNext(pos); ASSERT_VALID(pSeries); // Don't leave a space for empty pies. if (0 < pSeries->GetNonZeroElementCount()) { // Locate this pie. CPoint ptCenter; ptCenter.x = xOrigin + (nSeriesSpace * nPie) + nSeriesSpace / 2; ptCenter.y = m_ptOrigin.y - m_nYAxisHeight / 2; CRect rcPie; rcPie.left = ptCenter.x - nRadius; rcPie.right = ptCenter.x + nRadius; rcPie.top = ptCenter.y - nRadius; rcPie.bottom = ptCenter.y + nRadius; // Draw series label. CSize sizPieLabel(dc.GetTextExtent(pSeries->GetLabel())); VERIFY(dc.TextOut(ptCenter.x - (sizPieLabel.cx / 2), ptCenter.y + nRadius + GAP_PIXELS, pSeries->GetLabel())); // How much do the wedges total to? double dPieTotal(pSeries->GetDataTotal()); // Draw each wedge in this pie. CPoint ptStart(rcPie.left, ptCenter.y); double dRunningWedgeTotal(0.0); for (int nGroup = 0; nGroup < m_saLegendLabels.GetSize(); ++nGroup) { // Ignore empty wedges. if (0 < pSeries->GetData(nGroup)) { // Get the degrees of this wedge. dRunningWedgeTotal += pSeries->GetData(nGroup); double dPercent(dRunningWedgeTotal * 100.0 / dPieTotal); double degrees(360.0 * dPercent / 100.0); // Find the location of the wedge's endpoint. CPoint ptEnd(WedgeEndFromDegrees(degrees, ptCenter, nRadius)); // Special case: a wedge that takes up the whole pie would // otherwise be confused with an empty wedge. bool drawEmptyWedges = false; if (1 == pSeries->GetNonZeroElementCount()) { _ASSERTE(360 == (int)degrees && ptStart == ptEnd && "This is the problem we're correcting"); --ptEnd.y; drawEmptyWedges = true; } // If the wedge is zero size or very narrow, don't paint it. // If pie is small, and wedge data is small, we might get a wedges // where center and both endpoints lie on the same coordinate, // and endpoints differ only in one pixel. GDI draws such pie as whole pie, // so we just skip them instead. int distance = abs(ptStart.x-ptEnd.x) + abs(ptStart.y-ptEnd.y); if (drawEmptyWedges || distance > 1) { // Draw wedge. COLORREF crWedge(m_dwaColors.GetAt(nGroup)); CBrush br(crWedge); CBrush* pBrushOld = dc.SelectObject(&br); ASSERT_VALID(pBrushOld); VERIFY(dc.Pie(rcPie, ptStart, ptEnd)); // Create a region from the path we create. VERIFY(dc.BeginPath()); VERIFY(dc.Pie(rcPie, ptStart, ptEnd)); VERIFY(dc.EndPath()); CRgn * prgnWedge = new CRgn; VERIFY(prgnWedge->CreateFromPath(&dc)); pSeries->SetTipRegion(nGroup, prgnWedge); // Cleanup. dc.SelectObject(pBrushOld); br.DeleteObject(); ptStart = ptEnd; } } } ++nPie; } } // Draw X axis title CSize sizXLabel(dc.GetTextExtent(m_sXAxisLabel)); VERIFY(dc.TextOut(xOrigin + (nSeriesSpace * nPie - sizXLabel.cx)/2, m_ptOrigin.y - m_nYAxisHeight/2 + nRadius + GAP_PIXELS*2 + sizXLabel.cy, m_sXAxisLabel)); VERIFY(dc.SelectObject(pFontOld)); fontLabels.DeleteObject(); }