任意離散點曲線求交點c++實現

已知兩條曲線上的點座標(xi,yi),求二者交點。只需對曲線上線段進行遍歷求線段交點即可,效果如下

                               

下面是c++代碼實現

頭文件 CalLineCrossPt.h

#include "stdafx.h"
#include <vector>
using namespace std;

typedef struct tagPosition
{
	double  x;
	double  y;
	tagPosition(double _x,double _y) { x=_x; y=_y;}
	tagPosition() {};
	bool operator==(const tagPosition & pt) { return (x==pt.x && y==pt.y);} 
}CPosition;

CPosition IsLineCross(CPosition pt1,CPosition pt2,CPosition pt3,CPosition pt4);
void CalTwoLineCrossPoint(CPosition *_coord1,int _num1, CPosition *_coord2, int _num2,CPosition mincal,CPosition maxcal, vector<CPosition> &_crosspts);
void CalMulLinesCrossPoint(CPosition **_coord, int _numline, int *_numpt, vector<CPosition> &_crosspts);

實現文件 CalLineCrossPt.cpp

//================================================================
// 功能:    離散曲線求交點
//
// 作者:    jiangjp   [email protected]
// 單位:    China University of Geosciences (Wuhan)
// 日期:    2013/8/13
//================================================================

#include "stdafx.h"
#include "CalLineCrossPt.h"

void CalMulLinesCrossPoint(CPosition **_coord, int _numline, int *_numpt, vector<CPosition> &_crosspts)
{
	float xmin1,xmax1,xmin2,xmax2;    // 存儲兩條線所在矩形區域的兩個端點(最大最小座標)
	float ymin1,ymax1,ymin2,ymax2;
	CPosition mincal,maxcal;          // 存儲兩條線所在區域重疊形成的矩形區域兩端點(最大最小座標)
	CPosition *linemin=new CPosition[_numline];   // 開闢空間存儲每條測線的x,y值最小點
	CPosition *linemax=new CPosition[_numline];   // 開闢空間存儲每條測線的x,y值最大點

	vector<CPosition> tmpcrosspt;
	for(int i=0;i<_numline;i++){            // 查找每條線最大最小值
		linemin[i].x=_coord[i][0].x;
		linemin[i].y=_coord[i][0].y;
		linemax[i].x=_coord[i][0].x;
		linemax[i].y=_coord[i][0].y;

		for(int j=1;j<_numpt[i];j++){        
			if(_coord[i][j].x>linemax[i].x)  linemax[i].x=_coord[i][j].x;
			if(_coord[i][j].x<linemin[i].x)  linemin[i].x=_coord[i][j].x;
			if(_coord[i][j].y>linemax[i].y)  linemax[i].y=_coord[i][j].y;
			if(_coord[i][j].y<linemin[i].y)  linemin[i].y=_coord[i][j].y;	
		}
	}

	for(int i=0;i<_numline-1;i++){        // 對所有線兩兩循環	
		xmin1=linemin[i].x;               // 獲取第一條線最大最小值點
		xmax1=linemax[i].x;
		ymin1=linemin[i].y;
		ymax1=linemax[i].y;

		for(int j=i+1;j<_numline;j++){ 
			xmin2=linemin[j].x;           // 獲取第二條線最大最小值點
			xmax2=linemax[j].x;
			ymin2=linemin[j].y;
			ymax2=linemax[j].y;

			if(xmin1>xmax2 || xmin2>xmax1 || ymin1>ymax2 || ymin2>ymax2)   // 如果兩線所在區域重疊則不需要計算交點
				continue;
			else
			{
				mincal.x=xmin1>xmin2 ? xmin2 : xmin1;
				mincal.y=ymin1>ymin2 ? ymin2 : ymin1;

				maxcal.x=xmax1>xmax2 ? xmax1 : xmax2;
				maxcal.y=ymax1>ymax2 ? ymax1 : ymax2;
			}

			CalTwoLineCrossPoint(_coord[i],_numpt[i], _coord[j],_numpt[j],mincal, maxcal,tmpcrosspt);

			int numcrosspt=tmpcrosspt.size();
			for (int k=0;k<numcrosspt;k++){
				_crosspts.push_back(tmpcrosspt.at(k));
			}

			tmpcrosspt.clear();
		}
	}

	delete []linemin;
	delete []linemax;
}


