Gráficos por computadora (1) - Compresión de datos: método de Douglas Puck

**

Experimento 1: Compresión de datos: método de Douglas Puck

**

1.1 Propósito experimental

(1) Compresión de datos maestros: los principios básicos y el proceso de implementación del método de Douglas Puck.
(2) Dominar la declaración, definición y llamada de funciones, así como métodos de llamada anidados.
(3) Dominar la lectura y escritura de documentos.
(4) Dominar la idea de la programación orientada a objetos.

1.2 Contenido del experimento

(1) Leer archivo de texto
(2) MFC o C++ implementar el método Douglas Pugh

1.3 Ideas de algoritmos

Conecte una línea al primer y último punto de cada curva, encuentre las distancias desde todos los puntos a la línea y encuentre la distancia máxima dmax, y use dmax para comparar con la tolerancia D:
(1) Si dmax < D, en este curva (2) Si dmax≥D
, mantenga el punto de coordenadas correspondiente a dmax y tome este punto como el límite, divida la curva en dos partes y use el método repetidamente para estas dos partes.

De la idea básica del algoritmo, se puede ver que el algoritmo es recursivo. Y el núcleo del algoritmo es encontrar la distancia desde el punto hasta la línea.
La función principal del algoritmo es Simp() La función de esta función es determinar si los puntos en la línea se retienen o eliminan de acuerdo con la tolerancia de entrada LimitdDis.
La idea de realización de la función Simp() es conectar los puntos de una curva y los extremos de la curva para formar un triángulo, de la siguiente manera:
inserte la descripción de la imagen aquí

Primero según la fórmula de distancia punto a punto. Encuentre el valor de ABC. Luego aplique la fórmula del coseno
y luego de acuerdo con los valores cosA, cosB, sinA. Calcula la distancia. Realice el cálculo anterior para cada punto, encuentre la distancia de cada punto a ab, tome el valor máximo y compárelo con LimitdDis, si es mayor que la tolerancia, luego divida la curva en dos secciones desde el punto c y repita el primer paso , si es menor que, elimine todos los puntos entre a y b.

1.4 Diagrama de flujo

El diagrama de flujo de esta función es el siguiente,
inserte la descripción de la imagen aquí

1.5 Pasos experimentales

(1) Conecte los dos puntos A y B al principio y al final de la curva para formar una línea recta AB;
(2) Calcule el punto C con la mayor distancia desde el segmento de línea recta en la curva y calcule la distancia d entre él y AB;
(3) Compare esta distancia con el preestablecido El tamaño del umbral umbral, si es menor que el umbral, la línea recta se utiliza como aproximación de la curva, y se completa el procesamiento de la curva.
(4) Si la distancia es mayor que el umbral, use el punto C para dividir la curva en dos secciones AC y BC, y realice los pasos [1~3] en las dos secciones de la curva respectivamente.
(5) Después de procesar todas las curvas, conecte los puntos de división para formar una polilínea, que se utiliza como una aproximación de la curva original.

1.6 Código experimental

(1) Cree un archivo de encabezado ptstruct.h, que define la estructura correspondiente:

structPt
{
    
    
	floatx,y;//x,y坐标
	floatflag;//标识符
};

(2) Escriba un archivo de encabezado de clase (CDglsSF)
dglsf.h y agregue el siguiente código:

public:
	CDgls();
	virtual~CDgls();
	voidReadPtFile();//读点文件
voidDraw(CDC*pdc);//绘图
	intm_LimitDis;//限差
private:
	Ptm_pts[SIZE];//点数组,存入点
	intm_ptsnum;//点个数,用于读文件时获得,最后好操作下标
	voidDrawPts(CDC*pdc);//绘点集
	voidDrawInitLine(CDC*pdc);//绘初始线
	voidDrawSimpLine(CDC*pdc);//绘简化后的线
	doubledist(intptNo1,intptNo2);//计算两点间的距离
	doublesqrdist(intptNo1,intptNo2);//计算两点间的距离的平方,为求cos做准备
	intMaxdist();//返回最大距离的点号
	voidsimple(intptNo1,intptNo2);//简化
	voiddeletept(intptNo1,intptNo2);//删除ptNo1与ptNo2之间的点

(3) El código correspondiente se implementa en el archivo fuente dgisf.cpp:

#include "stdafx.h"
#include "CDGLS_SF.h"
#include "Dgls.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//
#include"math.h"
CDgls::CDgls()
{
    
    
m_LimitDis=50;//设定阈值
}

