已知两条曲线上的点坐标(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 1034378054@qq.com
// 单位: 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');