void CalTwoLineCrossPoint(CPosition *_coord1,int _num1, CPosition *_coord2, int _num2,CPosition mincal,CPosition maxcal, vector<CPosition> &_crosspts)         // 計算兩條線交點
{     //  _coord1, _coord2分別爲2條線座標,_num1,_num2分別爲2條線上點數目,mincal ,maxcal爲兩條線相交區域的矩形區域兩個角點,_crosspts爲所求的交點

	CPosition pos1,pos2,pos3,pos4;
	bool Found=false;

	for(int i=0;i<_num1-1;i++){        // 對條線相鄰兩點組成的線段依次求交點
		for(int j=0;j<_num2-1;j++){
			pos1=_coord1[i];           //  獲取相鄰點線段
			pos2=_coord1[i+1];
			pos3=_coord2[j];
			pos4=_coord2[j+1];
			// 判斷所求線段是否在兩測線相交區域內,如果在則進行求交點,否則不求
			if(pos1.x>=mincal.x && pos1.x<=maxcal.x && pos1.y>=mincal.y && pos1.y<=maxcal.y      
				&& pos2.x>=mincal.x && pos2.x<=maxcal.x && pos2.y>=mincal.y && pos2.y<=maxcal.y
				&& pos3.x>=mincal.x && pos3.x<=maxcal.x && pos3.y>=mincal.y && pos3.y<=maxcal.y
				&& pos4.x>=mincal.x && pos4.x<=maxcal.x && pos4.y>=mincal.y && pos4.y<=maxcal.y )
			{
				CPosition cpt=IsLineCross(pos1,pos2,pos3,pos4);      //  對兩線段求交點

				if(cpt.x!=-1 && cpt.y!=-1){
					_crosspts.push_back(cpt);
				}
			}
		}
	}
}


CPosition IsLineCross(CPosition pt1,CPosition pt2,CPosition pt3,CPosition pt4)
{                         // 線段pt1pt2用1標記,線段pt3pt4用2標記,如k1,k2
	float xmin1=pt1.x>pt2.x ? pt2.x: pt1.x;
	float xmax1=pt1.x>pt2.x ? pt1.x: pt2.x;
	float ymin1=pt1.y>pt2.y ? pt2.y: pt1.y;
	float ymax1=pt1.y>pt2.y ? pt1.y: pt2.y;

	float xmin2=pt3.x>pt4.x ? pt4.x: pt3.x;
	float xmax2=pt3.x>pt4.x ? pt3.x: pt4.x;
	float ymin2=pt3.y>pt4.y ? pt4.y: pt3.y;
	float ymax2=pt3.y>pt4.y ? pt3.y: pt4.y;

	if(xmin1>xmax2 || xmin2>xmax1 || ymin1>ymax2 || ymin2>ymax2)
		return CPosition(-1,-1);

	if(pt1.x==pt2.x)      // 當線段1斜率不存在
	{
		if(pt3.x==pt4.x){  // 當線段2斜率不存在	
			return CPosition(-1,-1);   // 當交點不存在返回(-1,-1)點
		}
		else              // 當線段2斜率存在  
		{
			float k2=(pt4.y-pt3.y)/(pt4.x-pt3.x);   // 計算線段2斜率
			float x=pt1.x;
			float y=k2*(x-pt3.x)+pt3.y;         // 將線段1的點x座標帶入線段2
			float xmin2=pt3.x>pt4.x ? pt4.x : pt3.x;
			float xmax2=pt3.x>pt4.x ? pt3.x : pt4.x;
			float ymin1=pt1.y>pt2.y ? pt2.y :pt1.y;
			float ymax1=pt1.y>pt2.y ? pt1.y :pt2.y;

			if( x>=xmin2 && x<=xmax2 ){     // 不考慮交點在兩線段端點
				if( y>=ymin1 && y<=ymax1 ){ // 如果所求y在線段1的範圍之內則有交點
					return CPosition(x,y);    // 返回交點
				}
				else{
					return CPosition(-1,-1);
				}
			}
			else{
				return CPosition(-1,-1);
			}
		}
	}
	else   // 如果線段1斜率存在
	{ 
		if(pt3.x==pt4.x){    // 如果線段2斜率不存在
		
			float k1=(pt2.y-pt1.y)/(pt2.x-pt1.x);
			float x=pt3.x;
			float y=k1*(x-pt1.x)+pt1.y;
			float xmin1=pt1.x>pt2.x ? pt2.x :pt1.x;
			float xmax1=pt1.x>pt2.x ? pt1.x :pt2.x;
			float ymin2=pt3.y>pt4.y ? pt4.y :pt3.y;
			float ymax2=pt3.y>pt4.y ? pt3.y :pt4.y;

			if( x>=xmin1 && x<=xmax1 ){  //如果交點位於線段端點視爲沒有交點
				if( y>=ymin2 && y<=ymax2 ){   
					return CPosition(x,y);
				}
				else{
					return CPosition(-1,-1);
				}
			}
			else{
				return CPosition(-1,-1);
			}
		}
		else   // 如果線段1和線段2斜率都存在
		{
			float k1=(pt2.y-pt1.y)/(pt2.x-pt1.x);   // 計算線段1和線段2的斜率
			float k2=(pt4.y-pt3.y)/(pt4.x-pt3.x);

			if(k1==k2)
				return CPosition(-1,-1);

			float x=((pt3.y-pt1.y+k1*pt1.x-k2*pt3.x))/(k1-k2);   // 計算兩線段的交點
			float y=k1*(x-pt1.x)+pt1.y;
			float xmin1=pt1.x>pt2.x ? pt2.x : pt1.x;
			float xmax1=pt1.x>pt2.x ? pt1.x : pt2.x;
			float xmin2=pt3.x>pt4.x ? pt4.x : pt3.x;
			float xmax2=pt3.x>pt4.x ? pt3.x : pt4.x;

			if((x>=xmin1 && x<=xmax1) && (x>=xmin2 && x<=xmax2)){  // 判斷線段交點是否在兩線段x範圍之內
				return CPosition(x,y);
			}
			else{
				return CPosition(-1,-1);
			}
		}
	}
}