CDgls::~CDgls()
{
    
    
}
void CDgls::Draw(CDC *pdc)
{
    
    
	
	ReadPtFile();//读取点坐标文件
    DrawPts(pdc);//画点
	DrawInitLine(pdc);//用线连接点坐标
    simple(0,m_ptsnum);//简化点
	DrawSimpLine(pdc);//画出简化后的线
}
void CDgls::DrawInitLine(CDC *pdc)
{
    
    
	int i;
    CPen pen;//定义画笔
	bool bpen=false;//将画笔属性设定为假
	bpen=pen.CreatePen(PS_SOLID,3,RGB(0,0,255));//创建画笔(蓝色)
	if(bpen==true)//判断笔属性
		pdc->SelectObject(&pen);//指向画笔选择的点
	for(i=0;i<m_ptsnum;i++)
	{
    
    
      pdc->MoveTo(m_pts[i].x,m_pts[i].y);//移动到选择的点
	  pdc->LineTo(m_pts[i+1].x,m_pts[i+1].y);//连接线
	}
	pen.DeleteObject();//关闭
}
void CDgls::DrawSimpLine(CDC *pdc)
{
    
    
   int i,iSum=0,lastx,lasty;
    CPen pen;//定义画笔
	bool bpen=false;//将画笔属性设定为假
	bpen=pen.CreatePen(PS_SOLID,5,RGB(255,0,0));//创建画笔(红色)
	if(bpen==true)
		pdc->SelectObject(&pen);//指向画笔选择的点

	for(i=0;i<=m_ptsnum;i++)
	{
    
    
		if(m_pts[i].flag=='T')
		{
    
     	
			iSum++;
			if(iSum<2)//如果点小于2
			{
    
    
				lastx=m_pts[i].x;//将选择的点赋给最后一点x坐标
				lasty=m_pts[i].y;//将选择的点赋给最后一点y坐标
			}
			else
			{
    
    
				pdc->MoveTo(lastx,lasty);//指针移动到最后一点
				pdc->LineTo(m_pts[i].x,m_pts[i].y);//画向下一点
				lastx=m_pts[i].x;//将选择的点赋给最后一点x坐标
				lasty=m_pts[i].y;//将选择的点赋给最后一点y坐标
			}
		}
	}
	pen.DeleteObject();//删除目标
}
void CDgls::DrawPts(CDC *pdc)
{
    
    
	CBrush brush;
	int i;
	brush.CreateSolidBrush(RGB(255,0,0));//创建红色刷子
	pdc->SelectObject(&brush);//指针指向刷子
	for(i=0;i<=m_ptsnum;i++)
	{
    
    
		pdc->Ellipse(m_pts[i].x-13,m_pts[i].y-13,m_pts[i].x+13,m_pts[i].y+13);//画点,半径为13
	}
	brush.DeleteObject();//删除


}
double CDgls::dist(int ptNo1,int ptNo2)
{
    
    
  double d;
  float delx,dely;
  delx=m_pts[ptNo1].x-m_pts[ptNo2].x;//计算x坐标增量
  dely=m_pts[ptNo1].y-m_pts[ptNo2].y;//计算y坐标增量
  d=sqrt(delx*delx+dely*dely);//计算距离
  return d;//返回距离

}
double CDgls::sqrdist(int ptNo1,int ptNo2)
{
    
    
  double f,d;
  f=dist(ptNo1,ptNo2);//获取相邻点的距离
  d=f*f;//计算距离的平方
  return d;//返回距离
}
int CDgls::Maxdist()
{
    
    
 return 0;
}
void CDgls::ReadPtFile()
{
    
    
	FILE *fp;//定义文件指针
	float x,y;
	int i=0;
	if((fp=fopen("F:\\计算机制图原理与方法\\DGLS_SF_DATA.txt","r"))==NULL)//打开文件
		AfxMessageBox("not open file!");
	while(!feof(fp))
	{
    
    
		fscanf(fp,"%f%f",&x,&y);//读取文件
        m_pts[i].x=x;//x值赋予x坐标
		m_pts[i].y=y;//y值赋予y坐标
		m_pts[i].flag='T';//属性改成真
		i++;
	}
	m_ptsnum=i-2;//点的计数-2
	fclose(fp);//关闭文件
}
void CDgls::simple(int ptNo1,int ptNo2)
{
    
    
	double a,b,c,cosA,cosB,sinA,maxdis,curdis;
	double a1,b1,c1;//求平方
	int i=0,maxNO=0;
	if(ptNo2-ptNo1>=2)//点个数要大于2个
	{
    
    
		maxdis=0.00;
		c1=sqrdist(ptNo1,ptNo2);
		c=dist(ptNo1,ptNo2);
		i=ptNo1+1;
		while(i<ptNo2)
		{
    
    
			curdis=0.00;
			b1=sqrdist(ptNo1,i);//计算两点间的距离的平方,为求cos做准备
			a1=sqrdist(ptNo2,i);//计算两点间的距离的平方,为求cos做准备
			b=dist(ptNo1,i);//计算两点间的距离
			a=dist(ptNo2,i);//计算两点间的距离
			cosA=(b1+c1-a1)/(2*b*c);//计算cos
			cosB=(a1+c1-b1)/(2*a*c);//计算cos
			//cosA=(b*b+c*c-a*a)/(2*b*c);
			//cosB=(a*a+c*c-b*b)/(2*a*c);
			sinA=(float)sqrt(1-cosA*cosA);
			
			if((cosA==0) || (cosB==0))
			{
    
    
				if(cosA==0)
				{
    
    
					curdis=b;
				}
				else
				{
    
    
					curdis=a;
				}
			}
			else
			{
    
    
				curdis=b*sinA;
			}
			if(maxdis<=curdis)
			{
    
    
				maxdis=curdis;
				maxNO=i;
			}
			i++;
		}
		if(maxdis>=m_LimitDis)
		{
    
    
			simple(ptNo1,maxNO);//简化
			simple(maxNO,ptNo2);//简化
		}
		else
		{
    
    
			deletept(ptNo1,ptNo2);//删除点
		}
	}
	
}
void CDgls::deletept(int ptNo1,int ptNo2)
{
    
    
	int c=ptNo1+1;
	while(c<ptNo2)
	{
    
    
		m_pts[c].flag='F';//属性改成假
		c++;
	}
}

1.7 Visualización de resultados experimentales

La línea azul es el punto en la curva original, y la línea roja es la línea que conecta los puntos simplificados.Cuanto mayor sea D, mayor será la simplificación, como se muestra en la siguiente figura.
m_LimitDis=100m_LimitDis=200m_LimitDis=50

Supongo que te gusta

Origin blog.csdn.net/chengzilhc/article/details/106728463
Recomendado
Clasificación