?? contourtracer.cpp
字號(hào):
// ContourTracer.cpp: implementation of the CContourTracer class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ContourGenerator.h"
#include "ContourTracer.h"
#include "2DMemAllocator.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CContourTracer::CContourTracer()
{
m_ppGridData = NULL;
m_pCurveList = NULL;
m_currentCurveLine = NULL;
xSide = NULL;
ySide = NULL;
}
CContourTracer::~CContourTracer()
{
FreeMemory();
}
BOOL CContourTracer::ExecuteTracing(float value)
{
ASSERT( m_gridDataInfo.cols != 0 ); //在調(diào)用該函數(shù)之前必須調(diào)用SetGridDataInfo()函數(shù)設(shè)置網(wǎng)格數(shù)據(jù)信息
if( value < m_gridDataInfo.zMin && value > m_gridDataInfo.zMax )
{
return FALSE;
}
m_valueTracing = value;
//1.為xSide和ySide分配內(nèi)存空間
AllocateMemory();
//2.掃描網(wǎng)格縱橫邊,內(nèi)插等值點(diǎn)
//該函數(shù)之中,在計(jì)算等值點(diǎn)時(shí),發(fā)現(xiàn)追蹤值與網(wǎng)格點(diǎn)上的數(shù)據(jù)相同時(shí),
//在計(jì)算前,會(huì)都數(shù)據(jù)做修正(加上一小偏移值)
InterpolateTracingValue();
//3.先追蹤開(kāi)曲線
TracingNonClosedContour();
//4.再追蹤閉曲線
TracingClosedContour();
//5.釋放空間
//FreeMemory();
return TRUE;
}
void CContourTracer::AllocateMemory()
{// 分配xSide,ySide空間
int cols = m_gridDataInfo.cols;
int rows = m_gridDataInfo.rows;
if( xSide == NULL )
{
//網(wǎng)格中存在rows*(cols-1)條橫邊,所有需要為xSide分配rows*(cols-1)空間就行
C2DMemAllocator::AllocMemory2D(xSide,rows,cols-1/*not cols*/);
}
if( ySide == NULL )
{
//網(wǎng)格中存在(rows-1)*cols條縱邊,所有需要為ySide分配(rows-1)*cols空間就行
C2DMemAllocator::AllocMemory2D(ySide,rows-1/*not rows*/,cols);
}
}
void CContourTracer::FreeMemory()
{
if( xSide != NULL )
{
C2DMemAllocator::FreeMemory2D(xSide);
xSide = NULL;
}
if( ySide != NULL )
{
C2DMemAllocator::FreeMemory2D(ySide);
ySide = NULL;
}
}
//-----消除網(wǎng)格交點(diǎn)奇異Z值------
//在自動(dòng)網(wǎng)格邊上追蹤等值點(diǎn)時(shí),有時(shí)會(huì)遇到網(wǎng)格交點(diǎn)上的Z值與追蹤的等值線值相等的情況;
//如果不對(duì)這種情況進(jìn)行處理,網(wǎng)格追蹤算法就會(huì)出現(xiàn)錯(cuò)誤,一般的處理如下:
//將網(wǎng)格交點(diǎn)上的z值加或減一個(gè)修正值,來(lái)消除奇異點(diǎn)的影響
//void CContourTracer::AmendingData(BOOL bForTracing /*是否為追縱算法而修正數(shù)據(jù)*/,
// float fValueTracing/*所要追蹤的等值線值*/)
//{
//
// ASSERT( m_ppGridData!=NULL );
//
// int i,j;
//
// float shift = 0.001f; //修正值
//
// if(bForTracing)
// {
// //若把與所要追蹤的值相同的加修正值
// for(i=0; i<m_gridDataInfo.rows; i++)
// {
// for(j=0; j<m_gridDataInfo.cols; j++)
// {
// if( m_ppGridData[i][j] == fValueTracing )
// m_ppGridData[i][j] += shift; //should changing back!!
// }
// }
// }
// else
// {
// float shiftVal = fValueTracing + shift;
//
// for(i=0; i<m_gridDataInfo.rows; i++)
// {
// for(j=0; j<m_gridDataInfo.cols; j++)
// {
// if( m_ppGridData[i][j] == shiftVal )
// m_ppGridData[i][j] -= shift; //restore original data
// }
// }
// }
//}
//掃描網(wǎng)格的縱、橫邊,并線性插值計(jì)算等值點(diǎn)的情況
//將各邊上的等值點(diǎn)情況存儲(chǔ)于xSide和ySide數(shù)組中,
// xSide存儲(chǔ)所有橫邊上的等值線情況, ySide存儲(chǔ)所有縱邊上的等值點(diǎn)情況
//在插值計(jì)算時(shí),對(duì)『與追蹤值相等的數(shù)據(jù)』要進(jìn)行修正處理后才計(jì)算,但在做修正處理時(shí)不要改變?cè)瓉?lái)的數(shù)據(jù)
void CContourTracer::InterpolateTracingValue()
{
/* 網(wǎng)格點(diǎn)標(biāo)識(shí)如下:
(i+1,j)·--------·(i+1,j+1)
| |
| |
| |
| |
(i,j) ·--------·(i,j+1)
i:表示行號(hào)(向上增加)
j:表示列號(hào)(向右增加)
標(biāo)識(shí)一個(gè)網(wǎng)格交點(diǎn)時(shí),行號(hào)在前,列號(hào)在右,如:(i,j)
*/
/* xSide,ySide中存儲(chǔ)r值,(w為追蹤值)
對(duì)于網(wǎng)格橫邊,r = (w - pData[i][j]) / (pData[i][j+1]-pData[i][j]);
對(duì)于網(wǎng)格縱邊,r = (w - pData[i][j]) / (pData[i+1][j]-pData[i][j]);
由于浮點(diǎn)運(yùn)算的誤差,xSide[i][j],ySide[i][j]有可能等于1.0或0.0
考慮如下情況:
1。當(dāng)追蹤值與網(wǎng)格點(diǎn)上的值很接近(但不相等)時(shí),由于運(yùn)算誤差,就會(huì)等于1.0
比如追蹤0值時(shí),遇到如下邊:
20 ·--------·-0.00000016 此邊上有0值,但計(jì)算 (0-20)/(-0.00000016-20) == 1.0
2。當(dāng)網(wǎng)格邊上兩端點(diǎn)上的值相差很懸殊時(shí)。
比如追蹤2值,遇到如下邊:
1.70141E+038 ·--------·1 此邊上有2值,計(jì)算(2-1.70141E+038) / (1-1.70141E+038) == 1.0
網(wǎng)格邊上有等值點(diǎn)時(shí),理論上比例值不會(huì)等于0或1;
但由于計(jì)算誤差,我們?cè)谒惴ㄖ信袛鄷r(shí),認(rèn)為0或1也是有等值點(diǎn)的
所以xSide,ySide中存儲(chǔ)的值是[0,1]的閉區(qū)間,不是(0,1)的開(kāi)區(qū)間
*/
ASSERT( m_ppGridData!=NULL );
ASSERT( xSide != NULL );
ASSERT( ySide != NULL );
int i,j;
int rows = m_gridDataInfo.rows;
int cols = m_gridDataInfo.cols;
float w = m_valueTracing;
float** pData = m_ppGridData;
float H1,H2; //分別記錄一條邊的兩個(gè)點(diǎn)上的數(shù)據(jù)值
float flag;
float shift = 0.001f; //修正值
/* 掃描并計(jì)算橫邊上的等值點(diǎn),有rows*(cols-1)條橫邊需要掃描*/
for(i=0; i<rows ; i++)
{
for(j=0;j<cols-1;j++)
{
/*考查橫邊(i,j)上的左交點(diǎn)(i,j)上的值pData[i][j]
和右交點(diǎn)(i,j+1)的值pData[i][j+1]*/
// if( pData[i][j] == pData[i][j+1] )
// {
// // -2表示此邊無(wú)等值點(diǎn)
// xSide[i][j] = -2.0f;
// }
// else
// {
// xSide[i][j] = (w - pData[i][j]) / ( pData[i][j+1] - pData[i][j] );
//
// if( ( xSide[i][j] <= 0 ) || ( xSide[i][j] >= 1 ) )
// xSide[i][j] = -2.0f;
// }
H1 = pData[i][j]; H2 = pData[i][j+1];
if( H1 == H2 )
{
xSide[i][j] = -2.0f;
}
else
{
flag = (w-H1) * (w-H2);
if( flag > 0 )
{
xSide[i][j] = -2.0f;
}
else if( flag < 0 )
{
xSide[i][j] = (w-H1) / (H2-H1) ;
ASSERT(xSide[i][j]>=0 && xSide[i][j]<=1.0f);
}
else if( flag == 0)
{//其中有一值與追蹤值w相等,則修正之(加上一小值偏移量)
if( H1 == w )
{
H1 += shift;
}
else
{
H2 += shift;
}
xSide[i][j] = (w-H1) / (H2-H1) ;
// ASSERT(xSide[i][j]>=0 && xSide[i][j]<=1.0f);
}
else
{
ASSERT(FALSE);
}
}
}
}
/* 掃描并計(jì)算縱邊上等值點(diǎn),有(rows-1)*cols條縱邊需要掃描*/
for(i=0; i<rows-1;i++)
{
for(j=0; j<cols; j++)
{
/*考查縱邊(i,j)上的下交點(diǎn)(i,j)上的值pData[i][j]
和上交點(diǎn)(i+1,j)的值pData[i+1][j]*/
// if( pData[i][j] == pData[i+1][j] )
// {
// /* -2表示此邊無(wú)等值點(diǎn),或已追蹤過(guò),以后不再考慮*/
// ySide[i][j] = -2.0f;
// }
// else
// {
// ySide[i][j] = (w - pData[i][j]) / ( pData[i+1][j] - pData[i][j] );
//
// if( ( ySide[i][j] <= 0 ) || ( ySide[i][j] >= 1 ) )
// ySide[i][j] = -2.0f;
// }
H1 = pData[i][j];
H2 = pData[i+1][j];
if( H1 == H2 )
{
ySide[i][j] = -2.0f;
}
else
{
flag = (w-H1) * (w-H2);
if( flag > 0 )
{
ySide[i][j] = -2.0f;
}
else if( flag < 0 )
{/*
網(wǎng)格邊上有等值點(diǎn)時(shí),存儲(chǔ)的值∈[0,1] (閉區(qū)間)
*/
ySide[i][j] = (w-H1) / (H2-H1) ;
ASSERT(ySide[i][j]>=0 && ySide[i][j]<=1.0f);
}
else if( flag == 0 )
{//如果其中有一值與追蹤值w相等,則修正之(加上一小值偏移量)
if( H1 == w )
{
H1 += shift;
}
else
{
H2 += shift;
}
ySide[i][j] = (w-H1) / (H2-H1) ;
// ASSERT(ySide[i][j]>=0 && ySide[i][j]<=1.0f);
}
else
{
ASSERT(FALSE);
}
}
}
}
}
inline void CContourTracer::CalcAndSaveOnePointCoord(int i, int j, BOOL bHorizon,float &x, float &y)
{
/*static*/ float deltX = (m_gridDataInfo.xMax - m_gridDataInfo.xMin) / ( m_gridDataInfo.cols - 1 );
/*static*/ float deltY = (m_gridDataInfo.yMax - m_gridDataInfo.yMin) / ( m_gridDataInfo.rows - 1 );
// should not be static, because diffirent input data has diffirent xyMin Max
if( bHorizon )
{//在橫邊上
x = m_gridDataInfo.xMin + ( j + xSide[i][j] ) * deltX;
y = m_gridDataInfo.yMin + i * deltY;
}
else
{//在縱邊上
x = m_gridDataInfo.xMin + j * deltX;
y = m_gridDataInfo.yMin + ( i + ySide[i][j] ) * deltY;
}
//Saving Coord
CGeoPoint point(x,y);
m_currentCurveLine->Add(point);
}
//當(dāng)下一個(gè)等值點(diǎn)找到后做相應(yīng)的處理
void CContourTracer::HandlingAfterNextPointFounded(int i, int j, BOOL bHorizon)
{//參數(shù)說(shuō)明:i,j分別是等值點(diǎn)所在邊的編號(hào),bHorizon指明所在邊是橫邊還是縱邊
//當(dāng)下一個(gè)等值點(diǎn)找到后做相應(yīng)的處理,如下:
//1.記錄該等值點(diǎn)的i,j
//2.計(jì)算并保存該等值點(diǎn)的坐標(biāo)
//3.標(biāo)志該等值點(diǎn)所在邊的已經(jīng)搜索過(guò)
//驗(yàn)證i∈[0,rows-1], j∈[0,cols-1]
ASSERT( i>=0 && i<=m_gridDataInfo.rows-1 && j>=0 && j<=m_gridDataInfo.cols-1 );
//1.
NextPoint.i = i;
NextPoint.j = j;
NextPoint.bHorV = bHorizon;
//2.
CalcAndSaveOnePointCoord(i,j,bHorizon,NextPoint.x,NextPoint.y);
//3.
if( NextPoint.bHorV )
{
xSide[i][j] = -2.0f; //已經(jīng)追蹤過(guò)
}
else
{
ySide[i][j] = -2.0f; //已經(jīng)追蹤過(guò)
}
}
void CContourTracer::TracingNextPoint()
{
/*
1.先確定出等值線的前進(jìn)方向(自下向上、由左向右、自上向下、由右向左,其中之一)
2.再追蹤下一個(gè)等值點(diǎn)
前進(jìn)方向可以如下判定:
if( 當(dāng)前點(diǎn).行號(hào) > 前一點(diǎn).行號(hào) )
{
下---->上
}
else if( 當(dāng)前點(diǎn).列號(hào) > 前一點(diǎn).列號(hào) )
{
左---->右
}
else if( 當(dāng)前點(diǎn)在橫邊上 )
{
上---->下
}
else
{
右---->左
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -