I'm doing some graphing with Direct2D with the mathematical function sqrt(x) (Square root of x) . I have written some code that translates Cartesian to screen co-ordinates and for the most part it is working however I am experiencing some floating point trouble as my "zoom level" increases. I think the value of
fPointsRightXpx[iIndexXpxCount][1] = (fOriginY - ( ((float)dPlotPointsRightFX[iIndexXpxCount][1]) * (fClientAreaY / 2) / (fScaleFactor)));
is rolling over. Is there something I can do to prevent this from occurring? My scale factor is half the visible units of x measured from left to right across the screen.
My code is as follows:
/******************************************/ /*plot points to the right of the origin***/ /******************************************/ //for each increment of x visible to the right of the origin point on the screen //calculate a f(X) and store the x and f(x) values in the dPlotPointsRightFX array //if there is an infinity value set the infinity flag. The default value for iSegmentsPerHalf //is 1000 int iSegmentsPerHalf = 1000; double dDistRightXpx = (fClientAreaX - fOriginX); double dOneGrid = fScaleFactor / 10; double dOneGridpx = (fClientAreaX / 2) / 10; double dDistRightX = (dDistRightXpx / dOneGridpx) * dOneGrid; double dDistLeftXpx = (fOriginX); double dDistLeftX = (dDistLeftXpx / dOneGridpx) * dOneGrid; double dPlotPointsRightFX[10000][2] = { NULL }; int iPlotPointsFXCount = 0; for (x = double(0); x <= double(dDistRightX) + (fScaleFactor / iSegmentsPerHalf); x += fScaleFactor / iSegmentsPerHalf) { //get the current f(x) for the value at x declared in for double dCurrentEquationFX = expression.value(); //store the current x dPlotPointsRightFX[iPlotPointsFXCount][0] = x; if (dCurrentEquationFX==INFINITY) { infinityY = true; } if (dCurrentEquationFX == -INFINITY) { infinityY = true; } //store the calculated f(x) for the current x dPlotPointsRightFX[iPlotPointsFXCount][1] = dCurrentEquationFX; //increment the counter so on the next iteration of for //we move to a new element of the array iPlotPointsFXCount++; } //convert the points from cartesian co-ordinates //to screen co-ordinates and store in fPointsRightXpx int iIndexXpxCount = 0; float fLastIndexXpx = fOriginX; float fPointsRightXpx[10000][2] = { 0.0f }; //set fIndexXpx to the origin point of X on the screen which is movable and is stored in //fOriginX. for (float fIndexXpx = fOriginX; fIndexXpx <= fClientAreaX; fIndexXpx += (fClientAreaX / 2) / iSegmentsPerHalf) { fPointsRightXpx[iIndexXpxCount][0] = fIndexXpx; //Convert the f(x) from cartesian co-ordinates to screen co-ordinates. I'm doing some calculations with the function //sqrt(x) and as the zoom level goes positive and f(x) values move further and further above the screen that the //value stored in fPointsRightXpx[iIndexXpxCount][1] is rolling over. I'm not sure yet what to do to prevent this //from happening but I'm working on it. I know there is a problem because at zoom level 116 there are positive values in //fPointsRightXpx[iIndexXpxCount][1] when there are supposed to be negative ones. For zoom levels less than 116 the function //is working as intended. I'm curious right now why for zoom level 116 this computation is not returning -1.#INF fPointsRightXpx[iIndexXpxCount][1] = (fOriginY - ( ((float)dPlotPointsRightFX[iIndexXpxCount][1]) * (fClientAreaY / 2) / (fScaleFactor))); iIndexXpxCount++; } //plot the points in increments of x to the screen starting at the origin and working to the right iIndexXpxCount = 0; fLastIndexXpx = fOriginX; for (float fIndexXpx = fOriginX; fIndexXpx <= fClientAreaX; fIndexXpx += (fClientAreaX/2)/iSegmentsPerHalf ) { //helper ellipses //ellipse = D2D1::Ellipse(D2D1::Point2F(fIndexXpx, fOriginY), 3, 3); //m_pRenderTarget->FillEllipse(ellipse, m_pCornflowerBlueBrush); //ellipse = D2D1::Ellipse(D2D1::Point2F(fIndexXpx, (dTranslatedY)), 3, 3); //m_pRenderTarget->FillEllipse(ellipse, m_pCornflowerBlueBrush); m_pRenderTarget->DrawLine( D2D1::Point2F(fIndexXpx, fOriginY), D2D1::Point2F(fIndexXpx, fPointsRightXpx[iIndexXpxCount][1]), m_pCornflowerBlueBrush, 0.5 ); if (iIndexXpxCount > 0) { m_pRenderTarget->DrawLine( D2D1::Point2F(fLastIndexXpx, fPointsRightXpx[iIndexXpxCount-1][1]), D2D1::Point2F(fIndexXpx, fPointsRightXpx[iIndexXpxCount][1]), m_pRedBrush, 2.0 ); } fLastIndexXpx = fIndexXpx; iIndexXpxCount ++; } /******************************************/ /*end plot point to the right******************/ /******************************************/
At my "zoomLevel" 116 which is viewing a smaller area of Cartesian space than "zoomLevel" 0 it appears that the value in:
fPointsRightXpx[iIndexXpxCount][1] = (fOriginY - ( ((float)dPlotPointsRightFX[iIndexXpxCount][1]) * (fClientAreaY / 2) / (fScaleFactor)));
is rolling over. Is there something I can do to prevent this from happening? I commented that area of the code describing what is happening.
Also it seems that:
if (dCurrentEquationFX == -INFINITY) { infinityY = true; }
is causing "C4056: overflow in floating-point constant arithmetic". My intent is to check for a negative infinity. I need my program to do something if there is a negative infinity and something different if there is a positive infinity. Is there something that can be done about ""C4056: overflow in floating-point constant arithmetic" in this case?
Thank You!