主程序 main

// CurveCrossTest.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"

#include <vector>
using namespace std;

#include "CalLineCrossPt.h"

int _tmain(int argc, _TCHAR* argv[])
{
	vector<CPosition> a;

	float line1_x[9]={1, 3, 4.5, 5.5, 6, 6,   8, 9,   10};
	float line1_y[9]={1, 3, 0,   0.5, 2, 2.7, 0, 1.5, 1.3};

	float line2_x[10]={0, 1, 1.3, 3,   4,   5.5, 7, 7, 8, 9};
	float line2_y[10]={1, 3, 3,   1.5, 1.9, 8,   0, 8, 3, 0};

	float line3_x[6]={1, 2, 3, 4, 5, 6};
	float line3_y[6]={6, 6, 6, 6, 6, 5.5};

	int line_num=3;
	int *numpt_line=new int[line_num];
	numpt_line[0]=9;
	numpt_line[1]=10;
	numpt_line[2]=6;
	CPosition **coord=new CPosition *[line_num];
	for (int i=0;i<line_num;i++){
		coord[i]=new CPosition[numpt_line[i]];
	}

	for (int j=0;j<numpt_line[0];j++){
		coord[0][j]=CPosition(line1_x[j],line1_y[j]);
		printf("line1: %f %f\n",coord[0][j].x,coord[0][j].y);
	}

	for (int j=0;j<numpt_line[1];j++){
		coord[1][j]=CPosition(line2_x[j],line2_y[j]);
		printf("line2: %f %f\n",coord[1][j].x,coord[1][j].y);
	}

	for (int j=0;j<numpt_line[2];j++){
		coord[2][j]=CPosition(line3_x[j],line3_y[j]);
		printf("line3: %f %f\n",coord[2][j].x,coord[2][j].y);
	}



	vector<CPosition> crosspts;
    CalMulLinesCrossPoint(coord, line_num, numpt_line, crosspts);

	int N=crosspts.size();

	FILE *fp_m = fopen("crosspt.txt", "wt");

	for (int i = 0; i < N; i++){
		fprintf(fp_m, "%lf %lf\n", crosspts.at(i).x,crosspts.at(i).y);
	}
	fclose(fp_m);

	return 0;
}

程序運行生成交點座標文件crosspt.txt,可用matlab繪製圖像如下

                                   

 

附matlab繪圖代碼

clear all;
clc;
close all;

line1_x=[1, 3, 4.5, 5.5, 6, 6,   8, 9,   10];
line1_y=[1, 3, 0,   0.5, 2, 2.7, 0, 1.5, 1.3];

line2_x=[0, 1, 1.3, 3,   4,   5.5, 7, 7, 8, 9];
line2_y=[1, 3, 3,   1.5, 1.9, 8,   0, 8, 3, 0];

line3_x=[1, 2, 3, 4, 5, 6];
line3_y=[6, 6, 6, 6, 6, 5.5];

crosspt=textread('crosspt.txt');
[numcrosspt,n]=size(crosspt);

figure
h1=plot(line1_x,line1_y,'*-k'); hold on
h2=plot(line2_x,line2_y,'*-b');
h3=plot(line3_x,line3_y,'*-g');
h4=plot(crosspt(:,1),crosspt(:,2),'or','LineWidth',3);
legend([h1 h2 h3 h4],'Line1','Line2','Line3','CrossPoints');

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章