Qt中計算座標的一些簡單函式介面
該文章原地址為:http://blog.csdn.net/chenxipu123/article/details/50380172
這些演算法非常的實用,對自己一些簡單的繪圖很有效果
//存放一些常用的函式或者一些常用功能的實現演算法;
//////////////////////////////////////////////////////////////////////////
//圓周率;
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//////////////////////////////////////////////////////////////////////////
//該函式返回的角度為從第一條線到第二條線逆時針方向選擇所經過的角度,範圍為0 - 360,不包括360度。
//QLineF::angleTo(const QLineF&)
//該函式是從x軸0點從發,沿正方向的水平線到直線的角度,範圍0 - 360,不包括360。
//QLineF::angle()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//已知螢幕座標系上兩點,且這兩點不在的x座標不相等,則他們所形成的 y = ax + b 形式的直線方程中:
//a = (y2 - y1) / (x2 - x1), b = (x2 * y1 - x1 * y2) / ( x2 - x1)
//注意:y1、y2的值為兩點的y值的相反數,如果要計算第三點的座標,所得到的第三點y值同樣需要再取其相反數作為螢幕座標的真正的值
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//計算平方的函式;
double square(const double num){return num * num;}
//////////////////////////////////////////////////////////////////////////
//計算螢幕上面兩個點之間的直線距離的函式,需要與計算平方函式同時使用;
double TwoPtDistance(const QPointF& pt1, const QPointF& pt2)
{return sqrt(double(square(pt2.x() - pt1.x()) + square(pt2.y() - pt1.y())));}
//////////////////////////////////////////////////////////////////////////
//************************************
// Method: caculateThirdPtFromTwoPoint
// Returns: 返回計算出的第三個點座標;
// Qualifier: 根據兩個點的位置和第三個點與第一個點連線的長度與前兩個點連線逆時針旋轉的角度,計算出第三個點的位置;
// Parameter: QPointF pt1 第一個點座標,該點也是關鍵點;
// Parameter: QPointF pt2 第二個點座標
// Parameter: double nLength第一個點與第三個點之間的直線距離;
// Parameter: double nAngle第一個點和第二個點的連線 與 第一個點和第三個點的連線之間的夾角,逆時針旋轉,使用的是弧度。
//************************************
QPointF caculateThirdPtFromTwoPoint(const QPointF& pt1, const QPointF& pt2, const double nLength, const double nAngle)
{
double x1 = pt1.x();
double y1 = pt1.y();
double x2 = pt2.x();
double y2 = pt2.y();
double x3 = 0.0, y3 = 0.0;
x3 = x1 + nLength * cos(double(atan2(y2 - y1, x2 - x1)) - nAngle);
y3 = y1 + nLength * sin(double(atan2(y2 - y1, x2 - x1)) - nAngle);
return QPointF(x3, y3);
}
//////////////////////////////////////////////////////////////////////////
//Qt中獲取文字的寬度和高度;
QFontMetrics fm;
QPainter p(this);
fm = p.fontMetrics();
fm.width("12345");//獲取字串的寬度;
fm.ascent() + fm.descent();//獲取字串的高度;
fm.ascent();//一個字的基線到最頂部的距離;
fm.descent();//一個字的基線到最底部的距離;
//////////////////////////////////////////////////////////////////////////
//獲取兩個點的中心點座標;
QPointF GetMiddlePoint(const QPointF& pt1, const QPointF& pt2)
{
return QPointF((pt2.x() + pt1.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0);
}
//////////////////////////////////////////////////////////////////////////
//************************************
// Method: GetDoubleArrowLine
// Qualifier: 根據一條直線的兩個端點計算出雙箭頭直線的箭頭座標;
// Parameter: const QPointF& pt1直線的第一個端點;
// Parameter: const QPointF& pt2直線的第二個端點;
// Parameter: QVector<QPointF> & arrow1返回的直線的第一個點處的箭頭座標;
// Parameter: QVector<QPointF> & arrow2返回的直線的第二個點處的箭頭座標;
//************************************
void GetDoubleArrowLine(const QPointF& pt1, const QPointF& pt2, QVector<QPointF>& arrow1, QVector<QPointF>& arrow2)
{
float x1 = pt1.x(); //lastPoint 起點
float y1 = pt1.y();
float x2 = pt2.x(); //endPoint 終點
float y2 = pt2.y();
float l = 10.0; //箭頭的那長度
float a = 30.0 / 180.0 * M_PI; //箭頭與線段角度
int nAbs = 1; //用於控制箭頭的正反向;
if(3 * l > TwoPtDistance(pt1, pt2))
nAbs = -1;
float x3 = x2 - nAbs * l * cos(atan2((y2 - y1), (x2 - x1)) - a);
float y3 = y2 - nAbs * l * sin(atan2((y2 - y1), (x2 - x1)) - a);
float x4 = x2 - nAbs * l * sin(atan2((x2 - x1), (y2 - y1)) - a);
float y4 = y2 - nAbs * l * cos(atan2((x2 - x1), (y2 - y1)) - a);
float x5 = x1 - nAbs * l * cos(atan2((y1 - y2), (x1 - x2)) - a);
float y5 = y1 - nAbs * l * sin(atan2((y1 - y2), (x1 - x2)) - a);
float x6 = x1 - nAbs * l * sin(atan2((x1 - x2), (y1 - y2)) - a);
float y6 = y1 - nAbs * l * cos(atan2((x1 - x2), (y1 - y2)) - a);
arrow2.append(QPointF(x3, y3));
arrow2.append(QPointF(x2, y2 - 0.5));
arrow2.append(QPointF(x4, y4));
arrow1.append(QPointF(x5, y5));
arrow1.append(QPointF(x1, y1 - 0.5));
arrow1.append(QPointF(x6, y6));
}
//////////////////////////////////////////////////////////////////////////
//************************************
// Method: 計算一個點到一條直線的垂直點座標;
// Returns: QPointF 返回垂直點的座標;
// Parameter: const QPointF & pt1 直線的第一個點;
// Parameter: const QPointF & pt2 直線的第二個點;
// Parameter: const QPointF pt3 目標點;
//************************************
QPointF caculateCrossPosPtToLine(const QPointF& pt1, const QPointF& pt2, const QPointF pt3)
{
QPointF ptCross;
//垂直的情況;
if (pt1.x() == pt2.x())
{
ptCross.setX(pt1.x());
ptCross.setY(pt3.y());
}
else
{
qreal x1 = pt1.x(), y1 = pt1.y();
qreal x2 = pt2.x(), y2 = pt2.y();
qreal x3 = pt3.x(), y3 = pt3.y();
qreal ss1 = square(x1 - x3) + square(y1 - y3);
qreal ss2 = square(x2 - x3) + square(y2 - y3);
qreal ll = square(x1 - x2) + square(y1 - y2);
qreal a = ss1 - ss2;
qreal t = a / (2.0 * ll) + 0.5;
ptCross = QLineF(pt1, pt2).pointAt(t);
}
return ptCross;
}
//////////////////////////////////////////////////////////////////////////
//************************************
// Method: 計算一個點一條直線的垂直距離;
// Returns: qreal返回垂直距離;
// Parameter: const QPointF & pt1 直線的第一個點;
// Parameter: const QPointF & pt2 直線的第二個點;
// Parameter: const QPointF pt3 目標點;
//************************************
qreal caculateCrossLengthPtToLine(const QPointF& pt1, const QPointF& pt2, const QPointF pt3)
{
//直線垂直的情況;
if (pt1.x() == pt2.x())
{
return pt3.x() - pt1.x();
}
else
{
qreal angle = QLineF(pt1, pt2).angleTo(QLineF(pt1, pt3));
qreal leng = sin(angle / 180 * M_PI) * (QLineF(pt1, pt3).length());
return leng;
}
}
//************************************
// Method: 計算兩條直線的相交點座標,平行則返回0,0點座標;
// Returns: 返回交點座標;
// Parameter: QLineF line1 第一條直線;
// Parameter: QLineF line2第二條直線;
//************************************
QPointF CaculateTwoLineCrossPt(QLineF line1, QLineF line2)
{
//斜率相等為平行線,沒有交點;
if (line1.angle() == line2.angle())
return QPointF();
qreal x1 = line1.p1().x();
qreal y1 = 0 - line1.p1().y();
qreal x2 = line1.p2().x();
qreal y2 = 0 - line1.p2().y();
qreal x3 = line2.p1().x();
qreal y3 = 0 - line2.p1().y();
qreal x4 = line2.p2().x();
qreal y4 = 0 - line2.p2().y();
if (x2 == x1 && x3 != x4)
{
qreal x = x1;
qreal y = 0 - (x3 * y4 - x4 * y3 + x1 * (y3 - y4)) / (x3 - x4);
return QPointF(x, y);
}
else if (x3 == x4 && x1 != x2)
{
qreal x = x3;
qreal y = 0 - (x1 * y2 - x2 * y1 + x3 * (y1 - y2)) / (x1 - x2);
return QPointF(x, y);
}
else
{
qreal a1 = (y2 - y1) / (x2 - x1);
qreal b1 = (x2 * y1 - x1 * y2) / (x2 - x1);
qreal a2 = (y4 - y3) / (x4 - x3);
qreal b2 = (x4 * y3 - x3 * y4) / (x4 - x3);
qreal x = (b2 - b1) / (a1 - a2);
qreal y = 0 - (a1 * b2 - a2 * b1) / (a1 - a2);
return QPointF(x, y);
}
}
//************************************
// Method: 求一條直線的哪個端點到目標點的距離最近;
// Returns: bool目標點在直線之內,返回true,否則返回false;
// Parameter: const QLineF & line直線;
// Parameter: const QPointF & pt目標點;
// Parameter: QPointF & nearPt返回最近的端點;
//************************************
bool GetLineNearPt(const QLineF& line, const QPointF & pt, QPointF& nearPt)
{
QLineF line1(line.p1(), pt);
QLineF line2(line.p2(), pt);
nearPt = (line1.length() <= line2.length() ? line.p1() : line.p2());
if (line1.length() + line2.length() <= line.length())
return true;
else
return false;
}
//************************************
// Method: 計算兩條直線是否在平行誤差範圍內平行;
// Returns: bool 平行true,不平行false;
// Parameter: const QLineF & line1 第一條直線;
// Parameter: const QLineF & line2第二條直線;
//************************************
#define ANGLE_ERROR_COEFFICIENT 3//角度誤差係數,度;
bool GetTwoLineIsCloseParallel(const QLineF& line1, const QLineF& line2)
{
qreal a1 = line1.angle();
qreal a2 = line2.angle();
qreal nT = qAbs(a1 - a2);
while (nT > 180)
{
nT -= 180;
}
if (nT <= ANGLE_ERROR_COEFFICIENT || nT >= 180 - ANGLE_ERROR_COEFFICIENT)
return true;
else
return false;
}
//************************************
// Method: 計算兩條直線所形成夾角的最小角度,範圍從 -180 到 180;
// Returns: double 返回形成的夾角;
// Parameter: const QLineF & line1直線1;
// Parameter: const QLineF & line2直線2;
// Parameter: const QPointF & circleCenter圓弧的中心點;
// Parameter: const double & angle角度;
// Parameter: const QPointF & startPt起始點座標;
//************************************
double caculateCrossAngle(const QLineF &line1, const QLineF &line2, const QPointF &circleCenter, const double &angle, const QPointF& startPt)
{
//計算兩條直線之間的夾角,而不是與某條直線的延長線的夾角;
double crossAngle = angle;
//圓弧的半徑;
double nRadius = QLineF(circleCenter, startPt).length();
//計算第一條線與經過圓心的平行線的角度;
double nAngle = QLineF(circleCenter.x(), circleCenter.y(), circleCenter.x() + nRadius, circleCenter.y()).angleTo(QLineF(circleCenter, startPt));
// 計算終點座標圓心形成直線的正負角度;
double angle1 = nAngle + crossAngle;
double angle2 = nAngle - (180 - crossAngle);
//計算終點座標;
double ptX1 = circleCenter.x() + nRadius * cos(angle1 / 180.0 * M_PI);
double ptY1 = circleCenter.y() - nRadius * sin(angle1 / 180.0 * M_PI);
double ptX2 = circleCenter.x.D() + nRadius * cos(angle2 / 180.0 * M_PI);
double ptY2 = circleCenter.y.D() - nRadius * sin(angle2 / 180.0 * M_PI);
//計算兩個終點座標與第二條線兩個端點的距離之和;
double length1 = QLineF(line2.p1(), QPointF(ptX1, ptY1)).length() + QLineF(line2.p2(), QPointF(ptX1, ptY1)).length();
double length2 = QLineF(line2.p1(), QPointF(ptX2, ptY2)).length() + QLineF(line2.p2(), QPointF(ptX2, ptY2)).length();
//取距離較短的對應的角度,作為圓弧的弧度;
if (length1 > length2)
crossAngle = crossAngle - 180;
if (crossAngle < -180)
crossAngle += 360;
return crossAngle;
}
// 用於計算第二條直線的哪個點與第一條直線的第一個點處於同一側;
QPointF CaculateOneSidePoint(const QLineF& l1, const QLineF& l2)
{
QLineF tL(l2.p2(), l2.p1());
double a1 = l1.angleTo(l2);
double a2 = l1.angleTo(tL);
if (a1 > 180)
a1 = 360 - a1;
if (a2 > 180)
a2 = 360 - a2;
if (a1 < a2)
return l2.p1();
else
return l2.p2();
}
//////////////////////////////////////////////////////////////////////////
// 計算兩條直線的中線,計算規則兩條直線的角平分線,如果兩條直線平行,則為等距離的線;
// 引數isAcuteAngle為是取兩條直線連線的銳角的角平分線還是鈍角的角平分線;
QLineF CaculateMiddleLine(const QLineF& l1, const QLineF& l2, bool isAcuteAngle = true)
{
QPointF p1, p2, p3, p4;
p1 = l1.p1();
p2 = l1.p2();
p3 = CaculateOneSidePoint(l1, l2);
p4 = (p3 == l2.p1() ? l2.p2() : l2.p1());
if (!isAcuteAngle)
qSwap(p3, p4);
double a1 = QLineF(p1, p2).angleTo(QLineF(p3, p4));
// 兩條直線平行, 返回兩條直線的兩個端點連線的中點所形成的線;
if (a1 == 0 || a1 == 180)
{
return QLineF(GetMiddlePoint(p1, p3), GetMiddlePoint(p2, p4));
}
QLineF crossLine;
crossLine.setP1(CaculateTwoLineCrossPt(l1, l2));
crossLine.setAngle(a1 / 2 + l1.angle());
QPointF m1, m2;
m1 = CaculateTwoLineCrossPt(QLineF(p1, p3), crossLine);
m2 = CaculateTwoLineCrossPt(QLineF(p2, p4), crossLine);
return QLineF(m1, m2);
}
//BMP影象檔案結構體;
typedef struct tagBITMAPFILEHEADER { // bmfh
tagBITMAPFILEHEADER(){
bfType = 0x4D42;
bfSize = 0;
bfReserved1 = bfReserved2 = 0;
bfOffBits = 0;
}
unsigned short bfType;//檔案型別,必須為 0x4D42,即為"BM",否則表示根本不是BMP
unsigned long
bfSize;//
該點陣圖檔案的大小,用位元組為單位;
unsigned short bfReserved1;//保留,為0;
unsigned short bfReserved2;//保留,為0;
unsigned long bfOffBits;//從檔案頭開始到實際的影象資料之間的位元組的偏移量;
} BITMAPFILEHEADER;
//點陣圖資訊段;
typedef struct tagBITMAPINFOHEADER{
tagBITMAPINFOHEADER(){
biSize = 0;
biWidth = biHeight = 0;
biPlanes = 1;
biBitCount = 1;
biCompression = 0;
biSizeImage = 0;
biXPelsPerMeter = biYPelsPerMeter = 0;
biClrUsed = 0;
biClrImportant = 0;
}
unsigned long biSize;//BITMAPINFOHEADER 結構體的大小;
long biWidth;//影象寬度;
long biHeight;//影象高度;
unsigned short biPlanes;//bmp圖片的平面屬,為1;
unsigned short biBitCount;//位元數/畫素, 1/4/8/16/24/32;
unsigned long biCompression;//影象資料壓縮型別: BI_RGB 0L沒有壓縮; BI_RLE8 1L; BI_RLE4 2L; BI_BITFIELDS 3L; BI_JPEG 4L;
unsigned long biSizeImage;//影象的大小,以位元組為單位,當使用BI_RGB 格式時,可設定為0;
long biXPelsPerMeter;//水平解析度,用畫素/米表示;
long biYPelsPerMeter;//垂直分表率;
unsigned long biClrUsed;//點陣圖實際使用的顏色表中顏色索引數,設定為0的話,表示使用所有的調色盤項;
unsigned long biClrImportant;//對影象顯示有重要影響的顏色索引的數目,如果是0,表示都重要;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
//調色盤;
typedef struct tagRGBQUAD {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
//************************************
// Method: BMP檔案內容填充;
// Returns: void
// Parameter: const uchar * pRred 通道;
// Parameter: const uchar * pGgreen 通道;
// Parameter: const uchar * pBblue 通道;
// Parameter: int w圖片寬度;
// Parameter: int h圖片高度;
// Parameter: QImage & image輸出的圖片物件;
//************************************
void writeBMPImage(const uchar* pR, const uchar* pG, const uchar* pB, int w, int h, QImage & image)
{
int rW = w;
//寬度對4取整;
if (w % 4)
rW = (rW / 4 + 1) * 4;
//填寫檔案頭;
BITMAPFILEHEADER bmpFileHead;
bmpFileHead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+rW * h * 32 / 8;
bmpFileHead.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
//填寫圖片資訊頭;
BITMAPINFOHEADER bmpInfoHead;
bmpInfoHead.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHead.biWidth = w;
bmpInfoHead.biHeight = h;
bmpInfoHead.biBitCount = 24;
bmpInfoHead.biCompression = BI_RGB;
bmpInfoHead.biSizeImage = rW * h * 24 / 8;
//分配整個檔案的大小的記憶體;
char * pBuf = new char[bmpFileHead.bfSize];
memset(pBuf, 0, bmpFileHead.bfSize);
//分配影象資料大小的記憶體;
char *pImage = new char[rW * h * 3];
memset(pImage, 0, rW * h * 3);
//將圖片顏色合成到影象資料中;
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
pImage[i * rW * 3 + j * 3] = pR[i * w + j];
pImage[i * rW * 3 + j * 3 + 1] = pG[i * w + j];
pImage[i * rW * 3 + j * 3 + 2] = pB[i * w + j];
}
}
//將所有資料放入buf中;
int nOffset = 0;
memcpy(pBuf + nOffset, bmpFileHead, sizeof(bmpFileHead));
nOffset += sizeof(bmpFileHead);
int nOffset = 0;
memcpy(pBuf + nOffset, bmpInfoHead, sizeof(bmpInfoHead));
nOffset += sizeof(bmpInfoHead);
int nOffset = 0;
memcpy(pBuf + nOffset, pImage, sizeof(rW * h * 3));
nOffset += sizeof(rW * h * 3);
//image物件載入圖片;
image.loadFromData(pBuf, nOffset);
}