📄 mathsubs.cpp
字号:
#include "stdafx.h"
//#include "CubSurface.h"
#include "drawcli.h"
#include "math.h"
#include "SideLine.h"
//#define MIN_DISTANCE 10 //最小跨度
/*
判断“点”是否在任意多边形内:
本算法采用射线追踪法:
过待测点的一条射线与多边形边的交点的个数,若为奇数,则在
多边形内,否则为外部。
实际上,我们只关心交点个数,没必要真正求出射线与边的交点。
改进的射线与边判断是否相交的方法如下:
被检测的点P(x,y)向y= -∞方向作射线。对边PiPi+1按以下顺序检测:
若(y>=yi and y>=yi+1) //边在被测点P的下方
{
//在左右之间或过右端点:
若( xi<x 且 x<=xi+1 ) 或 ( xi+1<x 且 x<=xi ) )
射线与边相交。
}
else 若(y>=yi || y>=yi+1) //被测点P在边的上、下之间
{
//在左右之间或过右端点:
若( (xi<x 且 x<=xi+1 ) 或 ( xi+1<x 且 x<=xi ) )
{
求射线(垂线)与边的交点yc
若yc<=y
射线与边相交。
}
}
*/
BOOL insideEx(float *XPV, float *YPV, int N, double x, double y, int &LOCP)
{
if (N<3) return 0;
float xi,yi, xj,yj;
xi = XPV[N-1];
yi = YPV[N-1];
int p=0;
LOCP = 0;
for (int i=0; i<N; i++)
{
xj = XPV[i];
yj = YPV[i];
if (y>=yi && y>=yj) //点在上面
{
//在左右方向之间或过右边顶点(线段其它部分在左边)
if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
p++;
}
if (y==yi && y==yj) LOCP = 1;
}
else if (y>=yi || y>=yj) //点在上、下之间
{
if (xi==xj && x==xi) //在垂线上
{
LOCP = 1;
p++;
}
else if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
//计算射线(垂直向下的直线)与边的交点:
//由边的直线方程:yc = y1+(xc-x1)*(y1-y2)/(x1-x2);
//令xc为待测点x
double yd = yi+(x-xi)*(yi-yj)/(xi-xj);
if (yd<=y)
{
if (yd==y) LOCP = 1;
p++;
}
}
}
xi = xj;
yi = yj;
}
return (p & 1);
}
//整数数组的实现:
BOOL insideEx(int *XPV, int *YPV, int N, int x, int y, int &LOCP)
{
if (N<3) return 0;
int xi,yi, xj,yj;
xi = XPV[N-1];
yi = YPV[N-1];
int p=0;
LOCP = 0;
for (int i=0; i<N; i++)
{
xj = XPV[i];
yj = YPV[i];
if (y>=yi && y>=yj) //点在上面
{
//在左右方向之间或过右边顶点(线段其它部分在左边)
if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
p++;
}
if (y==yi && y==yj) LOCP = 1;
}
else if (y>=yi || y>=yj) //点在上、下之间
{
if (xi==xj && x==xi) //在垂线上
{
LOCP = 1;
p++;
}
else if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
//计算射线(垂直向下的直线)与边的交点:
//由边的直线方程:yc = y1+(xc-x1)*(y1-y2)/(x1-x2);
//令xc为待测点x
float yd = yi+(float)(x-xi)*(yi-yj)/(xi-xj);
if (yd<=y)
{
if (yd==y) LOCP = 1;
p++;
}
}
}
xi = xj;
yi = yj;
}
return (p & 1);
}
//点数组的实现:
BOOL insideEx(CPoint *XYP, int N, int x, int y, int &LOCP)
{
if (N<3) return 0;
int xi,yi, xj,yj;
xi = XYP[N-1].x;
yi = XYP[N-1].y;
int p=0;
LOCP = 0;
for (int i=0; i<N; i++)
{
xj = XYP[i].x;
yj = XYP[i].y;
if (y>=yi && y>=yj) //点在上面
{
//在左右方向之间或过右边顶点(线段其它部分在左边)
if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
p++;
}
if (y==yi && y==yj) LOCP = 1;
}
else if (y>=yi || y>=yj) //点在上、下之间
{
if (xi==xj && x==xi) //在垂线上
{
LOCP = 1;
p++;
}
else if ( ( xi<x && x<=xj ) || ( xj<x && x<=xi) )
{
//计算射线(垂直向下的直线)与边的交点:
//由边的直线方程:yc = y1+(xc-x1)*(y1-y2)/(x1-x2);
//令xc为待测点x
float yd = yi+(float)(x-xi)*(yi-yj)/(xi-xj);
if (yd<=y)
{
if (yd==y) LOCP = 1;
p++;
}
}
}
xi = xj;
yi = yj;
}
return (p & 1);
}
//计算曲线的长度(整数):
double calcLength(int *x, int *y, int n)
{
int l;
double lm;
lm = 0;
for (l=0; l<n-1; l++)
{
lm = lm + sqrt( (double)(x[l+1]-x[l])*(x[l+1]-x[l])
+ (double)(y[l+1]-y[l])*(y[l+1]-y[l]) );
}
return lm;
}
//计算曲线的长度(浮点):
double calcLength(float *x, float *y, int n)
{
int l;
double lm;
lm = 0;
for (l=0; l<n-1; l++)
{
lm = lm + sqrt( (x[l+1]-x[l])*(x[l+1]-x[l])
+ (y[l+1]-y[l])*(y[l+1]-y[l]) );
}
return lm;
}
//判断是否相交(数学意义的直线)
int testCrossed(float xa, float ya, float xb, float yb,
float xA, float yA, float xB, float yB,
float &xc, float &yc)
{
double A1 = ya-yb;
double B1 = xb-xa;
double C1 = -xa*A1-ya*B1;
double A2 = yA-yB;
double B2 = xB-xA;
double C2 = -xA*A2-yA*B2;
double CC=A2*B1-A1*B2;
if (CC==0) return 0;
xc = (float)((B2*C1-B1*C2)/CC);
yc = (float)((A1*C2-A2*C1)/CC);
return 1;
}
//判断是否相交于第一条直线:
int testCross1( float xa, float ya, float xb, float yb,
float xA, float yA, float xB, float yB,
float &xc, float &yc)
{
if (! testCrossed( xa, ya, xb, yb, xA, yA, xB, yB, xc, yc)) return 0;
//是否落在第一条线上
if (xa<xb)
{
if ( xc<xa || xc>xb) return 0;
}
else
{
if ( xc>xa || xc<xb) return 0;
}
if (ya<yb)
{
if ( yc<ya || yc>yb) return 0;
}
else
{
if ( yc>ya || yc<yb) return 0;
}
return 1;
}
//判断是否相交于第二条直线
int testCross2( float xa, float ya, float xb, float yb,
float xA, float yA, float xB, float yB,
float &xc, float &yc)
{
if (! testCrossed( xa, ya, xb, yb, xA, yA, xB, yB, xc, yc)) return 0;
//是否落在第二条线上
if (xA<xB)
{
if ( xc<xA || xc>xB) return 0;
}
else
{
if ( xc>xA || xc<xB) return 0;
}
if (yA<yB)
{
if ( yc<yA || yc>yB) return 0;
}
else
{
if ( yc>yA || yc<yB) return 0;
}
return 1;
}
//判断是否相交点在二条直线上:
int testCross( float xa, float ya, float xb, float yb,
float xA, float yA, float xB, float yB,
float &xc, float &yc)
{
if (! testCrossed( xa, ya, xb, yb, xA, yA, xB, yB, xc, yc)) return 0;
if (xa<xb)
{
if (xc<xa || xc>xb) return 0;
}
else
{
if (xc>xa || xc<xb) return 0;
}
if (ya<yb)
{
if (yc<ya || yc>yb) return 0;
}
else
{
if (yc>ya || yc<yb) return 0;
}
if (xA<xB)
{
if (xc<xA || xc>xB) return 0;
}
else
{
if (xc>xA || xc<xB) return 0;
}
if (yA<yB)
{
if (yc<yA || yc>yB) return 0;
}
else
{
if (yc>yA || yc<yB) return 0;
}
return 1;
}
//判断是否相交点在二条直线上:
int testCross( long xa, long ya, long xb, long yb,
long xA, long yA, long xB, long yB,
long &xc, long &yc)
{
float _xc = (float)xc;
float _yc = (float)yc;
return testCross((float)xa, (float)ya, (float)xb, (float)yb,
(float)xA, (float)yA, (float)xB, (float)yB,
_xc,_yc);
}
//直线是否与多边型相交:
int crossXY(float *x, float *y,
float X, float Y,
float X1,float Y1,
float &XC, float &YC, int np)
{
//判断是否相交于在二条直线上:
for (int i=0; i<np; i++)
{
int t= testCross(
x[i], y[i],
x[i+1], y[i+1],
X, Y,
X1, Y1,
XC, YC);
if (t) return 1;
}
return 0;
}
/*
判断一个点,是否与一条曲线(多线段)的垂直交线的交点,落在该曲线上.
一个约束条件是,点到各个线段的距离(垂直距离)要小于给定的值。
*/
BOOL isVCrossAtLine(CPoint po, CPoint ps[], int nps, int &smin, int &ipos,
double &x0, double &y0)
{
CPoint p1,p2;
double A2,B2,C2;
double s;
double xk;
double A,B,C;
int issel = 0;
nps--;
for (int j=0; j<nps; j++)
{
p1 = ps[j];
p2 = ps[j+1];
A = p1.y - p2.y;
B = p2.x - p1.x;
if (A==0 && B==0)
{
if (po.x == p1.x && po.y==p1.y)
{
ipos = j;
return true;
}
continue;
}
C = -p1.x*A - p1.y*B;
//点到直线的距离:
s = fabs(A*po.x + B*po.y +C)/sqrt( B*B+ A*A);
if (s>=smin ) continue;
if (A==0) //水平线段,则过鼠标点的垂线为垂直线
{
x0 = po.x;
y0 = p1.y;
if (p1.x < p2.x)
{
if (po.x<p1.x || po.x>p2.x)
continue;
}
else
{
if (po.x<p2.x || po.x>p1.x)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
}
else if (B==0)
{
x0 = p1.x;
y0 = po.y;
if (p1.y < p2.y)
{
if (po.y<p1.y || po.y>p2.y)
continue;
}
else
{
if (po.y<p2.y || po.y>p1.y)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
}
else
{
//点斜式
xk = (float)B/A;
A2 = xk;
B2 = -1;
C2 = po.y - xk * po.x;
x0 = - (C *B2-C2*B )/(A *B2-A2*B );
y0 = - (C2*A -C *A2)/(A *B2-A2*B );
if (p1.x < p2.x)
{
if (x0<p1.x || x0>p2.x)
continue;
}
else
{
if (x0<p2.x || x0>p1.x)
continue;
}
if (p1.y < p2.y)
{
if (y0<p1.y || y0>p2.y)
continue;
}
else
{
if (y0<p2.y || y0>p1.y)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
} //end of dip-line
} //end for
return issel;
}
/*
分离的X,Y整数数组版本
*/
BOOL isVCrossAtLine(int pox, int poy, int psx[], int psy[],
int nps, int &smin, int &ipos,
double &x0, double &y0)
{
int p1x, p1y;
int p2x, p2y;
double A2,B2,C2;
double s;
double xk;
double A,B,C;
int issel = 0;
nps--;
for (int j=0; j<nps; j++)
{
p1x = psx[j];
p1y = psy[j];
p2x = psx[j+1];
p2y = psy[j+1];
A = p1y - p2y;
B = p2x - p1x;
if (A==0 && B==0)
{
if (pox == p1x && poy==p1y)
{
ipos = j;
smin = 0;
return true;
}
continue;
}
C = -p1x*A - p1y*B;
//点到直线的距离:
s = fabs(A*pox + B*poy +C)/sqrt( B*B+ A*A);
if (s>=smin ) continue;
if (A==0) //水平线段,则过鼠标点的垂线为垂直线
{
x0 = pox;
y0 = p1y;
if (p1x < p2x)
{
if (pox<p1x || pox>p2x)
continue;
}
else
{
if (pox<p2x || pox>p1x)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
}
else if (B==0)
{
x0 = p1x;
y0 = poy;
if (p1y < p2y)
{
if (poy<p1y || poy>p2y)
continue;
}
else
{
if (poy<p2y || poy>p1y)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
}
else
{
//点斜式
xk = B/A;
A2 = xk;
B2 = -1;
C2 = poy - xk * pox;
if (A *B2-A2*B==0)
{
j=j;
}
x0 = - (C *B2-C2*B )/(A *B2-A2*B );
y0 = - (C2*A -C *A2)/(A *B2-A2*B );
if (p1x < p2x)
{
if (x0<p1x || x0>p2x)
continue;
}
else
{
if (x0<p2x || x0>p1x)
continue;
}
if (p1y < p2y)
{
if (y0<p1y || y0>p2y)
continue;
}
else
{
if (y0<p2y || y0>p1y)
continue;
}
ipos = j;
smin = (int)s;
issel = true;
} //end of dip-line
} //end for
return issel;
}
/*
分离的X,Y浮点数组版本
*/
BOOL isVCrossAtLine(float pox, float poy, float psx[], float psy[],
int nps, float &smin, int &ipos,
double &x0, double &y0)
{
float p1x, p1y;
float p2x, p2y;
double A2,B2,C2;
double s;
double xk;
double A,B,C;
int issel = 0;
nps--;
for (int j=0; j<nps; j++)
{
p1x = psx[j];
p1y = psy[j];
p2x = psx[j+1];
p2y = psy[j+1];
A = p1y - p2y;
B = p2x - p1x;
if (A==0 && B==0)
{
if (pox == p1x && poy==p1y)
{
ipos = j;
smin = 0;
return true;
}
continue;
}
C = -p1x*A - p1y*B;
//点到直线的距离:
s = fabs(A*pox + B*poy +C)/sqrt( B*B+ A*A);
if (s>=smin ) continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -